Skip to content

Commit 2fed737

Browse files
authored
Merge pull request #316 from olafurpg/scala-gradle
2 parents b745d90 + b226a3e commit 2fed737

File tree

6 files changed

+126
-19
lines changed

6 files changed

+126
-19
lines changed

build.sbt

+6
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@ lazy val cli = project
147147
version,
148148
sbtVersion,
149149
scalaVersion,
150+
"semanticdbScalacVersions" ->
151+
com
152+
.sourcegraph
153+
.sbtsourcegraph
154+
.Versions
155+
.cachedSemanticdbVersionsByScalaVersion,
150156
"sbtSourcegraphVersion" ->
151157
com.sourcegraph.sbtsourcegraph.BuildInfo.version,
152158
"semanticdbVersion" -> V.scalameta,

docs/getting-started.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,11 @@ com.sourcegraph.lsif_java.LsifJava.printHelp(Console.out)
134134

135135
## Supported programming languages
136136

137-
| Programming language | Gradle | Maven | sbt | Tracking issue |
138-
| -------------------- | ------ | ----- | --- | --------------------------------------------------------------------------------------------------------------------------- |
139-
| Java |||| |
140-
| Scala | ||| [Maven](https://github.com/sourcegraph/lsif-java/issues/301), [Gradle](https://github.com/sourcegraph/lsif-java/issues/302) |
141-
| Kotlin |||| [#302](https://github.com/sourcegraph/lsif-java/issues/302) |
137+
| Programming language | Gradle | Maven | sbt | Tracking issue |
138+
| -------------------- | ------ | ----- | --- | ----------------------------------------------------------- |
139+
| Java |||| |
140+
| Scala | ||| [#302](https://github.com/sourcegraph/lsif-java/issues/302) |
141+
| Kotlin |||| [#304](https://github.com/sourcegraph/lsif-java/issues/304) |
142142

143143
### Java
144144

@@ -216,7 +216,7 @@ projects. However, the following Gradle integrations are not yet supported:
216216
| ----------- | --------- | -------------------------------------------------------------------------------- |
217217
| Android || [sourcegraph/lsif-java#304](https://github.com/sourcegraph/lsif-java/issues/304) |
218218
| Kotlin || [sourcegraph/lsif-java#177](https://github.com/sourcegraph/lsif-java/issues/177) |
219-
| Scala | | [sourcegraph/lsif-java#302](https://github.com/sourcegraph/lsif-java/issues/302) |
219+
| Scala | | |
220220

221221
### Maven
222222

lsif-java/src/main/scala/com/sourcegraph/lsif_java/buildtools/GradleBuildTool.scala

+68-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import java.nio.file._
66
import scala.collection.mutable.ListBuffer
77
import scala.util.Properties
88

9+
import com.sourcegraph.io.DeleteVisitor
10+
import com.sourcegraph.lsif_java.BuildInfo
911
import com.sourcegraph.lsif_java.Embedded
1012
import com.sourcegraph.lsif_java.commands.IndexCommand
1113
import os.CommandResult
@@ -78,9 +80,20 @@ class GradleBuildTool(index: IndexCommand) extends BuildTool("Gradle", index) {
7880
buildCommand +=
7981
s"-Porg.gradle.java.installations.paths=${toolchains.paths()}"
8082
}
81-
buildCommand ++= index.finalBuildCommand(List("clean", "compileTestJava"))
83+
buildCommand ++=
84+
index.finalBuildCommand(
85+
List[Option[String]](
86+
Some("clean"),
87+
Some("compileTestJava"),
88+
if (toolchains.isScalaEnabled)
89+
Some("compileTestScala")
90+
else
91+
None
92+
).flatten
93+
)
8294
buildCommand += lsifJavaDependencies
8395

96+
Files.walkFileTree(targetroot, new DeleteVisitor())
8497
val result = index.process(buildCommand, env = Map("TERM" -> "dumb"))
8598
printDebugLogs(toolchains.tmp)
8699
Embedded
@@ -112,6 +125,11 @@ class GradleBuildTool(index: IndexCommand) extends BuildTool("Gradle", index) {
112125

113126
val agentpath = Embedded.agentJar(tmp)
114127
val pluginpath = Embedded.semanticdbJar(tmp)
128+
def handleExceptionGroovySyntax(): String =
129+
if (index.verbose)
130+
"e.printStackTrace()"
131+
else
132+
""
115133
val dependenciesPath = targetroot.resolve("dependencies.txt")
116134
Files.deleteIfExists(dependenciesPath)
117135
val script =
@@ -137,6 +155,22 @@ class GradleBuildTool(index: IndexCommand) extends BuildTool("Gradle", index) {
137155
| // By enabling the SemanticDB Java agent on the Zinc daemon process, we manage
138156
| // to configure Zinc to use the semanticdb-javac compiler plugin for Java compilation.
139157
| tasks.withType(ScalaCompile) {
158+
|
159+
| if (scalaCompileOptions.additionalParameters == null) scalaCompileOptions.additionalParameters = []
160+
| try {
161+
| def scalaVersion = lsifJavaScalaVersion(project, configurations)
162+
| def semanticdbVersion = lsifJavaSemanticdbScalacVersions(scalaVersion)
163+
| def semanticdbScalacDependency ="org.scalameta:semanticdb-scalac_$$scalaVersion:$$semanticdbVersion"
164+
| def semanticdbScalac = project.configurations.detachedConfiguration(dependencies.create(semanticdbScalacDependency)).files[0]
165+
| scalaCompileOptions.additionalParameters << '-Xplugin:' + semanticdbScalac
166+
| scalaCompileOptions.additionalParameters << '-P:semanticdb:sourceroot:$sourceroot'
167+
| scalaCompileOptions.additionalParameters << '-P:semanticdb:targetroot:$targetroot'
168+
| scalaCompileOptions.additionalParameters << '-P:semanticdb:exclude:(src/play/twirl|src/play/routes)' // Ignore autogenerated Playframework files
169+
| scalaCompileOptions.additionalParameters << '-P:semanticdb:failures:warning'
170+
| scalaCompileOptions.additionalParameters << '-Xplugin-require:semanticdb'
171+
| } catch (Exception e) {
172+
| ${handleExceptionGroovySyntax()}
173+
| }
140174
| scalaCompileOptions.forkOptions.with {
141175
| jvmArgs << '-javaagent:$agentpath'
142176
| jvmArgs << '-Dsemanticdb.pluginpath=$pluginpath'
@@ -180,11 +214,43 @@ class GradleBuildTool(index: IndexCommand) extends BuildTool("Gradle", index) {
180214
| }
181215
| }
182216
|}
183-
""".stripMargin
217+
|def lsifJavaSemanticdbScalacVersions(scalaVersion) {
218+
| ${semanticdbScalacGroovySyntax()}[scalaVersion]
219+
|}
220+
|def lsifJavaScalaVersion(project, configurations) {
221+
| for (config in configurations) {
222+
| if (config.name == "zinc") continue
223+
| if (config.canBeResolved) {
224+
| def artifacts = config.incoming.artifactView { view ->
225+
| view.lenient = true
226+
| }.artifacts
227+
| for (artifact in artifacts) {
228+
| def id = artifact.id.componentIdentifier
229+
| if (id instanceof org.gradle.api.artifacts.component.ModuleComponentIdentifier
230+
| && id.group == "org.scala-lang"
231+
| && id.module == "scala-library") {
232+
| return id.version
233+
| }
234+
| }
235+
| }
236+
| }
237+
| return null
238+
|}
239+
| """.stripMargin
184240
Files.write(
185241
tmp.resolve("init-script.gradle"),
186242
script.getBytes(StandardCharsets.UTF_8)
187243
)
188244
}
189245

246+
def semanticdbScalacGroovySyntax(): String =
247+
BuildInfo
248+
.semanticdbScalacVersions
249+
.removed(
250+
"2.12.3"
251+
) // Not supported because the last semanticdb-scalac_2.12.3 release doesn't support the option -P:semanticdb:targetroot:PATH.
252+
.map { case (key, value) =>
253+
s"'$key':'$value'"
254+
}.mkString("[", ", ", "]")
255+
190256
}

lsif-java/src/main/scala/com/sourcegraph/lsif_java/buildtools/GradleJavaToolchains.scala

+15-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ case class GradleJavaToolchains(
1414
tool: GradleBuildTool,
1515
index: IndexCommand,
1616
gradleVersion: Option[String],
17+
isScalaEnabled: Boolean,
1718
gradleCommand: String,
1819
tmp: Path
1920
) {
@@ -55,6 +56,7 @@ object GradleJavaToolchains {
5556
): GradleJavaToolchains = {
5657
val scriptPath = tmp.resolve("java-toolchains.gradle")
5758
val toolchainsPath = tmp.resolve("java-toolchains.txt")
59+
val scalaEnabledPath = tmp.resolve("scala-enabled.txt")
5860
val gradleVersionPath = tmp.resolve("gradle-version.txt")
5961
val taskName = "lsifDetectJavaToolchains"
6062
val script =
@@ -70,7 +72,7 @@ object GradleJavaToolchains {
7072
|}
7173
|allprojects {
7274
| task $taskName {
73-
| def out = java.nio.file.Paths.get('$toolchainsPath')
75+
| def toolchainsOut = java.nio.file.Paths.get('$toolchainsPath')
7476
| doLast {
7577
| tasks.withType(JavaCompile) {
7678
| try {
@@ -79,14 +81,24 @@ object GradleJavaToolchains {
7981
| def version = javaCompiler.get().getMetadata().getLanguageVersion().asInt()
8082
| def line = "$$version $$path"
8183
| java.nio.file.Files.write(
82-
| out,
84+
| toolchainsOut,
8385
| [line],
8486
| java.nio.file.StandardOpenOption.APPEND,
8587
| java.nio.file.StandardOpenOption.CREATE)
8688
| } catch (Exception e) {
8789
| // Ignore errors.
8890
| }
8991
| }
92+
| boolean isScalaEnabled = project.plugins.any {
93+
| it.getClass().getName().endsWith("org.gradle.api.plugins.scala.ScalaPlugin")
94+
| }
95+
| if (isScalaEnabled) {
96+
| java.nio.file.Files.write(
97+
| java.nio.file.Paths.get('$scalaEnabledPath'),
98+
| ["true"],
99+
| java.nio.file.StandardOpenOption.APPEND,
100+
| java.nio.file.StandardOpenOption.CREATE)
101+
| }
90102
| }
91103
| }
92104
|}
@@ -119,6 +131,7 @@ object GradleJavaToolchains {
119131
tool,
120132
index,
121133
gradleVersion = gradleVersion,
134+
isScalaEnabled = Files.isRegularFile(scalaEnabledPath),
122135
gradleCommand = gradleCommand,
123136
tmp = tmp
124137
)

semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbTaskListener.java

+2-9
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ private void writeSemanticdb(Path output, Semanticdb.TextDocument textDocument)
6868
try {
6969
byte[] bytes =
7070
Semanticdb.TextDocuments.newBuilder().addDocuments(textDocument).build().toByteArray();
71+
Files.createDirectories(output.getParent());
7172
Files.write(output, bytes);
7273
} catch (IOException e) {
7374
reporter.exception(e);
@@ -101,15 +102,7 @@ private Result<Path, String> semanticdbOutputPath(SemanticdbJavacOptions options
101102
.resolve("semanticdb")
102103
.resolve(relativePath)
103104
.resolveSibling(filename);
104-
try {
105-
Files.createDirectories(semanticdbOutputPath.getParent());
106-
return Result.ok(semanticdbOutputPath);
107-
} catch (IOException exception) {
108-
return Result.error(
109-
String.format(
110-
"failed to create parent directory for '%s'. Error message: %s",
111-
semanticdbOutputPath, exception.getMessage()));
112-
}
105+
return Result.ok(semanticdbOutputPath);
113106
} else {
114107
return Result.error(
115108
String.format(

tests/buildTools/src/test/scala/tests/GradleBuildToolSuite.scala

+29
Original file line numberDiff line numberDiff line change
@@ -233,4 +233,33 @@ class GradleBuildToolSuite extends BaseBuildToolSuite {
233233
2,
234234
initCommand = gradleVersion("6.8.3")
235235
)
236+
237+
checkBuild(
238+
"scala",
239+
"""|/build.gradle
240+
|plugins {
241+
| id 'scala'
242+
|}
243+
|repositories {
244+
| mavenCentral()
245+
|}
246+
|dependencies {
247+
| implementation 'org.scala-lang:scala-library:2.12.12'
248+
|}
249+
|/src/main/java/foo/JExample.java
250+
|package foo;
251+
|public class JExample {}
252+
|/src/main/scala/foo/Example.scala
253+
|package foo
254+
|object Example {}
255+
|/src/test/java/foo/JExampleSuite.java
256+
|package foo;
257+
|public class JExampleSuite {}
258+
|/src/test/scala/foo/ExampleSuite.scala
259+
|package foo
260+
|class ExampleSuite {}
261+
|""".stripMargin,
262+
4
263+
)
264+
236265
}

0 commit comments

Comments
 (0)