Skip to content

Commit f521043

Browse files
authored
Merge pull request #173 from olafurpg/gradle-7
Add support for the Gradle Playframework plugin.
2 parents fb98dd4 + eea306f commit f521043

File tree

13 files changed

+218
-21
lines changed

13 files changed

+218
-21
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ abstract class BuildTool(val name: String, index: IndexCommand) {
1616

1717
def indexJdk(): Boolean = true
1818

19+
final def sourceroot: Path = index.workingDirectory
1920
final def targetroot: Path =
2021
AbsolutePath
2122
.of(index.targetroot.getOrElse(defaultTargetroot), index.workingDirectory)

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

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class GradleBuildTool(index: IndexCommand) extends BuildTool("Gradle", index) {
7575
buildCommand ++= index.finalBuildCommand(List("clean", "compileTestJava"))
7676
buildCommand += lsifJavaDependencies
7777

78-
val result = index.process(buildCommand.toList: _*)
78+
val result = index.process(buildCommand)
7979
printDebugLogs(toolchains.tmp)
8080
Embedded
8181
.reportUnexpectedJavacErrors(index.app.reporter, toolchains.tmp)
@@ -103,6 +103,9 @@ class GradleBuildTool(index: IndexCommand) extends BuildTool("Gradle", index) {
103103
case None =>
104104
""
105105
}
106+
107+
val agentpath = Embedded.agentJar(tmp)
108+
val pluginpath = Embedded.semanticdbJar(tmp)
106109
val dependenciesPath = targetroot.resolve("dependencies.txt")
107110
Files.deleteIfExists(dependenciesPath)
108111
val script =
@@ -111,16 +114,36 @@ class GradleBuildTool(index: IndexCommand) extends BuildTool("Gradle", index) {
111114
| boolean isJavaEnabled = project.plugins.any {
112115
| it.getClass().getName().endsWith("org.gradle.api.plugins.JavaPlugin")
113116
| }
114-
| if (!isJavaEnabled) return
115-
| tasks.withType(JavaCompile) {
116-
| options.fork = true
117-
| options.incremental = false
118-
| $executable
117+
| boolean isScalaEnabled = project.plugins.any {
118+
| it.getClass().getName().endsWith("org.gradle.api.plugins.scala.ScalaPlugin")
119+
| }
120+
| if (isJavaEnabled) {
121+
| tasks.withType(JavaCompile) {
122+
| options.fork = true
123+
| options.incremental = false
124+
| $executable
125+
| }
126+
| }
127+
| if (isScalaEnabled) {
128+
| // The Scala plugin runs Zinc, an incremental compiler, in a separate daemon process.
129+
| // Zinc invokes the Java compiler directly to compile mixed Java/Scala projects
130+
| // instead of respecting the `JavaCompile` fork options from the Gradle Java plugin.
131+
| // By enabling the SemanticDB Java agent on the Zinc daemon process, we manage
132+
| // to configure Zinc to use the semanticdb-javac compiler plugin for Java compilation.
133+
| tasks.withType(ScalaCompile) {
134+
| scalaCompileOptions.forkOptions.with {
135+
| jvmArgs << '-javaagent:$agentpath'
136+
| jvmArgs << '-Dsemanticdb.pluginpath=$pluginpath'
137+
| jvmArgs << '-Dsemanticdb.sourceroot=$sourceroot'
138+
| jvmArgs << '-Dsemanticdb.targetroot=$targetroot'
139+
| }
140+
| }
119141
| }
120142
| }
121143
| task $lsifJavaDependencies {
122144
| def depsOut = java.nio.file.Paths.get('$dependenciesPath')
123145
| doLast {
146+
| java.nio.file.Files.createDirectories(depsOut.getParent())
124147
| tasks.withType(JavaCompile) {
125148
| try {
126149
| configurations.each { config ->

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@ object GradleJavaToolchains {
9292
|}
9393
|""".stripMargin
9494
Files.write(scriptPath, script.getBytes(StandardCharsets.UTF_8))
95-
index.process(gradleCommand, "--init-script", scriptPath.toString, taskName)
95+
index.process(
96+
List(gradleCommand, "--init-script", scriptPath.toString, taskName)
97+
)
9698
val toolchains: List[GradleJavaCompiler] =
9799
if (Files.isRegularFile(toolchainsPath)) {
98100
Files

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class MavenBuildTool(index: IndexCommand) extends BuildTool("Maven", index) {
5353
)
5454
)
5555

56-
val exit = index.process(buildCommand.toList: _*)
56+
val exit = index.process(buildCommand)
5757
Embedded
5858
.reportUnexpectedJavacErrors(index.app.reporter, tmp)
5959
.getOrElse(exit)

lsif-java/src/main/scala/com/sourcegraph/lsif_java/commands/IndexCommand.scala

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,19 @@ case class IndexCommand(
6161
app: Application = Application.default
6262
) extends Command {
6363

64-
def process(shellable: String*): CommandResult = {
65-
app.info(shellable.mkString(" "))
64+
def process(
65+
shellable: Shellable,
66+
env: Map[String, String] = Map.empty
67+
): CommandResult = {
68+
app.info(shellable.value.mkString(" "))
6669
app
67-
.process(Shellable(shellable))
70+
.process(shellable)
6871
.call(
6972
check = false,
7073
stdout = Inherit,
7174
stderr = Inherit,
72-
cwd = workingDirectory
75+
cwd = workingDirectory,
76+
env = env
7377
)
7478
}
7579

lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifSemanticdb.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,21 @@ public static void run(LsifSemanticdbOptions options) throws IOException {
3737

3838
private void run() throws IOException {
3939
PackageTable packages = new PackageTable(options, writer);
40-
writer.emitMetaData();
41-
int projectId = writer.emitProject(options.language);
42-
4340
List<Path> files = SemanticdbWalker.findSemanticdbFiles(options);
4441
if (options.reporter.hasErrors()) return;
42+
if (files.isEmpty()) {
43+
options.reporter.error(
44+
"No SemanticDB files found. "
45+
+ "This typically means that `lsif-java` is unable to automatically "
46+
+ "index this codebase. If you are using Gradle or Maven, please report an issue to "
47+
+ "https://github.com/sourcegraph/lsif-java and include steps to reproduce. "
48+
+ "If you are using a different build tool, make sure that you have followed all "
49+
+ "of the steps from https://sourcegraph.github.io/lsif-java/docs/manual-configuration.html");
50+
return;
51+
}
4552
options.reporter.startProcessing(files.size());
53+
writer.emitMetaData();
54+
int projectId = writer.emitProject(options.language);
4655

4756
Set<String> isExportedSymbol = exportSymbols(files);
4857
List<Integer> documentIds =

lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifSemanticdbReporter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
public abstract class LsifSemanticdbReporter {
1010
public void error(Throwable e) {}
1111

12+
public void error(String message) {
13+
error(new RuntimeException(message));
14+
}
15+
1216
public void startProcessing(int taskSize) {}
1317

1418
public void processedOneItem() {}

semanticdb-agent/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbAgent.java

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55

66
import java.io.File;
77
import java.io.IOException;
8+
import java.io.OutputStream;
89
import java.io.PrintStream;
910
import java.lang.instrument.Instrumentation;
1011
import java.nio.charset.StandardCharsets;
1112
import java.nio.file.Files;
13+
import java.nio.file.Path;
1214
import java.nio.file.Paths;
1315
import java.nio.file.StandardOpenOption;
1416
import java.util.ArrayList;
@@ -21,18 +23,77 @@
2123
public class SemanticdbAgent {
2224

2325
public static void premain(String agentArgs, Instrumentation inst) {
26+
// NOTE(olafur): Uncoment below if you want see all the loaded classes.
27+
// PrintStream logger = newLogger();
28+
// inst.addTransformer(
29+
// new ClassFileTransformer() {
30+
// @Override
31+
// public byte[] transform(
32+
// ClassLoader loader,
33+
// String className,
34+
// Class<?> classBeingRedefined,
35+
// ProtectionDomain protectionDomain,
36+
// byte[] classfileBuffer) {
37+
// logger.println(className);
38+
// return classfileBuffer;
39+
// }
40+
// });
41+
new AgentBuilder.Default()
42+
.disableClassFormatChanges()
43+
.type(
44+
named("org.gradle.api.internal.tasks.compile.DefaultJvmLanguageCompileSpec")
45+
.or(named("tests.GradleDefaultJvmLanguageCompileSpec")))
46+
.transform(
47+
new AgentBuilder.Transformer.ForAdvice()
48+
.advice(
49+
named("getCompileClasspath"),
50+
DefaultJvmLanguageCompileSpecAdvice.class.getName()))
51+
.installOn(inst);
2452
new AgentBuilder.Default()
2553
.type(
2654
named("org.gradle.api.internal.tasks.compile.JavaCompilerArgumentsBuilder")
27-
.or(named("tests.GradleOptionsBuilder")))
55+
.or(named("tests.GradleJavaCompilerArgumentsBuilder")))
2856
.transform(
2957
new AgentBuilder.Transformer.ForAdvice()
30-
.advice(named("build"), GradleAdvice.class.getName()))
58+
.advice(named("build"), JavaCompilerArgumentsBuilderAdvice.class.getName()))
3159
.installOn(inst);
3260
}
3361

62+
private static PrintStream newLogger() {
63+
Path path = Paths.get(System.getProperty("user.home"), ".lsif-java", "logs.txt");
64+
try {
65+
Files.createDirectories(path.getParent());
66+
OutputStream fos =
67+
Files.newOutputStream(
68+
path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
69+
return new PrintStream(fos);
70+
} catch (IOException e) {
71+
return new PrintStream(
72+
new OutputStream() {
73+
@Override
74+
public void write(int b) {}
75+
});
76+
}
77+
}
78+
79+
@SuppressWarnings("all")
80+
public static class DefaultJvmLanguageCompileSpecAdvice {
81+
@Advice.OnMethodExit
82+
public static void getClasspath(
83+
@Advice.Return(readOnly = false, typing = DYNAMIC) List<File> classpath) {
84+
String PLUGINPATH = System.getProperty("semanticdb.pluginpath");
85+
if (PLUGINPATH == null) throw new NoSuchElementException("-Dsemanticdb.pluginpath");
86+
File semanticdbJar = new File(PLUGINPATH);
87+
if (!classpath.contains(semanticdbJar)) {
88+
List<File> newClasspath = new ArrayList<>(classpath);
89+
newClasspath.add(semanticdbJar);
90+
classpath = newClasspath;
91+
}
92+
}
93+
}
94+
3495
@SuppressWarnings("all")
35-
public static class GradleAdvice {
96+
public static class JavaCompilerArgumentsBuilderAdvice {
3697

3798
/**
3899
* The bytecode of this method gets injected at the end of the following method in Gradle:
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package tests
2+
3+
import java.io.File
4+
import java.util
5+
6+
import scala.jdk.CollectionConverters._
7+
8+
class GradleDefaultJvmLanguageCompileSpec(base: List[String]) {
9+
def getCompileClasspath: util.List[File] = {
10+
base.map(new File(_)).asJava
11+
}
12+
}

tests/buildTools/src/main/scala/tests/GradleOptionsBuilder.scala renamed to tests/buildTools/src/main/scala/tests/GradleJavaCompilerArgumentsBuilder.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ package tests
22

33
import scala.jdk.CollectionConverters._
44

5-
class GradleOptionsBuilder(base: List[String]) {
5+
class GradleJavaCompilerArgumentsBuilder(base: List[String]) {
66
def build(): java.util.List[String] = base.asJava
77
}

0 commit comments

Comments
 (0)