diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 245f8ab97..640bfdb79 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: - uses: DeterminateSystems/magic-nix-cache-action@v13 - name: Main project tests - run: nix develop .#jdk${{ matrix.java }} --command sbt test + run: nix develop .#jdk${{ matrix.java }} --command gradle test --no-daemon docker_test: runs-on: ubuntu-latest @@ -83,8 +83,8 @@ jobs: - uses: DeterminateSystems/magic-nix-cache-action@v13 - - run: nix develop --command sbt cli/pack - - run: echo "$PWD/scip-java/target/pack/bin" >> "$GITHUB_PATH" + - run: nix develop --command gradle :scip-java:installDist --no-daemon + - run: echo "$PWD/scip-java/build/install/scip-java/bin" >> "$GITHUB_PATH" - name: Auto-index scip-java codebase run: | # shellcheck disable=SC2016 @@ -113,10 +113,10 @@ jobs: - uses: DeterminateSystems/magic-nix-cache-action@v13 - name: scip-kotlinc tests - run: nix develop --command sbt scipKotlinc/test + run: nix develop --command gradle :scip-kotlinc:test --no-daemon - name: Regenerate snapshots - run: nix develop --command sbt scipSnapshots/run + run: nix develop --command gradle :scip-snapshots:saveSnapshots --no-daemon - name: Check snapshot drift run: | @@ -141,13 +141,13 @@ jobs: - run: | nix develop .#jdk${{ matrix.java }} --command \ - sbt --error cli/pack publishM2 publishLocal + gradle --no-daemon :scip-java:installDist publishToMavenLocal SCIP_JAVA_VERSION="$( - sed -n 's/^version:=//p' scip-java/target/pack/VERSION + sed -n 's/^version:=//p' scip-java/build/install/scip-java/VERSION )" test -n "$SCIP_JAVA_VERSION" printf 'SCIP_JAVA_VERSION=%s\n' "$SCIP_JAVA_VERSION" >> "$GITHUB_ENV" - printf 'SCIP_JAVA_CLI=%s\n' "$PWD/scip-java/target/pack/bin/scip-java" >> "$GITHUB_ENV" + printf 'SCIP_JAVA_CLI=%s\n' "$PWD/scip-java/build/install/scip-java/bin/scip-java" >> "$GITHUB_ENV" - run: | nix develop "$GITHUB_WORKSPACE#jdk${{ matrix.java }}" --command \ diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml index 4e6c6bb4a..c33e896a6 100644 --- a/.github/workflows/release-cli.yml +++ b/.github/workflows/release-cli.yml @@ -37,7 +37,7 @@ jobs: cd "$OUT_DIR" VERSION=${VERSION#v} - ARTIFACT="com.sourcegraph:scip-java_2.13:${VERSION}" + ARTIFACT="com.sourcegraph:scip-java:${VERSION}" for attempt in {1..10}; do if cs resolve "$ARTIFACT" >/dev/null 2>&1; then diff --git a/.github/workflows/release-maven.yml b/.github/workflows/release-maven.yml index e3f38ff45..dd7aaf906 100644 --- a/.github/workflows/release-maven.yml +++ b/.github/workflows/release-maven.yml @@ -15,13 +15,25 @@ jobs: with: summarize: false - uses: DeterminateSystems/magic-nix-cache-action@v13 - - name: Publish ${{ github.ref }} - run: nix develop --command sbt ci-release + - name: Publish snapshot ${{ github.ref }} + if: ${{ !startsWith(github.ref, 'refs/tags/') }} + run: nix develop --command gradle --no-daemon publishToMavenCentral env: - PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} - PGP_SECRET: ${{ secrets.PGP_SECRET }} - SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} - SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_PASSWORD }} + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_USERNAME }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.PGP_SECRET }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.PGP_PASSPHRASE }} + - name: Publish release ${{ github.ref }} + if: ${{ startsWith(github.ref, 'refs/tags/') }} + run: | + version="${GITHUB_REF_NAME#v}" + nix develop --command gradle --no-daemon \ + "-PreleaseVersion=$version" publishAndReleaseToMavenCentral + env: + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_PASSWORD }} + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_USERNAME }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.PGP_SECRET }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.PGP_PASSPHRASE }} release-cli: if: ${{ startsWith(github.ref, 'refs/tags/') }} diff --git a/.gitignore b/.gitignore index 97484a25c..ce6f3c1a3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,9 @@ result result-* -# sbt specific +# build tool output +.gradle/ +build/ .cache .history .lib/ @@ -13,8 +15,6 @@ dist/* target/ lib_managed/ src_managed/ -project/boot/ -project/plugins/project/ .bloop _site/ @@ -79,7 +79,3 @@ scip-snapshots/META-INF/ # writes META-INF/scip/sources/Test.kt.scip relative to the test # cwd. scip-kotlinc/META-INF/ - -# Standard sbt project metadata directories. -project/target/ -project/project/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 018188df7..20b6d5f27 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,8 +14,8 @@ nix develop .#jdk17 # JDK 17 nix develop .#jdk21 # JDK 21 ``` -This drops you into a shell with `sbt`, `maven`, `gradle`, `bazelisk`, -`nodejs`, `yarn`, `git`, `jq`, etc. all pinned to the versions used in CI. +This drops you into a shell with `gradle`, `maven`, `bazelisk`, `nodejs`, +`yarn`, `git`, `jq`, etc. all pinned to the versions used in CI. If you'd rather install tools manually, you'll need at least: @@ -43,25 +43,23 @@ These are the main components of the project. interface. - `scip-java/src/test`: build-tool integration tests and fixtures for the `scip-java` command-line interface. -- `build.sbt`: the sbt build definition. -- `project/plugins.sbt`: plugins for the sbt build. +- `settings.gradle.kts`: Gradle project layout. +- `build.gradle.kts`: Gradle build definition. +- `gradle/libs.versions.toml`: dependency and plugin versions. ## Helpful commands -| Command | Where | Description | -| ------------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------- | -| `sbt` | terminal | Start interactive sbt shell with Java 11 (run from `nix develop`). Takes a while to load on the first run. | -| `unit/test` | sbt | Run fast unit tests. | -| `~unit/test` | sbt | Start watch mode to run tests on file save, good for local edit-and-test workflows. | -| `cli/test` | sbt | Run slow build tool tests (Gradle, Maven). | -| `snapshots/testOnly tests.MinimizedSnapshotScipTest` | sbt | Runs fast snapshot tests. Indexes a small set of files under `tests/minimized`. | -| `snapshots/test` | sbt | Runs all snapshot tests. | -| `snapshots/run` | sbt | Update only the Java snapshot goldens under `tests/snapshots`. | -| `scipKotlincMinimized/kotlincSnapshots` | sbt | Update only the Kotlin snapshot goldens under `scip-kotlinc/minimized`. | -| `regenerateSnapshots` | sbt | Regenerate ALL snapshot goldens (Java + Kotlin). Run after fixing a bug. | -| `cli/run --cwd DIRECTORY` | sbt | Run `scip-java` command-line tool against a given Gradle/Maven build. | -| `google-java-format --replace $(git ls-files '*.java')` | terminal | Format Java sources (from `nix develop`). Enforced by `nix flake check`. | -| `ktfmt --kotlinlang-style $(git ls-files '*.kt')` | terminal | Format Kotlin sources (from `nix develop`). Enforced by `nix flake check`. | +| Command | Where | Description | +| ------------------------------------------------------- | -------- | ----------------------------------------------------------------------- | +| `gradle test --no-daemon` | terminal | Run all Gradle tests. | +| `gradle :scip-java:test --no-daemon` | terminal | Run CLI build-tool integration tests (Gradle, Maven, SCIP config). | +| `gradle :scip-kotlinc:test --no-daemon` | terminal | Run Kotlin compiler-plugin tests. | +| `gradle :scip-snapshots:test --no-daemon` | terminal | Compare Java and Kotlin snapshot goldens. | +| `gradle :scip-snapshots:saveSnapshots --no-daemon` | terminal | Regenerate Java and Kotlin snapshot goldens. | +| `gradle :scip-java:installDist --no-daemon` | terminal | Build a local `scip-java` distribution under `scip-java/build/install/`. | +| `gradle :scip-java:run --args='--cwd DIRECTORY'` | terminal | Run `scip-java` against a given Gradle/Maven build. | +| `google-java-format --replace $(git ls-files '*.java')` | terminal | Format Java sources (from `nix develop`). Enforced by `nix flake check`. | +| `ktfmt --kotlinlang-style $(git ls-files '*.kt')` | terminal | Format Kotlin sources (from `nix develop`). Enforced by `nix flake check`. | ## Import the project into IntelliJ @@ -80,20 +78,16 @@ Next, follow [these instructions](https://github.com/HPI-Information-Systems/Metanome/wiki/Installing-the-google-styleguide-settings-in-intellij-and-eclipse) here to configure the Google Java formatter. -Finally, run "File > Project From Existing Sources" to import the sbt build into -IntelliJ. Select the "sbt" option if it asks you to choose between -sbt/BSP/Bloop. +Finally, run "File > Project From Existing Sources" to import the Gradle build +into IntelliJ. Select the "Gradle" option if it asks you to choose a build +model. -It's best to run tests from the sbt shell, not from the IntelliJ UI. +It's best to run tests from Gradle, not from the IntelliJ UI. ## Tests are written in Java with JUnit 5 -The unit tests (`tests/unit`) and snapshot tests (`tests/snapshots`) are plain -Java using [JUnit 5](https://junit.org/junit5/), wired into sbt via -[sbt-jupiter-interface](https://github.com/sbt/sbt-jupiter-interface). The -snapshot suite is a JUnit `@TestFactory` that emits one dynamic test per -generated document, comparing it against the committed goldens under -`tests/snapshots/src/main/generated` -([snapshot testing](https://jestjs.io/docs/en/snapshot-testing) is heavily used -in this codebase). Build-tool tests (`scip-java/src/test`) are written in -Kotlin. +The Java tests use [JUnit 5](https://junit.org/junit5/) through Gradle's JUnit +Platform support. The snapshot suite is a JUnit `@TestFactory` that emits one +dynamic test per generated document, comparing it against the committed goldens +under `scip-snapshots/expected`. Build-tool tests (`scip-java/src/test`) are +written in Kotlin. diff --git a/Dockerfile b/Dockerfile index 5af452423..45ae2c6b6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,7 @@ RUN git config --global --add safe.directory * COPY . . -RUN sbt cli/pack && mkdir -p /app/scip-java && cp -R scip-java/target/pack/. /app/scip-java/ +RUN gradle --no-daemon :scip-java:installDist && mkdir -p /app/scip-java && cp -R scip-java/build/install/scip-java/. /app/scip-java/ COPY ./bin/scip-java-docker-script.sh /usr/bin/scip-java diff --git a/bin/docker-setup.sh b/bin/docker-setup.sh index b472e11b4..5bee3a434 100755 --- a/bin/docker-setup.sh +++ b/bin/docker-setup.sh @@ -3,14 +3,14 @@ set -eux curl -fLo /usr/local/bin/cs https://github.com/coursier/coursier/releases/download/v2.1.5/coursier chmod +x /usr/local/bin/cs ln -sf /usr/local/bin/cs /usr/local/bin/coursier -cs setup --yes --apps cs,coursier,sbt +cs setup --yes --apps cs,coursier curl -fLo maven.zip https://archive.apache.org/dist/maven/maven-3/3.9.1/binaries/apache-maven-3.9.1-bin.zip unzip -d /opt/maven maven.zip rm maven.zip mv /opt/maven/*/* /opt/maven -curl -fLo gradle.zip https://services.gradle.org/distributions/gradle-7.6.1-bin.zip +curl -fLo gradle.zip https://services.gradle.org/distributions/gradle-8.14.4-bin.zip unzip -d /opt/gradle gradle.zip rm gradle.zip mv /opt/gradle/*/* /opt/gradle diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 000000000..f239681bc --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,483 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import com.google.protobuf.gradle.ProtobufExtension +import com.google.protobuf.gradle.proto +import com.vanniktech.maven.publish.MavenPublishBaseExtension +import java.util.Properties +import org.gradle.api.JavaVersion +import org.gradle.api.distribution.DistributionContainer +import org.gradle.api.plugins.JavaApplication +import org.gradle.api.plugins.JavaPlugin +import org.gradle.api.plugins.JavaPluginExtension +import org.gradle.api.tasks.JavaExec +import org.gradle.api.tasks.SourceSetContainer +import org.gradle.api.tasks.Sync +import org.gradle.api.tasks.compile.JavaCompile +import org.gradle.api.tasks.javadoc.Javadoc +import org.gradle.api.tasks.testing.Test +import org.gradle.external.javadoc.StandardJavadocDocletOptions +import org.gradle.jvm.tasks.Jar +import org.gradle.language.jvm.tasks.ProcessResources +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + alias(libs.plugins.kotlin.jvm) apply false + alias(libs.plugins.protobuf) apply false + alias(libs.plugins.shadow) apply false + alias(libs.plugins.vanniktech.maven.publish) apply false +} + +val javacInternalsFile = layout.projectDirectory.file("gradle/javac-internals.properties") +val javacJvmOptions = + ( + Properties() + .apply { + javacInternalsFile.asFile.inputStream().use { load(it) } + } + .getProperty("javac.jvmOptions") + ?: error("Missing javac.jvmOptions in gradle/javac-internals.properties") + ) + .split(',') + .map { it.trim() } + .filter { it.isNotEmpty() } +val catalog = libs + +allprojects { + group = "com.sourcegraph" + version = providers.gradleProperty("releaseVersion").orElse("0.0.0-SNAPSHOT").get() +} + +subprojects { + // Several modules also have Bazel `BUILD` files. On the default macOS + // case-insensitive filesystem, Gradle's default `build/` directory collides + // with those files, so keep Gradle outputs under the already-ignored target/. + if (file("BUILD").isFile) { + layout.buildDirectory.set(layout.projectDirectory.dir("target/gradle")) + } + + plugins.withType { + extensions.configure { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + tasks.withType().configureEach { + options.encoding = "UTF-8" + options.release.set(11) + } + + tasks.withType().configureEach { + options.encoding = "UTF-8" + (options as StandardJavadocDocletOptions).addStringOption("Xdoclint:none", "-quiet") + } + + tasks.withType().configureEach { + useJUnitPlatform() + testLogging { + events("failed", "skipped") + } + } + } + + plugins.withId("org.jetbrains.kotlin.jvm") { + tasks.withType().configureEach { + compilerOptions.jvmTarget.set(JvmTarget.JVM_11) + } + } +} + +fun Project.configureMavenPublishing() { + apply(plugin = "com.vanniktech.maven.publish") + + extensions.configure("mavenPublishing") { + val repositoryUrl = "https://github.com/sourcegraph/scip-java" + publishToMavenCentral() + signAllPublications() + + pom { + name.set(project.name) + description.set(project.description ?: project.name) + url.set(repositoryUrl) + licenses { + license { + name.set("Apache-2.0") + url.set("http://www.apache.org/licenses/LICENSE-2.0") + } + } + developers { + developer { + id.set("sourcegraph") + name.set("Sourcegraph") + } + } + scm { + connection.set("scm:git:$repositoryUrl.git") + developerConnection.set("scm:git:ssh://git@github.com/sourcegraph/scip-java.git") + url.set(repositoryUrl) + } + } + } +} + +project(":scip-shared") { + apply(plugin = "java-library") + description = "Shared SCIP utilities used by scip-java compiler plugins" + + dependencies { + "api"(catalog.scip.java.bindings) + } + + configureMavenPublishing() +} + +project(":scip-javac") { + apply(plugin = "java-library") + apply(plugin = "com.github.johnrengelman.shadow") + description = "A javac plugin to emit SCIP information" + + dependencies { + "api"(project(":scip-shared")) + "testImplementation"(catalog.junit.jupiter.api) + "testRuntimeOnly"(catalog.junit.jupiter.engine) + "testRuntimeOnly"(catalog.junit.platform.launcher) + } + + tasks.named("compileJava") { + options.isDebug = true + val emptyProcessorPath = layout.buildDirectory.dir("empty-processorpath") + options.annotationProcessorPath = files(emptyProcessorPath) + doFirst { + emptyProcessorPath.get().asFile.mkdirs() + } + } + + tasks.named("test") { + jvmArgs(javacJvmOptions) + } + + tasks.named("shadowJar") { + mergeServiceFiles() + exclude("javax/**", "com/sun/**", "sun/**", "META-INF/versions/9/module-info.class") + relocate("com.google", "com.sourcegraph.shaded.com.google") + relocate("google", "com.sourcegraph.shaded.google") + relocate("org.relaxng", "com.sourcegraph.shaded.relaxng") + relocate("com.sourcegraph", "com.sourcegraph.shaded.com.sourcegraph") { + exclude("com.sourcegraph.scip_javac.ScipPlugin") + exclude("com.sourcegraph.scip_javac.InjectScipOptions") + } + } + + configureMavenPublishing() +} + +project(":scip-kotlinc") { + apply(plugin = "java-library") + apply(plugin = "org.jetbrains.kotlin.jvm") + apply(plugin = "com.github.johnrengelman.shadow") + description = "A kotlinc plugin to emit SCIP information" + + dependencies { + "implementation"(project(":scip-shared")) + "implementation"(catalog.scip.kotlin.bindings) + "compileOnly"(catalog.kotlin.stdlib) + "compileOnly"(catalog.kotlin.compiler.embeddable) + + "testImplementation"(catalog.kotlin.compiler.embeddable) + "testImplementation"(catalog.kotlin.test) + "testImplementation"(catalog.kotlin.test.junit5) + "testImplementation"(catalog.kotlin.reflect) + "testImplementation"(catalog.kotest.assertions.core) + "testImplementation"(catalog.kctfork.core) + "testRuntimeOnly"(catalog.junit.jupiter.engine) + "testRuntimeOnly"(catalog.junit.platform.launcher) + } + + tasks.withType().configureEach { + compilerOptions.freeCompilerArgs.add("-Xcontext-parameters") + } + + tasks.named("test") { + maxHeapSize = "2g" + } + + tasks.named("shadowJar") { + mergeServiceFiles() + relocate("com.intellij", "org.jetbrains.kotlin.com.intellij") + } + + configureMavenPublishing() +} + +project(":scip-gradle-plugin") { + apply(plugin = "java-library") + apply(plugin = "com.github.johnrengelman.shadow") + + dependencies { + "compileOnly"(catalog.gradle.api) + "compileOnly"(catalog.gradle.test.kit) + } +} + +project(":scip-maven-plugin") { + apply(plugin = "java-library") + description = "A Maven plugin that exports dependency metadata for scip-java" + + dependencies { + "implementation"(catalog.maven.plugin.api) + "implementation"(catalog.maven.project) + "compileOnly"(catalog.maven.plugin.annotations) + } + + tasks.named("processResources") { + exclude("META-INF/maven/plugin.template.xml") + from("src/main/resources/META-INF/maven/plugin.template.xml") { + into("META-INF/maven") + rename { "plugin.xml" } + filter { line: String -> line.replace("@VERSION@", project.version.toString()) } + } + inputs.property("version", project.version.toString()) + } + + configureMavenPublishing() +} + +project(":scip-aggregator") { + apply(plugin = "java-library") + apply(plugin = "com.google.protobuf") + description = "Aggregates compiler-plugin SCIP shards into a single SCIP index" + + dependencies { + "api"(catalog.scip.java.bindings) + "implementation"(project(":scip-shared")) + "testImplementation"(catalog.junit.jupiter.api) + "testRuntimeOnly"(catalog.junit.jupiter.engine) + "testRuntimeOnly"(catalog.junit.platform.launcher) + } + + extensions.configure("protobuf") { + val protobufVersion = catalog.versions.protobuf.asProvider().get() + protoc { + artifact = "com.google.protobuf:protoc:$protobufVersion" + } + } + + extensions.configure { + named("main") { + proto { + srcDir("src/main/protobuf") + } + } + } + + configureMavenPublishing() +} + +project(":scip-java") { + apply(plugin = "org.jetbrains.kotlin.jvm") + apply(plugin = "application") + description = "Java and Kotlin indexer for SCIP" + + dependencies { + "implementation"(project(":scip-aggregator")) + "implementation"(catalog.clikt.jvm) + "implementation"(catalog.kotlin.stdlib) + "implementation"(catalog.kotlin.compiler.embeddable) + "implementation"(catalog.kotlin.scripting.common) + "implementation"(catalog.kotlin.scripting.jvm) + "implementation"(catalog.kotlin.scripting.dependencies) + "implementation"(catalog.kotlin.scripting.dependencies.maven) + "implementation"(catalog.kotlinx.serialization.json.jvm) + + "testImplementation"(catalog.kotlin.test) + "testImplementation"(catalog.kotlin.test.junit5) + "testRuntimeOnly"(catalog.junit.jupiter.engine) + "testRuntimeOnly"(catalog.junit.platform.launcher) + } + + tasks.named("test") { + jvmArgs(javacJvmOptions) + systemProperty("scip.jdk.version", "11") + } + + extensions.configure { + mainClass.set("com.sourcegraph.scip_java.ScipJava") + } + + val generateEmbeddedResources = tasks.register("generateEmbeddedResources") { + val javacShadow = project(":scip-javac").tasks.named("shadowJar") + val gradleShadow = project(":scip-gradle-plugin").tasks.named("shadowJar") + val kotlincShadow = project(":scip-kotlinc").tasks.named("shadowJar") + + from(javacShadow.flatMap { it.archiveFile }) { + rename { "scip-plugin.jar" } + } + from(gradleShadow.flatMap { it.archiveFile }) { + rename { "gradle-plugin.jar" } + } + from(kotlincShadow.flatMap { it.archiveFile }) { + rename { "scip-kotlinc.jar" } + } + into(layout.buildDirectory.dir("generated/resources/embedded")) + } + + tasks.named("processResources") { + from(javacInternalsFile) + from(generateEmbeddedResources) + } + + tasks.named("jar") { + manifest { + attributes("Implementation-Version" to project.version) + } + } + + val generateDistributionVersion = tasks.register("generateDistributionVersion") { + val output = layout.buildDirectory.file("generated/distribution/VERSION") + inputs.property("version", project.version.toString()) + outputs.file(output) + doLast { + val file = output.get().asFile + file.parentFile.mkdirs() + file.writeText("version:=${project.version}\n") + } + } + + extensions.configure { + named("main") { + contents { + from(generateDistributionVersion) + } + } + } + + configureMavenPublishing() +} + +project(":scip-snapshots-java-common") { + apply(plugin = "java-library") + + dependencies { + "compileOnly"(catalog.lombok) + "annotationProcessor"(catalog.lombok) + } + + val annotationProcessorClasspath = configurations.named("annotationProcessor") + + tasks.named("compileJava") { + val javacShadow = project(":scip-javac").tasks.named("shadowJar") + val scipTargetroot = layout.buildDirectory.dir("scip-targetroot") + dependsOn(javacShadow) + classpath = classpath.plus(files(javacShadow.flatMap { it.archiveFile })) + options.annotationProcessorPath = + annotationProcessorClasspath.get().plus(files(javacShadow.flatMap { it.archiveFile })) + outputs.dir(scipTargetroot) + options.isFork = true + options.forkOptions.jvmArgs = (options.forkOptions.jvmArgs ?: emptyList()) + javacJvmOptions + options.compilerArgs.add( + "-Xplugin:scip -text:on -verbose -sourceroot:${rootProject.rootDir.absolutePath} " + + "-targetroot:${scipTargetroot.get().asFile.absolutePath} -randomtimestamp=${System.nanoTime()}" + ) + doFirst { + scipTargetroot.get().asFile.deleteRecursively() + scipTargetroot.get().asFile.mkdirs() + } + } +} + +project(":scip-snapshots-kotlin-common") { + apply(plugin = "java-library") + apply(plugin = "org.jetbrains.kotlin.jvm") + + dependencies { + "implementation"(catalog.kotlin.stdlib) + } + + val scipTargetroot = layout.buildDirectory.dir("scip-targetroot") + val javacShadow = project(":scip-javac").tasks.named("shadowJar") + val kotlincShadow = project(":scip-kotlinc").tasks.named("shadowJar") + + tasks.named("compileKotlin") { + dependsOn(kotlincShadow) + inputs.file(kotlincShadow.flatMap { it.archiveFile }) + outputs.dir(scipTargetroot) + compilerOptions.freeCompilerArgs.addAll( + "-Xplugin=${kotlincShadow.flatMap { it.archiveFile }.get().asFile.absolutePath}", + "-P", + "plugin:scip-kotlinc:sourceroot=${rootProject.rootDir.absolutePath}", + "-P", + "plugin:scip-kotlinc:targetroot=${scipTargetroot.get().asFile.absolutePath}", + ) + doFirst { + scipTargetroot.get().asFile.deleteRecursively() + scipTargetroot.get().asFile.mkdirs() + } + } + + tasks.named("compileJava") { + dependsOn(javacShadow) + classpath = classpath.plus(files(javacShadow.flatMap { it.archiveFile })) + options.annotationProcessorPath = files(javacShadow.flatMap { it.archiveFile }) + outputs.dir(scipTargetroot) + options.isFork = true + options.forkOptions.jvmArgs = (options.forkOptions.jvmArgs ?: emptyList()) + javacJvmOptions + options.compilerArgs.add( + "-Xplugin:scip -sourceroot:${rootProject.rootDir.absolutePath} " + + "-targetroot:${scipTargetroot.get().asFile.absolutePath}" + ) + } +} + +project(":scip-snapshots") { + apply(plugin = "java-library") + + dependencies { + "implementation"(project(":scip-java")) + "implementation"(catalog.scip.java.bindings) + "testImplementation"(catalog.junit.jupiter.api) + "testRuntimeOnly"(catalog.junit.jupiter.engine) + "testRuntimeOnly"(catalog.junit.platform.launcher) + } + + val javaCase = project(":scip-snapshots-java-common") + val kotlinCase = project(":scip-snapshots-kotlin-common") + val javaCaseClasses = javaCase.tasks.named("classes") + val kotlinCaseClasses = kotlinCase.tasks.named("classes") + val javaTargetroot = javaCase.layout.buildDirectory.dir("scip-targetroot") + val kotlinTargetroot = kotlinCase.layout.buildDirectory.dir("scip-targetroot") + val snapshotProperties = + mapOf( + "snapshot.sourceroot" to rootProject.rootDir.absolutePath, + "snapshot.cases" to "java-common,kotlin-common", + "snapshot.case.java-common.expectDir" to + rootProject.layout.projectDirectory.dir("scip-snapshots/expected/java/common").asFile.absolutePath, + "snapshot.case.java-common.targetroot" to javaTargetroot.get().asFile.absolutePath, + "snapshot.case.kotlin-common.expectDir" to + rootProject.layout.projectDirectory.dir("scip-snapshots/expected/kotlin/common").asFile.absolutePath, + "snapshot.case.kotlin-common.targetroot" to kotlinTargetroot.get().asFile.absolutePath, + "snapshot.case.kotlin-common.aggregateNoEmitInverseRelationships" to "true", + "scip.jdk.version" to "11", + ) + + tasks.named("test") { + dependsOn(javaCaseClasses, kotlinCaseClasses) + jvmArgs(javacJvmOptions) + systemProperties(snapshotProperties) + } + + tasks.register("saveSnapshots") { + group = "verification" + description = "Regenerates Java and Kotlin SCIP snapshot goldens." + dependsOn(tasks.named("classes"), javaCaseClasses, kotlinCaseClasses) + val sourceSets = project.extensions.getByType() + classpath = sourceSets.named("main").get().runtimeClasspath + mainClass.set("tests.SaveSnapshots") + jvmArgs(javacJvmOptions) + systemProperties(snapshotProperties) + } +} + +tasks.register("saveSnapshots") { + group = "verification" + description = "Regenerates all SCIP snapshot goldens." + dependsOn(":scip-snapshots:saveSnapshots") +} diff --git a/build.sbt b/build.sbt deleted file mode 100644 index 3dd9bcf23..000000000 --- a/build.sbt +++ /dev/null @@ -1,463 +0,0 @@ -import _root_.kotlin.Keys._ - -lazy val V = - new { - val protobuf = "4.34.2" - val scipBindings = "0.8.0" - val gradle = "8.10" - val kotlinVersion = "2.2.0" - val kotest = "4.6.3" - val kctfork = "0.7.1" - val clikt = "5.0.3" - val kotlinxSerialization = "1.9.0" - } - -// sbt-git's bundled JGit can't read linked worktrees; shell out to -// git CLI there. See https://github.com/sbt/sbt-git/issues/264. -if (file(".git").isFile) - Seq(useReadableConsoleGit) -else - Nil - -inThisBuild( - List( - organization := "com.sourcegraph", - homepage := Some(url("https://github.com/sourcegraph/scip-java")), - dynverSeparator := "-", - PB.protocVersion := V.protobuf, - autoScalaLibrary := false, - crossPaths := false, - // Pin bytecode to major 55 so compiler plugins can run on Java 11. - Compile / javacOptions ++= Seq("--release", "11"), - incOptions ~= { old => - old.withEnabled(false).withApiDebug(true) - }, - licenses := - List("Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0")) - ) -) - -name := "root" -(publish / skip) := true - -// Shared module with the SCIP shard utilities (symbol encoder, document -// builder, on-disk writer) consumed by both the Java compiler plugin -// (scip-javac) and the Kotlin compiler plugin (scip-kotlinc). -lazy val scipShared = project - .in(file("scip-shared")) - .settings( - moduleName := "scip-shared", - libraryDependencies += - "org.scip-code" % "scip-java-bindings" % V.scipBindings - ) - -lazy val javacPlugin = project - .in(file("scip-javac")) - .settings( - moduleName := "scip-javac", - // Scoped to compile so doc tasks (which reject -g) are unaffected. - Compile / compile / javacOptions += "-g", - // JDK 14+ ServiceLoader-scans the classpath for Plugin providers; our - // own META-INF/services entry points at ScipPlugin before it's - // built. Force an empty processor path so javac skips the scan. - Compile / compile / javacOptions ++= { - val empty = target.value / "empty-processorpath" - IO.createDirectory(empty) - Seq("-processorpath", empty.getAbsolutePath) - }, - (assembly / assemblyMergeStrategy) := { - case PathList("javax", _ @_*) => - MergeStrategy.discard - case PathList("com", "sun", _ @_*) => - MergeStrategy.discard - case PathList("sun", _ @_*) => - MergeStrategy.discard - case PathList("META-INF", "versions", "9", "module-info.class") => - MergeStrategy.discard - case x => - val oldStrategy = (assembly / assemblyMergeStrategy).value - oldStrategy(x) - }, - (assembly / assemblyShadeRules) := - Seq( - ShadeRule - .rename( - // Don't rename ScipPlugin since the fully-qualified name is - // referenced from META-INF/services/com.sun.source.util.Plugin - "com.sourcegraph.scip_javac.ScipPlugin" -> - "com.sourcegraph.scip_javac.ScipPlugin", - // Don't rename InjectScipOptions because we load it via FQN to - // process a list of Java compiler options. - "com.sourcegraph.scip_javac.InjectScipOptions" -> - "com.sourcegraph.scip_javac.InjectScipOptions", - "com.google.**" -> "com.sourcegraph.shaded.com.google.@1", - // Shade everything else in the scip-javac compiler plugin in - // order to be able to index the plugin code itself. Without this step, - // we can't add the plugin to the classpath while compiling the source - // code of the plugin itself because it results in cryptic compile errors. - "com.sourcegraph.**" -> "com.sourcegraph.shaded.com.sourcegraph.@1", - "google.**" -> "com.sourcegraph.shaded.google.@1", - "org.relaxng.**" -> "com.sourcegraph.shaded.relaxng.@1" - ) - .inAll - ), - // JUnit 5 for the colocated in-process javac tests (test scope only, so it - // stays out of the published scip-javac POM). - libraryDependencies += "com.github.sbt.junit" % "jupiter-interface" % - JupiterKeys.jupiterVersion.value % Test, - Test / fork := true, - // The tests drive javac in-process via ScipPlugin; on JDK 17+ this requires - // the JDK-internal javac packages to be opened. - Test / javaOptions ++= javacModuleOptions.map(_.stripPrefix("-J")) - ) - .dependsOn(scipShared) - -// The scip-kotlinc compiler plugin. Built as a fat-jar that is later -// embedded into the scip-java CLI distribution (see cli's resourceGenerators) -// so the runtime no longer needs to fetch a published scip-kotlinc -// artifact from Maven. -lazy val scipKotlinc = project - .in(file("scip-kotlinc")) - .enablePlugins(KotlinPlugin) - .settings( - name := "scip-kotlinc", - moduleName := "scip-kotlinc", - description := "A kotlinc plugin to emit SCIP information", - kotlinVersion := V.kotlinVersion, - kotlincJvmTarget := "1.8", - kotlincOptions ++= Seq("-Xinline-classes", "-Xcontext-parameters"), - // sbt-kotlin-plugin defaults to adding `kotlin-scripting-compiler-embeddable` - // (and its transitive kotlin-stdlib) as a regular dependency. Mark them - // Provided — kotlinc supplies them at runtime, and we don't want them - // bundled into the fat-jar. - kotlinRuntimeProvided := true, - // kotlin-stdlib is supplied by kotlinc at runtime — keep on compile - // classpath via Provided so the assembled fat-jar does not bundle it. - libraryDependencies += - "org.jetbrains.kotlin" % "kotlin-stdlib" % V.kotlinVersion % Provided, - // SCIP message classes come from scipShared (which depends on - // scip-java-bindings); this adds the Kotlin DSL extensions on top. - libraryDependencies += - "org.scip-code" % "scip-kotlin-bindings" % V.scipBindings, - // kotlin-compiler-embeddable is supplied by kotlinc at runtime - libraryDependencies += "org.jetbrains.kotlin" % - "kotlin-compiler-embeddable" % V.kotlinVersion % Provided, - // ---- sbt-assembly fat-jar --------------------------------------------- - // Produces a shaded jar for consumers that need a self-contained compiler - // plugin, such as the CLI resource embedding and minimized fixture build. - assembly / assemblyShadeRules := - Seq( - // Relocate any IntelliJ classes the same way kotlin-compiler-embeddable - // does internally. Do NOT rename `com.sourcegraph.**` — the - // META-INF/services files reference those FQNs. - ShadeRule - .rename("com.intellij.**" -> "org.jetbrains.kotlin.com.intellij.@1") - .inAll - ), - // tests - libraryDependencies ++= - Seq( - "org.jetbrains.kotlin" % "kotlin-compiler-embeddable" % - V.kotlinVersion % Test, - "org.jetbrains.kotlin" % "kotlin-test" % V.kotlinVersion % Test, - "org.jetbrains.kotlin" % "kotlin-test-junit5" % V.kotlinVersion % Test, - "org.jetbrains.kotlin" % "kotlin-reflect" % V.kotlinVersion % Test, - "io.kotest" % "kotest-assertions-core-jvm" % V.kotest % Test, - "dev.zacsweers.kctfork" % "core" % V.kctfork % Test, - "com.github.sbt.junit" % "jupiter-interface" % - JupiterKeys.jupiterVersion.value % Test - ), - Test / fork := true, - Test / javaOptions += "-Xmx2g", - // sbt-kotlin-plugin 3.1.6 inspects every jar on the kotlinc classpath and - // moves any jar containing META-INF/services/org.jetbrains.kotlin.compiler.plugin.* - // entries into the compiler-plugin classpath, removing it from the regular - // classpath. kctfork ships such service files for its own internal use as a - // KAPT/registrar shim, which makes its public API (com.tschuchort.compiletesting.*) - // invisible to our test sources. Workaround: pre-extract kctfork to a - // directory and add that directory to the test classpath — sbt-kotlin-plugin - // only inspects .jar files, so directories pass through unmodified. - Test / unmanagedJars += { - val report = update.value - val files = report.allFiles - val jar = files - .find(_.getName == s"core-${V.kctfork}.jar") - .getOrElse( - sys.error(s"kctfork core-${V.kctfork}.jar not found in update report") - ) - val dir = target.value / s"kctfork-${V.kctfork}-extracted" - val marker = dir / ".extracted" - if (!marker.exists()) { - IO.delete(dir) - IO.unzip(jar, dir) - IO.touch(marker) - } - Attributed.blank(dir) - } - ) - .dependsOn(scipShared) - -lazy val gradlePlugin = project - .in(file("scip-gradle-plugin")) - .settings( - name := "scip-gradle", - publish / skip := true, - libraryDependencies ++= - List( - "dev.gradleplugins" % "gradle-api" % V.gradle % Provided, - "dev.gradleplugins" % "gradle-test-kit" % V.gradle % Provided - ) - ) - -lazy val mavenPlugin = project - .in(file("scip-maven-plugin")) - .settings( - moduleName := "scip-maven-plugin", - libraryDependencies ++= - Seq( - "org.apache.maven" % "maven-plugin-api" % "3.6.3", - "org.apache.maven.plugin-tools" % "maven-plugin-annotations" % "3.6.4" % - Provided, - "org.apache.maven" % "maven-project" % "2.2.1" - ), - Compile / resourceGenerators += - Def.task { - val dir = (Compile / managedResourceDirectories).value.head / - "META-INF" / "maven" - IO.createDirectory(dir) - val file = dir / "plugin.xml" - val template = IO.read( - (Compile / resourceDirectory).value / "META-INF" / "maven" / - "plugin.template.xml" - ) - - IO.write(file, template.replace("@VERSION@", version.value)) - - Seq(file) - } - ) - -// Aggregates compiler-plugin shards into the final SCIP index consumed by the CLI. -lazy val scipAggregator = project - .in(file("scip-aggregator")) - .settings( - moduleName := "scip-aggregator", - libraryDependencies ++= - Seq( - "org.scip-code" % "scip-java-bindings" % V.scipBindings, - // JUnit 5 for the colocated Java unit tests (test scope only, so it is - // excluded from the published POM and keeps this a Java-only module). - "com.github.sbt.junit" % "jupiter-interface" % - JupiterKeys.jupiterVersion.value % Test - ), - (Compile / PB.targets) := - Seq(PB.gens.java(V.protobuf) -> (Compile / sourceManaged).value) - ) - .dependsOn(scipShared) - -lazy val cli = project - .in(file("scip-java")) - .enablePlugins(KotlinPlugin, PackPlugin) - .settings( - moduleName := "scip-java", - kotlinVersion := V.kotlinVersion, - kotlincJvmTarget := "11", - (Compile / mainClass) := Some("com.sourcegraph.scip_java.ScipJava"), - (run / baseDirectory) := (ThisBuild / baseDirectory).value, - // ScipJava.main can call System.exit, so we always fork the JVM when - // sbt invokes it directly so it cannot kill the surrounding sbt process. - Compile / run / fork := true, - Test / fork := true, - // Our CI set up is a couple of measly vCPUs so parallelising tests there makes - // everything worse. - Test / testForkedParallel := !sys.env.contains("CI"), - // The SCIP build tool drives javac in-process; on JDK 17+ this requires - // opening the JDK-internal javac packages. - Test / javaOptions ++= javacModuleOptions.map(_.stripPrefix("-J")), - // Pin the JDK version embedded in stdlib SCIP symbols so output is stable. - Test / javaOptions += "-Dscip.jdk.version=11", - libraryDependencies ++= - List( - "com.github.ajalt.clikt" % "clikt-jvm" % V.clikt, - "org.jetbrains.kotlinx" % "kotlinx-serialization-json-jvm" % - V.kotlinxSerialization, - "org.jetbrains.kotlin" % "kotlin-compiler-embeddable" % V.kotlinVersion, - "org.jetbrains.kotlin" % "kotlin-scripting-common" % V.kotlinVersion, - "org.jetbrains.kotlin" % "kotlin-scripting-jvm" % V.kotlinVersion, - "org.jetbrains.kotlin" % "kotlin-scripting-dependencies" % - V.kotlinVersion, - "org.jetbrains.kotlin" % "kotlin-scripting-dependencies-maven" % - V.kotlinVersion - ), - libraryDependencies ++= - Seq( - "org.jetbrains.kotlin" % "kotlin-test" % V.kotlinVersion % Test, - "org.jetbrains.kotlin" % "kotlin-test-junit5" % V.kotlinVersion % Test, - "com.github.sbt.junit" % "jupiter-interface" % - JupiterKeys.jupiterVersion.value % Test - ), - (Compile / resourceGenerators) += - Def - .task { - val out = (Compile / resourceManaged).value.toPath - IO.delete(out.toFile) - - val outs = Seq( - (javacPlugin / Compile / assembly).value -> - out.resolve("scip-plugin.jar").toFile, - (gradlePlugin / Compile / assembly).value -> - out.resolve("gradle-plugin.jar").toFile, - (scipKotlinc / Compile / assembly).value -> - out.resolve("scip-kotlinc.jar").toFile - ) - - IO.copy( - outs, - overwrite = true, - preserveLastModified = false, - preserveExecutable = true - ) - val propsFile = out.resolve("scip-java.properties").toFile - // Build version consumed at runtime by BuildInfo.version (Kotlin). - IO.write(propsFile, s"version=${version.value}\n") - - propsFile +: outs.map(_._2) - } - .taskValue - ) - .dependsOn(scipAggregator) - -// Kotlin snapshot case. The fixture includes Java sources as interop -// consumers, but the case is still keyed by the Kotlin compiler/plugin version -// axis. It writes *.scip shards under target/scip-targetroot/ for the central -// scipSnapshots project to aggregate and compare with goldens. -lazy val scipSnapshotsKotlinCommon = project - .in(file("scip-snapshots/cases/kotlin/common")) - .enablePlugins(KotlinPlugin) - .settings( - publish / skip := true, - kotlinVersion := V.kotlinVersion, - kotlincJvmTarget := "1.8", - kotlinLib("stdlib"), - // Force javac to fork. Two reasons: - // 1. JDK 9+ strongly encapsulates jdk.compiler internals; scip-javac - // reflectively touches them and needs --add-exports flags. With a - // forked javac we can pass `-J--add-exports=...` (mirrors scip-java). - // 2. sbt's in-process javac receives `vf://` virtual-file URIs from the - // MappedFileConverter, which scip-javac cannot resolve via - // java.nio.file.Path.of. Forked javac is invoked with absolute file - // paths instead, so the plugin sees real paths. - // Setting javaHome to Some() flips - // ZincUtil.compilers/JavaTools.directOrFork from direct → fork. - javaHome := Some(file(System.getProperty("java.home"))), - Compile / javacOptions ++= javacModuleOptions, - // Attach the assembled kotlinc fat-jar to the compile classpath. - // sbt-kotlin-plugin's AnalyzingKotlinCompiler partitions the classpath: - // any jar containing META-INF/services/org.jetbrains.kotlin.compiler.plugin* - // entries (which our fat-jar does, for both CommandLineProcessor and - // CompilerPluginRegistrar) is moved into args.pluginClasspaths and removed - // from the regular classpath. So no `-Xplugin=` is needed and we - // don't have to predict the assembled jar's filename. The .value reference - // also gives us the right task ordering — assembly runs before compile. - Compile / unmanagedJars += - Attributed.blank((scipKotlinc / Compile / assembly).value), - // Wire the locally-built scip-javac fat jar in place of fetching the - // published `com.sourcegraph:scip-javac` artifact at compile time. - Compile / unmanagedJars += - Attributed.blank((javacPlugin / Compile / assembly).value), - Compile / kotlincPluginOptions ++= { - val srcRoot = (ThisBuild / baseDirectory).value.getAbsolutePath - val tgtRoot = (target.value / "scip-targetroot").getAbsolutePath - Seq( - s"plugin:scip-kotlinc:sourceroot=$srcRoot", - s"plugin:scip-kotlinc:targetroot=$tgtRoot" - ) - }, - // The scip javac plugin parses its own argument string, so - // `-Xplugin:scip -sourceroot:<...> -targetroot:<...>` MUST be passed - // as a single javac argument (matches the existing Gradle behavior). - Compile / javacOptions += { - val srcRoot = (ThisBuild / baseDirectory).value - val tgtRoot = target.value / "scip-targetroot" - s"-Xplugin:scip -sourceroot:${srcRoot.getAbsolutePath} " + - s"-targetroot:${tgtRoot.getAbsolutePath}" - } - ) - -lazy val scipSnapshotsJavaCommon = project - .in(file("scip-snapshots/cases/java/common")) - .settings( - publish / skip := true, - run / fork := true, - libraryDependencies += "org.projectlombok" % "lombok" % "1.18.22", - // Fork javac so it receives real file paths instead of sbt's `vf://` virtual-file URIs - // (see the comment on `scipSnapshotsKotlinCommon` for the long story). - javaHome := Some(file(System.getProperty("java.home"))), - // Keep minimized snapshots stable across JDK 11/17/21. - Compile / javacOptions ++= Seq("--release", "11"), - Compile / javacOptions ++= javacModuleOptions, - javacOptions += - List( - s"-Xplugin:scip", - s"-text:on", - s"-verbose", - s"-sourceroot:${(ThisBuild / baseDirectory).value}", - s"-targetroot:${(Compile / semanticdbTargetRoot).value}", - s"-randomtimestamp=${System.nanoTime()}" - ).mkString(" ") - ) - .dependsOn(javacPlugin) - -def javacModuleOptions = List( - "-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", - "-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", - "-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", - "-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", - "-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" -) - -lazy val scipSnapshots = project - .in(file("scip-snapshots")) - .settings( - publish / skip := true, - Test / fork := true, - // Open the JDK-internal javac packages to the in-process javac the tests - // drive; on JDK 17+ this is required or the reflective access fails. - Test / javaOptions ++= javacModuleOptions.map(_.stripPrefix("-J")), - // Pin the JDK version embedded in stdlib SCIP symbols (e.g. `jdk 11 - // java/lang/String#`) so snapshots are stable across JDK 11/17/21. - Test / javaOptions += "-Dscip.jdk.version=11", - libraryDependencies += "com.github.sbt.junit" % "jupiter-interface" % - JupiterKeys.jupiterVersion.value % Test, - Compile / mainClass := Some("tests.SaveSnapshots"), - Compile / run / fork := true, - Test / javaOptions ++= snapshotPathOptions.value, - Compile / run / javaOptions ++= snapshotPathOptions.value - ) - .dependsOn(cli) - -// Runtime paths for the snapshot generator, passed as -D system properties. -// Depending on each snapshot case's compile task guarantees fresh targetroots -// whenever `scipSnapshots/test` or `scipSnapshots/run` evaluate javaOptions. -def snapshotPathOptions = Def.task { - val _java = (scipSnapshotsJavaCommon / Compile / compile).value - val _kotlin = (scipSnapshotsKotlinCommon / Compile / compile).value - val snapshotRoot = (ThisBuild / baseDirectory).value / "scip-snapshots" - Seq( - s"-Dsnapshot.sourceroot=${(ThisBuild / baseDirectory).value.getAbsolutePath}", - "-Dsnapshot.cases=java-common,kotlin-common", - s"-Dsnapshot.case.java-common.expectDir=${( - snapshotRoot / "expected" / "java" / "common" - ).getAbsolutePath}", - s"-Dsnapshot.case.java-common.targetroot=${( - scipSnapshotsJavaCommon / Compile / semanticdbTargetRoot - ).value.getAbsolutePath}", - s"-Dsnapshot.case.kotlin-common.expectDir=${( - snapshotRoot / "expected" / "kotlin" / "common" - ).getAbsolutePath}", - s"-Dsnapshot.case.kotlin-common.targetroot=${(( - scipSnapshotsKotlinCommon / target - ).value / "scip-targetroot").getAbsolutePath}", - "-Dsnapshot.case.kotlin-common.aggregateNoEmitInverseRelationships=true" - ) -} diff --git a/docs/getting-started.md b/docs/getting-started.md index 2707c705d..d8f5c7a8b 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -66,11 +66,11 @@ Docker image with a pre-installed Java version. # macOS/Linux curl -fLo coursier https://git.io/coursier-cli \ && chmod +x coursier \ - && ./coursier launch com.sourcegraph:scip-java_2.13:@STABLE_VERSION@ -- --help + && ./coursier launch com.sourcegraph:scip-java:@STABLE_VERSION@ -- --help # macOS Homebrew brew install coursier/formulas/coursier \ - && coursier launch com.sourcegraph:scip-java_2.13:@STABLE_VERSION@ -- --help + && coursier launch com.sourcegraph:scip-java:@STABLE_VERSION@ -- --help ``` The Java launcher uses @@ -92,7 +92,7 @@ you still need a Java installation to run the `scip-java` binary. # macOS/Linux curl -fLo coursier https://git.io/coursier-cli \ && chmod +x coursier \ - && ./coursier bootstrap --standalone -o scip-java com.sourcegraph:scip-java_2.13:@STABLE_VERSION@ --main com.sourcegraph.scip_java.ScipJava + && ./coursier bootstrap --standalone -o scip-java com.sourcegraph:scip-java:@STABLE_VERSION@ --main com.sourcegraph.scip_java.ScipJava ./scip-java --help ``` @@ -107,12 +107,12 @@ The `scip-java` command-line interface is published to Maven Central. You can run the command-line interface as a library by directly invoking the `main()` method on the `com.sourcegraph.scip_java.ScipJava` class. -[![](https://img.shields.io/maven-central/v/com.sourcegraph/scip-java_2.13)](https://repo1.maven.org/maven2/com/sourcegraph/scip-java_2.13/) +[![](https://img.shields.io/maven-central/v/com.sourcegraph/scip-java)](https://repo1.maven.org/maven2/com/sourcegraph/scip-java/) If you're using Gradle. ```groovy -implementation group: 'com.sourcegraph', name: 'scip-java_2.13', version: '@STABLE_VERSION@' +implementation group: 'com.sourcegraph', name: 'scip-java', version: '@STABLE_VERSION@' ``` If you're using Maven. @@ -120,7 +120,7 @@ If you're using Maven. ```xml com.sourcegraph - scip-java_2.13 + scip-java @STABLE_VERSION@ ``` diff --git a/flake.nix b/flake.nix index bbe5eece7..53b054dc4 100644 --- a/flake.nix +++ b/flake.nix @@ -37,7 +37,6 @@ (maven.override ({ jdk_headless = jdk; })) nixfmt nodejs - (sbt.override ({ jre = jdk; })) scipCli yarn ]; diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 000000000..1eafd41ed --- /dev/null +++ b/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8 +kotlin.code.style=official +kotlin.stdlib.default.dependency=false diff --git a/gradle/javac-internals.properties b/gradle/javac-internals.properties new file mode 100644 index 000000000..c1e82fca5 --- /dev/null +++ b/gradle/javac-internals.properties @@ -0,0 +1,7 @@ +# JVM flags required by scip-javac to access internal javac APIs on Java 9+. +javac.jvmOptions=\ +--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED,\ +--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED,\ +--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED,\ +--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED,\ +--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 000000000..637001a88 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,50 @@ +[versions] +clikt = "5.0.3" +gradle-api = "8.10" +junit-jupiter = "5.11.4" +junit-platform = "1.11.4" +kctfork = "0.7.1" +kotest = "4.6.3" +kotlin = "2.2.0" +kotlinx-serialization = "1.9.0" +lombok = "1.18.22" +maven-plugin-annotations = "3.6.4" +maven-plugin-api = "3.6.3" +maven-project = "2.2.1" +protobuf = "4.34.2" +protobuf-plugin = "0.9.4" +scip-bindings = "0.8.0" +shadow = "8.1.1" +vanniktech-maven-publish = "0.35.0" + +[libraries] +clikt-jvm = { module = "com.github.ajalt.clikt:clikt-jvm", version.ref = "clikt" } +gradle-api = { module = "dev.gradleplugins:gradle-api", version.ref = "gradle-api" } +gradle-test-kit = { module = "dev.gradleplugins:gradle-test-kit", version.ref = "gradle-api" } +junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit-jupiter" } +junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit-jupiter" } +junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junit-platform" } +kctfork-core = { module = "dev.zacsweers.kctfork:core", version.ref = "kctfork" } +kotest-assertions-core = { module = "io.kotest:kotest-assertions-core-jvm", version.ref = "kotest" } +kotlin-compiler-embeddable = { module = "org.jetbrains.kotlin:kotlin-compiler-embeddable", version.ref = "kotlin" } +kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } +kotlin-scripting-common = { module = "org.jetbrains.kotlin:kotlin-scripting-common", version.ref = "kotlin" } +kotlin-scripting-dependencies = { module = "org.jetbrains.kotlin:kotlin-scripting-dependencies", version.ref = "kotlin" } +kotlin-scripting-dependencies-maven = { module = "org.jetbrains.kotlin:kotlin-scripting-dependencies-maven", version.ref = "kotlin" } +kotlin-scripting-jvm = { module = "org.jetbrains.kotlin:kotlin-scripting-jvm", version.ref = "kotlin" } +kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" } +kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } +kotlin-test-junit5 = { module = "org.jetbrains.kotlin:kotlin-test-junit5", version.ref = "kotlin" } +kotlinx-serialization-json-jvm = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-jvm", version.ref = "kotlinx-serialization" } +lombok = { module = "org.projectlombok:lombok", version.ref = "lombok" } +maven-plugin-annotations = { module = "org.apache.maven.plugin-tools:maven-plugin-annotations", version.ref = "maven-plugin-annotations" } +maven-plugin-api = { module = "org.apache.maven:maven-plugin-api", version.ref = "maven-plugin-api" } +maven-project = { module = "org.apache.maven:maven-project", version.ref = "maven-project" } +scip-java-bindings = { module = "org.scip-code:scip-java-bindings", version.ref = "scip-bindings" } +scip-kotlin-bindings = { module = "org.scip-code:scip-kotlin-bindings", version.ref = "scip-bindings" } + +[plugins] +kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +protobuf = { id = "com.google.protobuf", version.ref = "protobuf-plugin" } +shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" } +vanniktech-maven-publish = { id = "com.vanniktech.maven.publish", version.ref = "vanniktech-maven-publish" } diff --git a/project/build.properties b/project/build.properties deleted file mode 100644 index c02c575fd..000000000 --- a/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.11.3 diff --git a/project/plugins.sbt b/project/plugins.sbt deleted file mode 100644 index b098a7edd..000000000 --- a/project/plugins.sbt +++ /dev/null @@ -1,6 +0,0 @@ -addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.16") -addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.11.1") -addSbtPlugin("com.thesamet" % "sbt-protoc" % "1.0.6") -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.15.0") -addSbtPlugin("org.jetbrains.scala" % "sbt-kotlin-plugin" % "3.1.6") -addSbtPlugin("com.github.sbt.junit" % "sbt-jupiter-interface" % "0.15.1") diff --git a/scip-java/src/main/kotlin/com/sourcegraph/scip_java/BuildInfo.kt b/scip-java/src/main/kotlin/com/sourcegraph/scip_java/BuildInfo.kt deleted file mode 100644 index 058f91489..000000000 --- a/scip-java/src/main/kotlin/com/sourcegraph/scip_java/BuildInfo.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.sourcegraph.scip_java - -import java.util.Properties - -/** - * Build metadata for the scip-java CLI. - * - * Replaces the previously sbt-generated `BuildInfo.java`. The static [javacModuleOptions] live here - * directly; the build-time [version] is injected by sbt into the `scip-java.properties` classpath - * resource (see the `resourceGenerators` for the `cli` project in build.sbt). - */ -object BuildInfo { - - /** - * `--add-exports` flags required to access internal javac APIs from the SCIP compiler plugin. - * Java 11+ is the supported baseline. - * - * Kept in sync with `javacModuleOptions` in build.sbt, which applies the same flags when - * compiling the plugin and the test fixtures. - */ - val javacModuleOptions: List = - listOf( - "-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", - "-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", - "-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", - "-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", - "-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", - ) - - /** - * The scip-java release version. Read from the `scip-java.properties` resource that sbt - * generates into the jar. Falls back to a placeholder when running without the generated - * resource on the classpath. - */ - val version: String by lazy { - val props = Properties() - BuildInfo::class.java.getResourceAsStream("/scip-java.properties")?.use { props.load(it) } - props.getProperty("version") ?: "0.0.0-SNAPSHOT" - } -} diff --git a/scip-java/src/main/kotlin/com/sourcegraph/scip_java/Embedded.kt b/scip-java/src/main/kotlin/com/sourcegraph/scip_java/Embedded.kt index 7fbad332b..d7400ac3a 100644 --- a/scip-java/src/main/kotlin/com/sourcegraph/scip_java/Embedded.kt +++ b/scip-java/src/main/kotlin/com/sourcegraph/scip_java/Embedded.kt @@ -5,9 +5,22 @@ import java.nio.charset.StandardCharsets import java.nio.file.Files import java.nio.file.Path import java.nio.file.StandardCopyOption +import java.util.Properties object Embedded { + val javacLauncherJvmOptions: List by lazy { + val properties = Properties() + val input = + Embedded::class.java.getResourceAsStream("/javac-internals.properties") + ?: error("missing embedded resource: /javac-internals.properties") + input.use { properties.load(it) } + val jvmOptions = + properties.getProperty("javac.jvmOptions") + ?: error("missing javac.jvmOptions in /javac-internals.properties") + jvmOptions.split(',').map { it.trim() }.filter { it.isNotEmpty() }.map { "-J$it" } + } + fun scipJar(tmpDir: Path): Path = copyFile(tmpDir, "scip-plugin.jar") fun gradlePluginJar(tmpDir: Path): Path = copyFile(tmpDir, "gradle-plugin.jar") @@ -16,7 +29,9 @@ object Embedded { private fun javacErrorpath(tmp: Path): Path = tmp.resolve("errorpath.txt") - fun customJavac(sourceroot: Path, targetroot: Path, tmp: Path): Path { + data class CustomJavac(val executable: Path, val environment: Map) + + fun customJavac(sourceroot: Path, targetroot: Path, tmp: Path): CustomJavac { val bin = tmp.resolve("bin") val javac = bin.resolve("javac") val java = bin.resolve("java") @@ -25,49 +40,22 @@ object Embedded { val javacopts = targetroot.resolve("javacopts.txt") Files.createDirectories(targetroot) Files.createDirectories(bin) - Files.write( - java, - ("#!/usr/bin/env bash\n" + "java \"\$@\"\n").toByteArray(StandardCharsets.UTF_8), - ) - val newJavacopts = tmp.resolve("javac_newarguments") - // --add-exports flags required to access internal javac APIs from our - // SCIP plugin. Always set; Java 11+ is the supported baseline. - val javacModuleOptions = BuildInfo.javacModuleOptions.joinToString(" ") - val injectScipArguments = - listOf( - "java", - "-Dscip.errorpath=$errorpath", - "-Dscip.pluginpath=$pluginpath", - "-Dscip.sourceroot=$sourceroot", - "-Dscip.targetroot=$targetroot", - "-Dscip.output=\$NEW_JAVAC_OPTS", - "-Dscip.old-output=$javacopts", - "-classpath $pluginpath", - "com.sourcegraph.scip_javac.InjectScipOptions", - "\"\$@\"", - ) - .joinToString(" ") - val script = buildString { - append("#!/usr/bin/env bash\n") - append("set -eu\n") - append("LAUNCHER_ARGS=()\n") - append("NEW_JAVAC_OPTS=\"$newJavacopts-\$RANDOM\"\n") - append("for arg in \"\$@\"; do\n") - append(" if [[ \$arg == -J* ]]; then\n") - append(" LAUNCHER_ARGS+=(\"\$arg\")\n") - append(" fi\n") - append("done\n") - append(injectScipArguments).append('\n') - append("if [ \${#LAUNCHER_ARGS[@]} -eq 0 ]; then\n") - append(" javac $javacModuleOptions \"@\$NEW_JAVAC_OPTS\"\n") - append("else\n") - append(" javac $javacModuleOptions \"@\$NEW_JAVAC_OPTS\" \"\${LAUNCHER_ARGS[@]}\"\n") - append("fi\n") - } - Files.write(javac, script.toByteArray(StandardCharsets.UTF_8)) + copyResource(java, "scip-java/java-forwarder.sh") + copyResource(javac, "scip-java/custom-javac.sh") javac.toFile().setExecutable(true) java.toFile().setExecutable(true) - return javac + return CustomJavac( + javac, + mapOf( + "SCIP_ERRORPATH" to errorpath.toString(), + "SCIP_JAVAC_LAUNCHER_JVM_OPTIONS" to javacLauncherJvmOptions.joinToString("\n"), + "SCIP_JAVAC_OPTIONS_PREFIX" to tmp.resolve("javac_newarguments").toString(), + "SCIP_OLD_JAVAC_OPTS" to javacopts.toString(), + "SCIP_PLUGINPATH" to pluginpath.toString(), + "SCIP_SOURCEROOT" to sourceroot.toString(), + "SCIP_TARGETROOT" to targetroot.toString(), + ), + ) } /** @@ -93,12 +81,16 @@ object Embedded { } private fun copyFile(tmpDir: Path, filename: String): Path { - val input = - Embedded::class.java.getResourceAsStream("/$filename") - ?: error("missing embedded resource: /$filename") val out = tmpDir.resolve(filename) + copyResource(out, filename) + return out + } + + private fun copyResource(out: Path, resource: String) { + val input = + Embedded::class.java.getResourceAsStream("/$resource") + ?: error("missing embedded resource: /$resource") Files.createDirectories(out.parent) input.use { Files.copy(it, out, StandardCopyOption.REPLACE_EXISTING) } - return out } } diff --git a/scip-java/src/main/kotlin/com/sourcegraph/scip_java/ScipJava.kt b/scip-java/src/main/kotlin/com/sourcegraph/scip_java/ScipJava.kt index 70d2dfb3d..bd69ca9e1 100644 --- a/scip-java/src/main/kotlin/com/sourcegraph/scip_java/ScipJava.kt +++ b/scip-java/src/main/kotlin/com/sourcegraph/scip_java/ScipJava.kt @@ -10,6 +10,10 @@ object ScipJava { @JvmField val app: ScipJavaApp = ScipJavaApp() + val version: String by lazy { + ScipJava::class.java.`package`?.implementationVersion ?: "0.0.0-SNAPSHOT" + } + @JvmStatic fun main(args: Array) { app.runAndExitIfNonZero(args.toList()) diff --git a/scip-java/src/main/kotlin/com/sourcegraph/scip_java/ScipJavaApp.kt b/scip-java/src/main/kotlin/com/sourcegraph/scip_java/ScipJavaApp.kt index a4f612e97..3e073b94d 100644 --- a/scip-java/src/main/kotlin/com/sourcegraph/scip_java/ScipJavaApp.kt +++ b/scip-java/src/main/kotlin/com/sourcegraph/scip_java/ScipJavaApp.kt @@ -65,7 +65,7 @@ class ScipJavaApp { reporter.reset() val processedArgs = applyGlobalCwd(rewriteNestedOptions(args)) val root = RootCommand(this) - root.versionOption(BuildInfo.version, names = setOf("--version", "-v")) + root.versionOption(ScipJava.version, names = setOf("--version", "-v")) root.subcommands(IndexCommand(), AggregateCommand(), SnapshotCommand()) return try { root.parse(processedArgs) diff --git a/scip-java/src/main/kotlin/com/sourcegraph/scip_java/buildtools/MavenBuildTool.kt b/scip-java/src/main/kotlin/com/sourcegraph/scip_java/buildtools/MavenBuildTool.kt index 83e0f7ed8..be37f3f91 100644 --- a/scip-java/src/main/kotlin/com/sourcegraph/scip_java/buildtools/MavenBuildTool.kt +++ b/scip-java/src/main/kotlin/com/sourcegraph/scip_java/buildtools/MavenBuildTool.kt @@ -24,7 +24,7 @@ class MavenBuildTool(index: IndexCommand) : BuildTool("Maven", index) { val mavenScript = if (Files.isRegularFile(mvnw) && Files.isExecutable(mvnw)) mvnw.toString() else "mvn" - val executable = + val javac = Embedded.customJavac( index.workingDirectory, index.finalTargetroot(defaultTargetroot), @@ -38,7 +38,7 @@ class MavenBuildTool(index: IndexCommand) : BuildTool("Maven", index) { // '-Dmaven.compiler.executable' setting. Forcing the compilerId to // 'javac' fixes the issue for this repo. command += "-Dmaven.compiler.compilerId=javac" - command += "-Dmaven.compiler.executable=$executable" + command += "-Dmaven.compiler.executable=${javac.executable}" command += "-Dmaven.compiler.fork=true" command += index.finalBuildCommand( @@ -52,7 +52,7 @@ class MavenBuildTool(index: IndexCommand) : BuildTool("Maven", index) { ) ) - val exit = index.app.runProcess(command) + val exit = index.app.runProcess(command, env = javac.environment) Embedded.reportUnexpectedJavacErrors(index.app.reporter, tmp) ?: exit } } diff --git a/scip-java/src/main/kotlin/com/sourcegraph/scip_java/buildtools/ScipBuildTool.kt b/scip-java/src/main/kotlin/com/sourcegraph/scip_java/buildtools/ScipBuildTool.kt index 7b0eef76b..35224af3f 100644 --- a/scip-java/src/main/kotlin/com/sourcegraph/scip_java/buildtools/ScipBuildTool.kt +++ b/scip-java/src/main/kotlin/com/sourcegraph/scip_java/buildtools/ScipBuildTool.kt @@ -1,6 +1,5 @@ package com.sourcegraph.scip_java.buildtools -import com.sourcegraph.scip_java.BuildInfo import com.sourcegraph.scip_java.Embedded import com.sourcegraph.scip_java.commands.IndexCommand import java.io.File @@ -166,7 +165,7 @@ class ScipBuildTool(index: IndexCommand) : BuildTool("SCIP", index) { // The scip-kotlinc compiler plugin is built and shipped together // with the scip-java CLI as an embedded resource (see Embedded.kt and - // the cli/resourceGenerators task in build.sbt). + // the :scip-java Gradle resources wiring). val plugin = Embedded.scipKotlincJar(tmp) val classpath = @@ -300,13 +299,12 @@ class ScipBuildTool(index: IndexCommand) : BuildTool("SCIP", index) { } val javac = javacPath(config) index.app.reporter.info("$ $javac @$argsfile") - val javacModuleOptions = BuildInfo.javacModuleOptions val jvmOptions = config.jvmOptions.map { "-J$it" } val cmd = mutableListOf() cmd += javac.toString() cmd += "@$argsfile" - cmd += javacModuleOptions + cmd += Embedded.javacLauncherJvmOptions cmd += jvmOptions val result = ProcessRunner.run( diff --git a/scip-java/src/main/kotlin/com/sourcegraph/scip_java/commands/AggregateRunner.kt b/scip-java/src/main/kotlin/com/sourcegraph/scip_java/commands/AggregateRunner.kt index 730e2999e..af5404124 100644 --- a/scip-java/src/main/kotlin/com/sourcegraph/scip_java/commands/AggregateRunner.kt +++ b/scip-java/src/main/kotlin/com/sourcegraph/scip_java/commands/AggregateRunner.kt @@ -2,7 +2,7 @@ package com.sourcegraph.scip_java.commands import com.sourcegraph.scip_aggregator.ScipAggregator import com.sourcegraph.scip_aggregator.ScipAggregatorOptions -import com.sourcegraph.scip_java.BuildInfo +import com.sourcegraph.scip_java.ScipJava import com.sourcegraph.scip_java.ScipJavaApp import com.sourcegraph.scip_java.buildtools.ClasspathEntry import java.nio.file.Path @@ -41,7 +41,7 @@ object AggregateRunner { absoluteOutput, sourceroot, app.reporter, - ToolInfo.newBuilder().setName("scip-java").setVersion(BuildInfo.version).build(), + ToolInfo.newBuilder().setName("scip-java").setVersion(ScipJava.version).build(), parallel, packages.map { it.toPackageInformation() }, emitInverseRelationships, diff --git a/scip-java/src/main/resources/scip-java/custom-javac.sh b/scip-java/src/main/resources/scip-java/custom-javac.sh new file mode 100644 index 000000000..f8c2e6cbb --- /dev/null +++ b/scip-java/src/main/resources/scip-java/custom-javac.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -eu + +: "${SCIP_ERRORPATH:?}" +: "${SCIP_JAVAC_LAUNCHER_JVM_OPTIONS:?}" +: "${SCIP_JAVAC_OPTIONS_PREFIX:?}" +: "${SCIP_OLD_JAVAC_OPTS:?}" +: "${SCIP_PLUGINPATH:?}" +: "${SCIP_SOURCEROOT:?}" +: "${SCIP_TARGETROOT:?}" + +LAUNCHER_ARGS=() +JAVAC_JVM_OPTIONS=() +while IFS= read -r option; do + if [[ -n "$option" ]]; then + JAVAC_JVM_OPTIONS+=("$option") + fi +done <<< "$SCIP_JAVAC_LAUNCHER_JVM_OPTIONS" +NEW_JAVAC_OPTS="$SCIP_JAVAC_OPTIONS_PREFIX-$RANDOM" + +for arg in "$@"; do + if [[ $arg == -J* ]]; then + LAUNCHER_ARGS+=("$arg") + fi +done + +java \ + "-Dscip.errorpath=$SCIP_ERRORPATH" \ + "-Dscip.pluginpath=$SCIP_PLUGINPATH" \ + "-Dscip.sourceroot=$SCIP_SOURCEROOT" \ + "-Dscip.targetroot=$SCIP_TARGETROOT" \ + -Dscip.output="$NEW_JAVAC_OPTS" \ + "-Dscip.old-output=$SCIP_OLD_JAVAC_OPTS" \ + -classpath "$SCIP_PLUGINPATH" \ + com.sourcegraph.scip_javac.InjectScipOptions \ + "$@" + +javac "${JAVAC_JVM_OPTIONS[@]}" "@$NEW_JAVAC_OPTS" "${LAUNCHER_ARGS[@]}" diff --git a/scip-java/src/main/resources/scip-java/java-forwarder.sh b/scip-java/src/main/resources/scip-java/java-forwarder.sh new file mode 100644 index 000000000..b1f148234 --- /dev/null +++ b/scip-java/src/main/resources/scip-java/java-forwarder.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec java "$@" diff --git a/scip-snapshots/README.md b/scip-snapshots/README.md index 22455a71b..1da6073c1 100644 --- a/scip-snapshots/README.md +++ b/scip-snapshots/README.md @@ -20,5 +20,5 @@ expected/ version-specific cases when a fixture needs newer language features, for example `cases/java/release-17`, `cases/java/release-21`, or `cases/kotlin/kotlin-2.2`. -Run `sbt scipSnapshots/test` to compare goldens and `sbt scipSnapshots/run` to -regenerate them. +Run `gradle :scip-snapshots:test` to compare goldens and +`gradle :scip-snapshots:saveSnapshots` to regenerate them. diff --git a/scip-snapshots/src/main/java/tests/MinimizedSnapshotScipGenerator.java b/scip-snapshots/src/main/java/tests/MinimizedSnapshotScipGenerator.java index 8b61cedca..dc635c0ce 100644 --- a/scip-snapshots/src/main/java/tests/MinimizedSnapshotScipGenerator.java +++ b/scip-snapshots/src/main/java/tests/MinimizedSnapshotScipGenerator.java @@ -18,8 +18,7 @@ /** * Indexes the {@code scip-snapshots/cases} corpora and renders golden SCIP snapshots. Runtime paths - * are supplied as {@code -Dsnapshot.*} system properties by the sbt build (see build.sbt), - * replacing the former sbt-buildinfo generated values. + * are supplied as {@code -Dsnapshot.*} system properties by the Gradle build. */ public class MinimizedSnapshotScipGenerator { public static final class SnapshotCase { @@ -140,7 +139,9 @@ private static String requiredProperty(String name) { String value = System.getProperty(name); if (value == null || value.trim().isEmpty()) { throw new IllegalStateException( - "Missing -D" + name + ". Run via sbt scipSnapshots/test or scipSnapshots/run."); + "Missing -D" + + name + + ". Run via gradle :scip-snapshots:test or :scip-snapshots:saveSnapshots."); } return value; } diff --git a/scip-snapshots/src/main/java/tests/SaveSnapshots.java b/scip-snapshots/src/main/java/tests/SaveSnapshots.java index 40affa330..1180e8d6e 100644 --- a/scip-snapshots/src/main/java/tests/SaveSnapshots.java +++ b/scip-snapshots/src/main/java/tests/SaveSnapshots.java @@ -1,15 +1,15 @@ package tests; /** - * Regenerates all snapshot goldens (invoked by {@code sbt scipSnapshots/run}). Snapshot cases are - * supplied via {@code -Dsnapshot.*} system properties by the sbt build. + * Regenerates all snapshot goldens (invoked by {@code gradle :scip-snapshots:saveSnapshots}). + * Snapshot cases are supplied via {@code -Dsnapshot.*} system properties by the Gradle build. */ public final class SaveSnapshots { private SaveSnapshots() {} public static void main(String[] args) { // Keep regenerated goldens stable across JDK 11/17/21 by pinning the JDK version embedded in - // stdlib SCIP symbols. Matches the `-Dscip.jdk.version=11` set on the test JVM in build.sbt. + // stdlib SCIP symbols. Matches the `-Dscip.jdk.version=11` set on the test JVM in Gradle. System.setProperty("scip.jdk.version", "11"); MinimizedSnapshotScipGenerator generator = new MinimizedSnapshotScipGenerator(); for (MinimizedSnapshotScipGenerator.SnapshotCase snapshotCase : diff --git a/scip-snapshots/src/test/java/tests/AssertSnapshotHandler.java b/scip-snapshots/src/test/java/tests/AssertSnapshotHandler.java index 3882b626a..201ba04b3 100644 --- a/scip-snapshots/src/test/java/tests/AssertSnapshotHandler.java +++ b/scip-snapshots/src/test/java/tests/AssertSnapshotHandler.java @@ -40,7 +40,8 @@ public void onSnapshotTest( fail( "no snapshot file for " + relativePath - + ". To fix this problem, execute the command 'sbt scipSnapshots/run'"); + + ". To fix this problem, execute the command 'gradle" + + " :scip-snapshots:saveSnapshots'"); } String expected; try { diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 000000000..a0f22fcdb --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,32 @@ +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + mavenCentral() + gradlePluginPortal() + } +} + +rootProject.name = "scip-java" + +include( + "scip-shared", + "scip-javac", + "scip-kotlinc", + "scip-aggregator", + "scip-maven-plugin", + "scip-gradle-plugin", + "scip-java", + "scip-snapshots", + "scip-snapshots-java-common", + "scip-snapshots-kotlin-common", +) + +project(":scip-snapshots-java-common").projectDir = file("scip-snapshots/cases/java/common") +project(":scip-snapshots-kotlin-common").projectDir = file("scip-snapshots/cases/kotlin/common")