diff --git a/build.sbt b/build.sbt index 721c3b41..b0757f9c 100644 --- a/build.sbt +++ b/build.sbt @@ -85,29 +85,28 @@ lazy val semanticdbShared = project lazy val gradlePlugin = project .in(file("semanticdb-gradle-plugin")) + .enablePlugins(KotlinPlugin) .settings( name := "semanticdb-gradle", - buildInfoPackage := "com.sourcegraph.scip_java", publish / skip := true, - scalacOptions ++= Seq("-target:11", "-release", "11"), + kotlinVersion := V.kotlinVersion, + kotlincJvmTarget := "11", + // The Gradle init script puts only gradle-plugin.jar on the initscript + // classpath, so the assembled jar must contain kotlin-stdlib. + kotlinLib("stdlib"), + // Mark sbt-kotlin-plugin's auto-added kotlin-scripting-compiler-embeddable + // as Provided so it does NOT get bundled into our gradle-plugin.jar fat-jar. + // (kotlin-compiler-embeddable is already isolated to the KotlinInternal + // configuration and will not be picked up by sbt-assembly.) + kotlinRuntimeProvided := true, + Compile / javacOptions ++= Seq("--release", "11"), + Compile / sourceGenerators += gradlePluginBuildInfoGenerator.taskValue, libraryDependencies ++= List( "dev.gradleplugins" % "gradle-api" % V.gradle % Provided, - "dev.gradleplugins" % "gradle-test-kit" % V.gradle % Provided, - "org.jetbrains.kotlin" % "kotlin-gradle-plugin" % V.kotlinVersion % - Provided - ), - buildInfoKeys := - Seq[BuildInfoKey]( - version, - sbtVersion, - scalaVersion, - "javacModuleOptions" -> javacModuleOptions, - "semanticdbVersion" -> V.scalameta, - "scala213" -> V.scala213 + "dev.gradleplugins" % "gradle-test-kit" % V.gradle % Provided ) ) - .enablePlugins(BuildInfoPlugin) lazy val javacPlugin = project .in(file("semanticdb-javac")) @@ -535,6 +534,56 @@ def javacModuleOptions = List( "-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" ) +// Source-generator for the Gradle plugin's small build-info Java class. +// Replaces the previous sbt-buildinfo-generated Scala BuildInfo object so the +// gradle-plugin module can stay Kotlin-only (and the generated class is easy +// to consume from Kotlin). +def javaStringLiteral(value: String): String = { + val escaped = value.flatMap { + case '\\' => + "\\\\" + case '"' => + "\\\"" + case '\n' => + "\\n" + case '\r' => + "\\r" + case '\t' => + "\\t" + case c if c.isControl => + f"\\u${c.toInt}%04x" + case c => + c.toString + } + "\"" + escaped + "\"" +} + +lazy val gradlePluginBuildInfoGenerator = Def.task { + val out = (Compile / sourceManaged).value / "com" / "sourcegraph" / + "scip_java" / "GradlePluginBuildInfo.java" + IO.createDirectory(out.getParentFile) + val optionsLiteral = javacModuleOptions + .map(javaStringLiteral) + .mkString("Arrays.asList(", ", ", ")") + val versionLiteral = javaStringLiteral(version.value) + val contents = + s"""package com.sourcegraph.scip_java; + | + |import java.util.Arrays; + |import java.util.Collections; + |import java.util.List; + | + |public final class GradlePluginBuildInfo { + | private GradlePluginBuildInfo() {} + | public static final String version = $versionLiteral; + | public static final List javacModuleOptions = + | Collections.unmodifiableList($optionsLiteral); + |} + |""".stripMargin + IO.write(out, contents) + Seq(out) +} + lazy val unit = project .in(file("tests/unit")) .settings( diff --git a/semanticdb-gradle-plugin/src/main/kotlin/com/sourcegraph/gradle/semanticdb/SemanticdbGradlePlugin.kt b/semanticdb-gradle-plugin/src/main/kotlin/com/sourcegraph/gradle/semanticdb/SemanticdbGradlePlugin.kt new file mode 100644 index 00000000..650aac21 --- /dev/null +++ b/semanticdb-gradle-plugin/src/main/kotlin/com/sourcegraph/gradle/semanticdb/SemanticdbGradlePlugin.kt @@ -0,0 +1,396 @@ +package com.sourcegraph.gradle.semanticdb + +import com.sourcegraph.scip_java.GradlePluginBuildInfo +import java.io.File +import java.lang.reflect.Method +import java.nio.file.Files +import java.nio.file.Paths +import java.nio.file.StandardOpenOption +import org.gradle.api.Action +import org.gradle.api.DefaultTask +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.publish.PublishingExtension +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.api.tasks.SourceSetContainer +import org.gradle.api.tasks.TaskAction +import org.gradle.api.tasks.compile.JavaCompile + +class SemanticdbGradlePlugin : Plugin { + override fun apply(project: Project) { + project.afterEvaluate( + Action { p -> + p.repositories.add(p.repositories.mavenCentral()) + p.repositories.add(p.repositories.mavenLocal()) + + val extra = p.extensions.extraProperties + val extraProperties: Map = extra.properties + + val targetRoot: Any = + extraProperties["semanticdbTarget"] ?: p.buildDir + + val javacPluginVersion = GradlePluginBuildInfo.version + val javacPluginJar = extraProperties["javacPluginJar"] as String? + + val javacPluginDep: Any = + if (javacPluginJar != null) + p.files(javacPluginJar) + // We fall back to the javac plugin published to Maven if no jar + // is specified. The JAR would usually be provided by auto-indexer. + else + "com.sourcegraph:semanticdb-javac:$javacPluginVersion" + + val sourceRoot = p.rootDir + val tasks = p.tasks + + // List of compilation commands that we need to trigger to index + // all the sources in the project we care about. This list is + // built progressively as we check for java and kotlin plugins. + val triggers = mutableListOf() + + if (p.plugins.hasPlugin("java")) { + triggers += "compileJava" + triggers += "compileTestJava" + + val hasAnnotationPath = + try { + val apConfig = + p.configurations.getByName("annotationProcessor") + apConfig.isCanBeResolved && + apConfig.dependencies.size > 0 + } catch (_: Exception) { + false + } + + val compilerPluginAdded = + try { + p.dependencies.add("compileOnly", javacPluginDep) + + if (hasAnnotationPath) { + p.dependencies + .add("annotationProcessor", javacPluginDep) + } + + p.dependencies.add("testCompileOnly", javacPluginDep) + + true + } catch (exc: Exception) { + // The `compileOnly` configuration has likely already been + // resolved by another plugin or buildscript, so we can no + // longer add new dependencies to it. The project will be + // skipped (no SemanticDB output) and the post-build check + // in `GradleBuildTool` will surface a clearer error. + Logging.warn( + "scip-java: failed to attach SemanticDB compiler " + + "plugin to project '${p.name}' " + + "(${exc.javaClass.simpleName}: ${exc.message}). " + + "This subproject will not be indexed." + ) + false + } + + p.tasks + .withType(JavaCompile::class.java) + .configureEach( + Action { task -> + // Add --add-exports JVM args so our compiler plugin + // can access javac internals. Required on JDK 17+ + // (JEP 403), no-op on 11-16. + val forkOptions = task.options.forkOptions + val jvmArgs = + GradlePluginBuildInfo + .javacModuleOptions + .map { it.removePrefix("-J") } + val existing = forkOptions.jvmArgs + if (existing == null) { + forkOptions.jvmArgs = jvmArgs + } else { + existing.addAll(jvmArgs) + } + + task.options.isFork = true + task.options.isIncremental = false + + if (compilerPluginAdded) { + val args = task.options.compilerArgs + + // It's important we don't add the plugin + // configuration more than once, as javac + // considers that an error. + if (args.none { + it.startsWith("-Xplugin:semanticdb") + } + ) { + args.add( + // We add this to ensure that the sources + // are _always_ recompiled, so that Gradle + // doesn't cache any state. + // TODO: before this plugin is published to + // Maven Central, we will need to revert + // this change - as it can have detrimental + // effect on people's builds. + "-Xplugin:semanticdb " + + "-targetroot:$targetRoot " + + "-sourceroot:$sourceRoot " + + "-randomtimestamp=${System.nanoTime()}" + ) + } + } + } + ) + } + + val isKotlinMultiplatform = + p.plugins.any { it.javaClass.name.contains("KotlinMultiplatform") } + + if (p.plugins.hasPlugin("kotlin") || isKotlinMultiplatform) { + if (isKotlinMultiplatform) { + triggers += "compileKotlinJvm" + triggers += "compileTestKotlinJvm" + } else { + triggers += "compileKotlin" + triggers += "compileTestKotlin" + } + + p.tasks.configureEach( + Action { task -> + if (task.javaClass.simpleName.contains("KotlinCompile")) { + configureKotlinCompileTask( + task = task, + sourceRoot = sourceRoot, + targetRoot = targetRoot, + extraProperties = extraProperties + ) + } + } + ) + } + + tasks.create( + "scipCompileAll", + Action { task -> + triggers.forEach { trigger -> + task.dependsOn(tasks.getByName(trigger)) + } + } + ) + + tasks.create("scipPrintDependencies", WriteDependencies::class.java) + } + ) + } + + private fun configureKotlinCompileTask( + task: Task, + sourceRoot: File, + targetRoot: Any, + extraProperties: Map + ) { + // Do not reference org.jetbrains.kotlin.gradle.tasks.KotlinCompile here. + // + // This plugin is loaded from a Gradle init script with only the assembled + // gradle-plugin.jar on the initscript classpath. The target build may or + // may not have the Kotlin Gradle Plugin loaded by Gradle's plugin + // classloader. A direct symbolic reference to KotlinCompile can cause + // NoClassDefFoundError when this plugin class is loaded. + // + // Instead, reflect on the actual task instance Gradle gives us. This + // mirrors the structural-typing approach the previous Scala implementation + // used (see SemanticdbGradlePlugin.scala, lines 162-179). + val kotlinOptions = task.invokeNoArg("getKotlinOptions") + val getFreeCompilerArgs = kotlinOptions.findNoArgMethod("getFreeCompilerArgs") + val setFreeCompilerArgs = kotlinOptions.findOneArgMethod("setFreeCompilerArgs") + + @Suppress("UNCHECKED_CAST") + val existingArgs = getFreeCompilerArgs.invoke(kotlinOptions) as List + + // The semanticdb-kotlinc compiler plugin is built and shipped together + // with the scip-java CLI. The CLI's init script writes the absolute path + // of the embedded jar into the `semanticdbKotlincJar` extra property, so + // we no longer need to resolve a separately-published artifact at + // apply-time. + val semanticdbKotlinc = + (extraProperties["semanticdbKotlincJar"] as String?) + ?: throw IllegalStateException( + "semanticdbKotlincJar extra property must be set by the " + + "scip-java init script when indexing Kotlin sources" + ) + + val newArgs = ArrayList(existingArgs.size + 5) + newArgs.addAll(existingArgs) + newArgs.addAll( + listOf( + "-Xplugin=$semanticdbKotlinc", + "-P", + "plugin:semanticdb-kotlinc:sourceroot=$sourceRoot", + "-P", + "plugin:semanticdb-kotlinc:targetroot=$targetRoot" + ) + ) + + setFreeCompilerArgs.invoke(kotlinOptions, newArgs) + } + + private fun Any.invokeNoArg(name: String): Any = + findNoArgMethod(name).invoke(this) + + private fun Any.findNoArgMethod(name: String): Method = + javaClass.methods.firstOrNull { + it.name == name && it.parameterCount == 0 + } ?: throw NoSuchMethodException("${javaClass.name}.$name()") + + private fun Any.findOneArgMethod(name: String): Method = + javaClass.methods.firstOrNull { + it.name == name && it.parameterCount == 1 + } ?: throw NoSuchMethodException("${javaClass.name}.$name()") +} + +open class WriteDependencies : DefaultTask() { + @TaskAction + fun printResolvedDependencies() { + val depsOut = + project.extensions.extraProperties.properties["dependenciesOut"] + ?.toString() + ?.let { Paths.get(it) } + + depsOut?.parent?.let { Files.createDirectories(it) } + + val deps = mutableListOf() + val projectName = project.name + val projectPath = + project.path.replace(Regex("[^a-z0-9A-Z_-]"), "_") + val dependenciesPath = + depsOut?.let { path -> + val filename = path.fileName + if (filename.endsWith("dependencies.txt")) { + path.parent.resolve("$projectPath.$filename") + } else { + path + } + } + + // List the project itself as a dependency so that we can assign project + // name/version to symbols that are defined in this project. + // + // The code below is roughly equivalent to the following with Groovy: + // deps += "$publication.groupId $publication.artifactId $publication.version $sourceSets.main.output.classesDirectory" + + val crossRepoBanner = + """ + |This will not prevent a SCIP index from being created, but the symbols + |extracted from this project won't be available for cross-repository navigation, + |as this project doesn't define any Maven coordinates by which it can be referred back to. + |See here for more details: https://sourcegraph.github.io/scip-java/docs/manual-configuration.html#step-5-optional-enable-cross-repository-navigation + """ + + try { + val publications = + project.extensions + .findByType(PublishingExtension::class.java)!! + .publications + .withType(MavenPublication::class.java) + + publications.forEach { publication -> + try { + val main = + project.extensions + .getByType(SourceSetContainer::class.java) + .getByName("main") + + main.output + .classesDirs + .files + .map { it.absolutePath } + .sorted() + .take(1) + .forEach { classesDirectory -> + deps += + listOf( + publication.groupId, + publication.artifactId, + publication.version, + classesDirectory + ).joinToString("\t") + } + } catch (exception: Exception) { + val publicationName = + listOf( + publication.groupId, + publication.artifactId, + publication.version + ).joinToString(":") + + Logging.warn( + """ + |Failed to extract `main` source set from publication `$publicationName` in project `$projectName``. + $crossRepoBanner + |Here's the raw error message: + | "${exception.message}" + |Continuing without cross-repository support. + """.trimMargin().trim() + ) + } + } + } catch (exception: Exception) { + Logging.warn( + """ + |Failed to extract Maven publication from the project `$projectName`. + $crossRepoBanner + |Here's the raw error message (${exception.javaClass}): + | "${exception.message}" + |Continuing without cross-repository support. + """.trimMargin().trim() + ) + } + + project.configurations.forEach { conf -> + if (conf.isCanBeResolved) { + try { + val resolved = conf.resolvedConfiguration + resolved.resolvedArtifacts.forEach { artifact -> + val id = artifact.moduleVersion.id + deps += + listOf( + id.group, + id.name, + id.version, + artifact.file.absolutePath + ).joinToString("\t") + } + } catch (exc: Exception) { + println( + "Skipping configuration '${conf.name}' due to resolution failure: ${exc.message}" + ) + } + } + } + + val dependencies = deps.distinct() + + if (dependenciesPath == null) { + dependencies.forEach { println(it) } + } else { + Files.write( + dependenciesPath, + dependencies, + StandardOpenOption.APPEND, + StandardOpenOption.CREATE + ) + } + } +} + +private object Logging { + fun info(vararg msg: Any?) { + System.err.println( + "[INFO] [scip-java.gradle] ${msg.joinToString(" ")}" + ) + } + + fun warn(vararg msg: Any?) { + System.err.println( + "[WARNING] [scip-java.gradle] ${msg.joinToString(" ")}" + ) + } +} diff --git a/semanticdb-gradle-plugin/src/main/scala/SemanticdbGradlePlugin.scala b/semanticdb-gradle-plugin/src/main/scala/SemanticdbGradlePlugin.scala deleted file mode 100644 index b9c531e8..00000000 --- a/semanticdb-gradle-plugin/src/main/scala/SemanticdbGradlePlugin.scala +++ /dev/null @@ -1,397 +0,0 @@ -package com.sourcegraph.gradle.semanticdb - -import java.nio.file.Files -import java.nio.file.Paths -import java.{util => ju} - -import scala.jdk.CollectionConverters._ -import scala.util._ - -import com.sourcegraph.scip_java.BuildInfo -import org.gradle.api.DefaultTask -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.publish.PublishingExtension -import org.gradle.api.publish.maven.MavenPublication -import org.gradle.api.tasks.SourceSetContainer -import org.gradle.api.tasks.TaskAction -import org.gradle.api.tasks.compile.JavaCompile - -class SemanticdbGradlePlugin extends Plugin[Project] { - import Logging._ - - override def apply(project: Project): Unit = { - project.afterEvaluate { project => - project.getRepositories().add(project.getRepositories().mavenCentral()) - project.getRepositories().add(project.getRepositories().mavenLocal()) - - val extra = project.getExtensions().getExtraProperties() - val extraProperties = extra.getProperties().asScala - - val targetRoot = extra - .getProperties() - .asScala - .getOrElse("semanticdbTarget", project.getBuildDir()) - - val javacPluginVersion = BuildInfo.version - - val javacPluginJar = extraProperties - .get("javacPluginJar") - .map(_.asInstanceOf[String]) - - val javacPluginDep = javacPluginJar - .map[Object](jar => project.files(jar)) - // we fallback to javac plugin published to maven if there is no jar specified - // the JAR would usually be provided by auto-indexer - .getOrElse(s"com.sourcegraph:semanticdb-javac:${javacPluginVersion}") - - val sourceRoot = project.getRootDir() - - val tasks = project.getTasks() - - // List of compilation commands that we will need to trigger - // to index all the sources in the project we care about. - // This list is built progressively as we check for java and kotlin - // plugins - val triggers = List.newBuilder[String] - - if (project.getPlugins().hasPlugin("java")) { - - triggers += "compileJava" - triggers += "compileTestJava" - - val hasAnnotationPath = Try( - project.getConfigurations().getByName("annotationProcessor") - ).map(apConfig => - if (apConfig.isCanBeResolved()) { - apConfig.getDependencies().size() > 0 - } else - false - ) - .toOption - .contains(true) - - val compilerPluginAdded = - try { - project.getDependencies().add("compileOnly", javacPluginDep) - - if (hasAnnotationPath) { - project - .getDependencies() - .add("annotationProcessor", javacPluginDep) - } - - project.getDependencies().add("testCompileOnly", javacPluginDep) - - true - } catch { - case exc: Exception => - // The `compileOnly` configuration has likely already been - // resolved by another plugin or buildscript, so we can no longer - // add new dependencies to it. The project will be skipped (no - // SemanticDB output) and the post-build check in - // `GradleBuildTool` will surface a clearer error. - warn( - s"scip-java: failed to attach SemanticDB compiler plugin to project '${project - .getName()}' (${exc.getClass().getSimpleName()}: ${exc - .getMessage()}). This subproject will not be indexed." - ) - false - } - - project - .getTasks() - .withType(classOf[JavaCompile]) - .configureEach { task => - // Add --add-exports JVM args so our compiler plugin can access - // javac internals. Required on JDK 17+ (JEP 403), no-op on 11-16. - val forkOptions = task.getOptions().getForkOptions() - val jvmArgs = - BuildInfo.javacModuleOptions.map(_.stripPrefix("-J")).asJava - forkOptions.getJvmArgs() match { - case null => - forkOptions.setJvmArgs(jvmArgs) - case _ => - forkOptions.getJvmArgs().addAll(jvmArgs) - } - - task.getOptions().setFork(true) - task.getOptions().setIncremental(false) - - if (compilerPluginAdded) { - val args = task.getOptions().getCompilerArgs() - - // It's important we don't add the plugin configuration more than - // once, as javac considers that an error - if (!args.asScala.exists(_.startsWith("-Xplugin:semanticdb"))) { - args.addAll( - List( - // We add this to ensure that the sources are _always_ - // recompiled, so that Gradle doesn't cache any state - // TODO: before this plugin is published to Maven Central, - // we will need to revert this change - as it can have detrimental - // effect on people's builds - s"-Xplugin:semanticdb -targetroot:$targetRoot -sourceroot:$sourceRoot -randomtimestamp=${System - .nanoTime()}" - ).asJava - ) - } - } - } - } - - val isKotlinMultiplatform = project - .getPlugins() - .asScala - .exists(_.getClass().getName().contains("KotlinMultiplatform")) - - if (project.getPlugins().hasPlugin("kotlin") || isKotlinMultiplatform) { - if (isKotlinMultiplatform) { - triggers += "compileKotlinJvm" - triggers += "compileTestKotlinJvm" - } else { - triggers += "compileKotlin" - triggers += "compileTestKotlin" - } - - project - .getTasks - .configureEach { task => - if (task.getClass().getSimpleName().contains("KotlinCompile")) { - - // I we actually refer to KotlinCompile at _any_ point here, then - // plugin fails with NoClassDefFoundError - because the plugin - // classpath is murky - // - // We also don't want to bundle kotlin plugin with this one as it - // can cause all sorts of troubles). - // - // Instead, we commit the sins of reflection for our limited - // needs. - val compilerArgs = task - .asInstanceOf[{ - def getKotlinOptions(): { - def getFreeCompilerArgs(): ju.List[String] - def setFreeCompilerArgs(args: ju.List[String]): Unit - // def getLanguageVersion(): Any - } - }] - .getKotlinOptions() - - // The semanticdb-kotlinc compiler plugin is now built and shipped - // together with the scip-java CLI. The CLI's init script writes - // the absolute path of the embedded jar into the - // `semanticdbKotlincJar` extra property so we no longer need to - // resolve a separately-published artifact at apply-time. - val semanticdbKotlinc = extraProperties - .get("semanticdbKotlincJar") - .map(_.asInstanceOf[String]) - .getOrElse { - throw new IllegalStateException( - "semanticdbKotlincJar extra property must be set by the " + - "scip-java init script when indexing Kotlin sources" - ) - } - - val newArgs = - new ju.ArrayList[String]( - compilerArgs.getFreeCompilerArgs().size + 5 - ) - newArgs.addAll(compilerArgs.getFreeCompilerArgs()) - newArgs.addAll( - List( - "-Xplugin=" + semanticdbKotlinc, - "-P", - s"plugin:semanticdb-kotlinc:sourceroot=$sourceRoot", - "-P", - s"plugin:semanticdb-kotlinc:targetroot=$targetRoot" - ).asJava - ) - - compilerArgs.setFreeCompilerArgs(newArgs) - } - } - } - - tasks.create( - "scipCompileAll", - { task => - triggers - .result() - .foldLeft(task) { case (tsk, trig) => - tsk.dependsOn(tasks.getByName(trig)) - } - - } - ) - - tasks.create("scipPrintDependencies", classOf[WriteDependencies]) - - } - - } - -} - -class WriteDependencies extends DefaultTask { - import Logging._ - - @TaskAction - def printResolvedDependencies(): Unit = { - - val depsOut = Option( - getProject().getExtensions().getExtraProperties().get("dependenciesOut") - ).map(_.toString).map(Paths.get(_)) - - depsOut.foreach(path => - java.nio.file.Files.createDirectories(path.getParent()) - ) - - val deps = List.newBuilder[String] - val project = getProject() - val projectName = project.getName() - val projectPath = project.getPath().replaceAll("[^a-z0-9A-Z_-]", "_") - val dependenciesPath = depsOut.map { path => - val filename = path.getFileName() - if (filename.endsWith("dependencies.txt")) { - val last = projectPath + "." + path.getFileName().toString() - path.getParent().resolve(last) - } else - path - } - - // List the project itself as a dependency so that we can assign project name/version to symbols that are defined in this project. - // The code below is roughly equivalent to the following with Groovy: - // deps += "$publication.groupId $publication.artifactId $publication.version $sourceSets.main.output.classesDirectory" - - val crossRepoBanner = - """ - |This will not prevent a SCIP index from being created, but the symbols - |extracted from this project won't be available for cross-repository navigation, - |as this project doesn't define any Maven coordinates by which it can be referred back to. - |See here for more details: https://sourcegraph.github.io/scip-java/docs/manual-configuration.html#step-5-optional-enable-cross-repository-navigation - """ - - Try( - project - .getExtensions() - .findByType(classOf[PublishingExtension]) - .getPublications() - .withType(classOf[MavenPublication]) - .asScala - ) match { - case Failure(exception) => - warn( - s""" - |Failed to extract Maven publication from the project `$projectName`. - $crossRepoBanner - |Here's the raw error message (${exception.getClass()}): - | "${exception.getMessage()}" - |Continuing without cross-repository support. - """.stripMargin.trim() - ) - - case Success(publications) => - publications.foreach { publication => - Try( - project - .getExtensions() - .getByType(classOf[SourceSetContainer]) - .getByName("main") - ) match { - case Failure(exception) => - val publicationName = List( - publication.getGroupId(), - publication.getArtifactId(), - publication.getVersion() - ).mkString(":") - - warn( - s""" - |Failed to extract `main` source set from publication `${publicationName}` in project `$projectName``. - $crossRepoBanner - |Here's the raw error message: - | "${exception.getMessage()}" - |Continuing without cross-repository support. - """.stripMargin.trim() - ) - - case Success(value) => - value - .getOutput() - .getClassesDirs() - .getFiles() - .asScala - .toList - .map(_.getAbsolutePath()) - .sorted - .take(1) - .foreach { classesDirectory => - deps += - List( - publication.getGroupId(), - publication.getArtifactId(), - publication.getVersion(), - classesDirectory - ).mkString("\t") - } - - } - } - } - - project - .getConfigurations() - .forEach { conf => - if (conf.isCanBeResolved()) { - try { - val resolved = conf.getResolvedConfiguration() - resolved - .getResolvedArtifacts() - .forEach { artif => - deps += - List( - artif.getModuleVersion().getId().getGroup(), - artif.getModuleVersion().getId().getName(), - artif.getModuleVersion().getId().getVersion(), - artif.getFile().getAbsolutePath() - ).mkString("\t") - - } - } catch { - case exc: Exception => - println( - s"Skipping configuration '${conf - .getName()}' due to resolution failure: ${exc.getMessage()}" - ) - } - - } - } - - val dependencies = deps.result().distinct - - dependenciesPath match { - case None => - dependencies.foreach(println) - case Some(path) => - Files.write( - path, - dependencies.asJava, - java.nio.file.StandardOpenOption.APPEND, - java.nio.file.StandardOpenOption.CREATE - ) - } - } -} - -private object Logging { - def info(msg: Any*) = System - .err - .println(s"[INFO] [scip-java.gradle] ${msg.mkString(" ")}") - - def warn(msg: Any*) = System - .err - .println(s"[WARNING] [scip-java.gradle] ${msg.mkString(" ")}") - -}