diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 5d20a9d..76563ea 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -16,23 +16,6 @@ jobs: steps: - uses: actions/checkout@v4 - - run: | - ls - pwd - - - name: Checkout Anchor Source Generator - uses: actions/checkout@v4 - with: - repository: sava-software/anchor-src-gen - token: ${{ secrets.GH_READ_PROJECTS }} - path: anchor-src-gen - - - run: | - ls - pwd - - - uses: gradle/actions/wrapper-validation@v3 - - uses: oracle-actions/setup-java@v1 if: ${{ vars.GRADLE_JAVA_VERSION != vars.JAVA_VERSION }} with: @@ -49,12 +32,18 @@ jobs: website: jdk.java.net release: ${{ vars.JAVA_VERSION }} - - run: printf "org.gradle.java.home=%s" "$JAVA_HOME" > gradle.properties - if: ${{ vars.GRADLE_JAVA_VERSION == vars.JAVA_VERSION }} + - name: Checkout Anchor Source Generator + uses: actions/checkout@v4 + with: + repository: sava-software/anchor-src-gen + token: ${{ secrets.GH_READ_PROJECTS }} + path: anchor-src-gen + + - uses: gradle/actions/wrapper-validation@v3 - name: Generate Source & Check run: | - ./genSrc.sh --tjv="${{ vars.JAVA_VERSION }}" --log="INFO" --tl=2 --bdm=200 --nt=5 --sd="programs/src/main/java" --rpc="${{ secrets.RPC_URL }}" + ./anchor-src-gen/genSrc.sh --tjv="${{ vars.JAVA_VERSION }}" --tl=2 --bdm=200 --nt=5 --sd="programs/src/main/java" --bp="software.sava.anchor.programs" --mn="software.sava.anchor_programs" --rpc="${{ secrets.RPC_URL }}" ./gradlew -PtargetJava=${{ vars.JAVA_VERSION }} check --stacktrace env: GITHUB_ACTOR: ${{ secrets.GITHUB_ACTOR }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 930054a..d609973 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,15 +33,21 @@ jobs: website: jdk.java.net release: ${{ vars.JAVA_VERSION }} - - run: printf "org.gradle.java.home=%s" "$JAVA_HOME" > gradle.properties - if: ${{ vars.GRADLE_JAVA_VERSION == vars.JAVA_VERSION }} + - name: Checkout Anchor Source Generator + uses: actions/checkout@v4 + with: + repository: sava-software/anchor-src-gen + token: ${{ secrets.GH_READ_PROJECTS }} + path: anchor-src-gen + + - uses: gradle/actions/wrapper-validation@v3 - name: Generate Source, Check & Publish run: | - ./genSrc.sh --tjv="${{ vars.JAVA_VERSION }}" --log="INFO" --tl=2 --bdm=200 --nt=5 --sd="programs/src/main/java" --rpc="${{ secrets.RPC_URL }}" + ./anchor-src-gen/genSrc.sh --tjv="${{ vars.JAVA_VERSION }}" --tl=2 --bdm=200 --nt=5 --sd="programs/src/main/java" --bp="software.sava.anchor.programs" --mn="software.sava.anchor_programs" --rpc="${{ secrets.RPC_URL }}" ./gradlew --stacktrace -PtargetJava=${{ vars.JAVA_VERSION }} check :anchor-programs:publish env: GITHUB_ACTOR: ${{ secrets.GITHUB_ACTOR }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_SAVA_USER: ${{ secrets.GPR_USER }} - GITHUB_SAVA_TOKEN: ${{ secrets.GPR_TOKEN }} + GITHUB_SAVA_TOKEN: ${{ secrets.GPR_TOKEN }} \ No newline at end of file diff --git a/README.md b/README.md index aee1f83..20ab1da 100644 --- a/README.md +++ b/README.md @@ -2,24 +2,6 @@ # Anchor Programs [![Build](https://github.com/sava-software/anchor-programs/actions/workflows/gradle.yml/badge.svg)](https://github.com/sava-software/anchor-programs/actions/workflows/gradle.yml) [![Release](https://github.com/sava-software/anchor-programs/actions/workflows/release.yml/badge.svg)](https://github.com/sava-software/anchor-programs/actions/workflows/release.yml) -## Generate Source - -Replace the values below to fit your needs. - -```bash -./genSrc.sh \ - --log=[INFO|WARN|DEBUG] \ - --tabLength=2 \ - --sourceDirectory="programs/src/main/java" \ - --moduleName="software.sava.anchor_programs" \ - --basePackageName="software.sava.anchor.programs" \ - --rpc="https://rpc.com" \ - --programsCSV="generator/main_net_programs.csv" \ - --baseDelayMillis=200 \ - --numThreads=5 \ - --screen=[0|1] -``` - ## Requirements - The latest generally available JDK. This project will continue to move to the latest and will not maintain diff --git a/build.gradle b/build.gradle index 9386514..b194161 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,3 @@ -buildscript { - repositories { - maven { url = 'https://plugins.gradle.org/m2/' } - mavenCentral() - } - dependencies { - // https://plugins.gradle.org/plugin/org.beryx.jlink - classpath "org.beryx:badass-jlink-plugin:3.0.1" - } -} - def getAppVersion = { -> try (final var gitTagOut = new ByteArrayOutputStream()) { exec { diff --git a/generator/build.gradle b/generator/build.gradle deleted file mode 100644 index 4991df2..0000000 --- a/generator/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -apply plugin: 'org.beryx.jlink' - -dependencies { - implementation "systems.comodal:json-iterator:$jsoniter" - - implementation "software.sava:sava-core:$sava" - implementation "software.sava:sava-rpc:$sava" - - implementation "software.sava:solana-programs:$sava_solana_programs" - implementation "software.sava:anchor-src-gen:$sava_anchor_src_gen" -} - -def gitHash = { -> - def stdout = new ByteArrayOutputStream() - exec { - commandLine 'git', 'rev-parse', '--short', 'HEAD' - standardOutput = stdout - } - return stdout.toString().trim(); -} as Object - -afterEvaluate { - jlink { - mergedModuleJarVersion.set("0") - imageName.set(gitHash()) - options.addAll(List.of('--bind-services', '--no-man-pages', '--ignore-signing-information')) - enableCds() - } -} \ No newline at end of file diff --git a/generator/src/main/java/module-info.java b/generator/src/main/java/module-info.java deleted file mode 100644 index 7613a0a..0000000 --- a/generator/src/main/java/module-info.java +++ /dev/null @@ -1,11 +0,0 @@ -module software.sava.anchor_generator { - requires java.net.http; - - requires systems.comodal.json_iterator; - - requires software.sava.core; - requires software.sava.rpc; - - requires software.sava.solana_programs; - requires software.sava.anchor_src_gen; -} diff --git a/generator/src/main/java/software/sava/anchor/programs/Entrypoint.java b/generator/src/main/java/software/sava/anchor/programs/Entrypoint.java deleted file mode 100644 index 099b0fd..0000000 --- a/generator/src/main/java/software/sava/anchor/programs/Entrypoint.java +++ /dev/null @@ -1,224 +0,0 @@ -package software.sava.anchor.programs; - -import software.sava.anchor.AnchorIDL; -import software.sava.anchor.AnchorSourceGenerator; -import software.sava.core.accounts.PublicKey; -import software.sava.core.tx.Instruction; -import software.sava.rpc.json.http.SolanaNetwork; -import software.sava.rpc.json.http.client.SolanaRpcClient; -import systems.comodal.jsoniter.JsonIterator; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.net.URI; -import java.net.http.HttpClient; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ConcurrentSkipListSet; -import java.util.concurrent.Executors; -import java.util.concurrent.Semaphore; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.LongBinaryOperator; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import static java.nio.file.StandardOpenOption.*; -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static software.sava.core.accounts.PublicKey.fromBase58Encoded; - -public final class Entrypoint extends Thread { - - private final Semaphore semaphore; - private final ConcurrentLinkedQueue> tasks; - private final AtomicLong errorCount; - private final long baseDelayMillis; - private final AtomicLong latestCall; - private final SolanaRpcClient rpcClient; - private final Path sourceDirectory; - private final String basePackageName; - private final Set exports; - private final int tabLength; - - private Entrypoint(final Semaphore semaphore, - final ConcurrentLinkedQueue> tasks, - final AtomicLong errorCount, - final long baseDelayMillis, - final AtomicLong latestCall, - final SolanaRpcClient rpcClient, - final Path sourceDirectory, - final String basePackageName, - final Set exports, - final int tabLength) { - this.semaphore = semaphore; - this.tasks = tasks; - this.errorCount = errorCount; - this.baseDelayMillis = baseDelayMillis; - this.latestCall = latestCall; - this.rpcClient = rpcClient; - this.sourceDirectory = sourceDirectory; - this.basePackageName = basePackageName; - this.exports = exports; - this.tabLength = tabLength; - } - - private String formatPackage(final String moduleName) { - return String.format("%s.%s.anchor", basePackageName, moduleName); - } - - private AnchorSourceGenerator createGenerator(final String moduleName, final AnchorIDL idl) { - return new AnchorSourceGenerator( - sourceDirectory, - formatPackage(moduleName), - tabLength, - idl - ); - } - - private AnchorSourceGenerator createGenerator(final String moduleName, final PublicKey programAddress) { - final var idl = AnchorSourceGenerator.fetchIDLForProgram(programAddress, rpcClient).join(); - return createGenerator(moduleName, idl); - } - - private AnchorSourceGenerator createGenerator(final String moduleName, final URI url) { - final var idl = AnchorSourceGenerator.fetchIDL(rpcClient.httpClient(), url).join(); - return createGenerator(moduleName, idl); - } - - private AnchorSourceGenerator createGenerator(final String moduleName, final String addressOrURL) { - return addressOrURL.startsWith("https://") - ? createGenerator(moduleName, URI.create(addressOrURL)) - : createGenerator(moduleName, fromBase58Encoded(addressOrURL)); - } - - private AnchorSourceGenerator createGenerator(final Map.Entry task) { - return createGenerator(task.getKey(), task.getValue()); - } - - private static final LongBinaryOperator MAX = Long::max; - - @Override - public void run() { - Map.Entry task = null; - for (long delayMillis, latestCall, now, sleep; ; ) { - try { - task = this.tasks.poll(); - if (task == null) { - return; - } - this.semaphore.acquire(); - delayMillis = this.baseDelayMillis * (this.errorCount.get() + 1); - latestCall = this.latestCall.get(); - now = System.currentTimeMillis(); - sleep = (latestCall + delayMillis) - now; - if (sleep > 0) { - MILLISECONDS.sleep(sleep); - now = System.currentTimeMillis(); - } - this.latestCall.getAndAccumulate(now, MAX); - final var generator = createGenerator(task); - generator.run(); - generator.addExports(exports); - this.latestCall.getAndAccumulate(now + ((System.currentTimeMillis() - now) >> 1), MAX); - this.errorCount.getAndUpdate(x -> x > 0 ? x - 1 : x); - } catch (final RuntimeException e) { - this.errorCount.getAndUpdate(x -> x < 100 ? x + 1 : x); - this.tasks.add(task); - } catch (final InterruptedException e) { - throw new RuntimeException(e); - } finally { - this.semaphore.release(); - } - } - } - - private static String mandatoryProperty(final String key) { - return Objects.requireNonNull(System.getProperty(key, "Must pass property "), key); - } - - private static String propertyOrElse(final String key, final String orElse) { - final var property = System.getProperty(key); - return property == null || property.isBlank() ? orElse : property; - } - - public static void main(final String[] args) throws InterruptedException { - final var clas = Entrypoint.class; - final var moduleName = clas.getModule().getName(); - final int tabLength = Integer.parseInt(propertyOrElse( - moduleName + ".tabLength", - "2" - )); - final var sourceDirectory = Path.of(propertyOrElse(moduleName + ".sourceDirectory", "anchor-programs/src/main/java")).toAbsolutePath(); - final var outputModuleName = propertyOrElse(moduleName + ".moduleName", moduleName.substring(0, moduleName.lastIndexOf('.')) + ".anchor_programs"); - final var basePackageName = propertyOrElse(moduleName + ".basePackageName", clas.getPackageName()); - final var rpcEndpoint = System.getProperty(moduleName + ".rpc"); - final var programsCSV = mandatoryProperty(moduleName + ".programsCSV"); - final int numThreads = Integer.parseInt(propertyOrElse(moduleName + ".numThreads", "5")); - final int baseDelayMillis = Integer.parseInt(propertyOrElse(moduleName + ".baseDelayMillis", "200")); - - try (final var lines = Files.lines(Path.of(programsCSV))) { - final var semaphore = new Semaphore(numThreads, false); - final var tasks = new ConcurrentLinkedQueue>(); - lines.map(line -> { - final int comma = line.indexOf(','); - return Map.entry(line.substring(0, comma), line.substring(comma + 1)); - }).forEach(tasks::add); - - final var errorCount = new AtomicLong(); - final var latestCall = new AtomicLong(); - - try (final var executor = Executors.newVirtualThreadPerTaskExecutor()) { - try (final var httpClient = HttpClient.newBuilder().executor(executor).build()) { - final var rpcClient = SolanaRpcClient.createHttpClient( - rpcEndpoint == null || rpcEndpoint.isBlank() ? SolanaNetwork.MAIN_NET.getEndpoint() : URI.create(rpcEndpoint), - httpClient - ); - - final var exports = new ConcurrentSkipListSet(); - final var threads = IntStream.range(0, numThreads) - .mapToObj(_ -> new Entrypoint( - semaphore, tasks, errorCount, baseDelayMillis, latestCall, - rpcClient, - sourceDirectory, basePackageName, - exports, - tabLength - )) - .peek(Thread::start) - .toList(); - - exports.add(String.format("requires %s;", HttpClient.class.getModule().getName())); - exports.add(String.format("requires %s;", JsonIterator.class.getModule().getName())); - exports.add(String.format("requires %s;", Instruction.class.getModule().getName())); - exports.add(String.format("requires %s;", SolanaRpcClient.class.getModule().getName())); - exports.add(String.format("requires %s;", System.class.getModule().getName())); - exports.add(String.format("requires %s;", AnchorSourceGenerator.class.getModule().getName())); - final var moduleFilePath = sourceDirectory.resolve("module-info.java"); - - if (Files.exists(moduleFilePath)) { - try (final var moduleFileLines = Files.lines(moduleFilePath)) { - moduleFileLines - .map(String::strip) - .filter(line -> !line.isBlank() && !line.startsWith("module") && !line.equals("}")) - .forEach(exports::add); - } - } - final var builder = new StringBuilder(2_048); - builder.append(String.format("module %s {%n", outputModuleName)); - - for (final var thread : threads) { - thread.join(); - } - - builder.append(exports.stream().sorted(String::compareToIgnoreCase).collect(Collectors.joining("\n")).indent(tabLength)); - builder.append('}').append('\n'); - Files.writeString(moduleFilePath, builder.toString(), CREATE, TRUNCATE_EXISTING, WRITE); - } - } - } catch (final IOException e) { - throw new UncheckedIOException(e); - } - } -} diff --git a/generator/main_net_programs.csv b/main_net_programs.csv similarity index 100% rename from generator/main_net_programs.csv rename to main_net_programs.csv diff --git a/settings.gradle b/settings.gradle index 4c211de..8394689 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,4 @@ rootProject.name = 'anchor-programs' -include 'generator' - include 'programs' project(':programs').name = 'anchor-programs'