Skip to content

Commit

Permalink
Handle older versions of Gradle
Browse files Browse the repository at this point in the history
  • Loading branch information
Arthur McGibbon committed Jun 14, 2024
1 parent 7550bfb commit 013a0b4
Show file tree
Hide file tree
Showing 9 changed files with 526 additions and 390 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,28 @@
package com.microsoft.java.bs.gradle.plugin;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import com.microsoft.java.bs.gradle.model.GradleModuleDependency;
import com.microsoft.java.bs.gradle.model.ScalaExtension;
import com.microsoft.java.bs.gradle.model.SupportedLanguage;
import com.microsoft.java.bs.gradle.model.impl.DefaultScalaExtension;
import org.gradle.api.Project;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.SourceDirectorySet;
import org.gradle.api.internal.tasks.scala.MinimalScalaCompileOptions;
import org.gradle.api.internal.tasks.scala.ScalaCompileSpec;
import org.gradle.api.internal.tasks.scala.ZincScalaCompilerArgumentsGenerator;
import org.gradle.api.tasks.ScalaSourceDirectorySet;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.scala.ScalaCompile;
import org.gradle.api.tasks.scala.ScalaCompileOptions;
import org.gradle.util.GradleVersion;

import com.microsoft.java.bs.gradle.model.SupportedLanguages;

Expand All @@ -44,9 +46,20 @@ public SupportedLanguage<ScalaExtension> getLanguage() {

@Override
public Collection<File> getSourceFoldersFor(Project project, SourceSet sourceSet) {
SourceDirectorySet sourceDirectorySet = sourceSet.getExtensions()
.findByType(ScalaSourceDirectorySet.class);
return sourceDirectorySet == null ? Collections.emptySet() : sourceDirectorySet.getSrcDirs();
if (GradleVersion.current().compareTo(GradleVersion.version("7.1")) >= 0) {
SourceDirectorySet sourceDirectorySet = sourceSet.getExtensions()
.findByType(ScalaSourceDirectorySet.class);
return sourceDirectorySet == null ? Collections.emptySet() : sourceDirectorySet.getSrcDirs();
} else {
// there is no way pre-Gradle 7.1 to get the scala source dirs separately from other
// languages. Luckily source dirs from all languages are jumbled together in BSP,
// so we can just reply with all.
// resource dirs must be removed.
Set<File> allSource = sourceSet.getAllSource().getSrcDirs();
Set<File> allResource = sourceSet.getResources().getSrcDirs();
return allSource.stream().filter(dir -> !allResource.contains(dir))
.collect(Collectors.toSet());
}
}

@Override
Expand Down Expand Up @@ -109,164 +122,60 @@ private String getScalaBinaryVersion(GradleModuleDependency scalaLibraryDependen
return version.substring(0, idx2);
}

private List<String> getScalaCompilerArgs(ScalaCompile scalaCompile) {
ScalaCompileSpecContainer specContainer = new ScalaCompileSpecContainer(scalaCompile);
ZincScalaCompilerArgumentsGenerator argGenerator = new ZincScalaCompilerArgumentsGenerator();
return argGenerator.generate(specContainer);
}

private List<File> getScalaJars(ScalaCompile scalaCompile) {
return new LinkedList<>(scalaCompile.getScalaClasspath().getFiles());
}

// a minimal implementation of ScalaCompileSpec so ZincScalaCompilerArgumentsGenerator can
// be used to generate the Scala compile options instead of duplicating it.
private static class ScalaCompileSpecContainer implements ScalaCompileSpec {

private final ScalaCompile scalaCompile;

ScalaCompileSpecContainer(ScalaCompile scalaCompile) {
this.scalaCompile = scalaCompile;
}

@Override
public List<File> getCompileClasspath() {
throw new UnsupportedOperationException("Unimplemented method 'getCompileClasspath'");
}

@Override
public File getDestinationDir() {
throw new UnsupportedOperationException("Unimplemented method 'getDestinationDir'");
}

@Override
public Integer getRelease() {
throw new UnsupportedOperationException("Unimplemented method 'getRelease'");
}

@Override
public String getSourceCompatibility() {
throw new UnsupportedOperationException("Unimplemented method 'getSourceCompatibility'");
}

@Override
public Iterable<File> getSourceFiles() {
throw new UnsupportedOperationException("Unimplemented method 'getSourceFiles'");
}

@Override
public List<File> getSourceRoots() {
throw new UnsupportedOperationException("Unimplemented method 'getSourceRoots'");
}

@Override
public String getTargetCompatibility() {
throw new UnsupportedOperationException("Unimplemented method 'getTargetCompatibility'");
}

@Override
public File getTempDir() {
throw new UnsupportedOperationException("Unimplemented method 'getTempDir'");
}

@Override
public File getWorkingDir() {
throw new UnsupportedOperationException("Unimplemented method 'getWorkingDir'");
}

@Override
public void setCompileClasspath(List<File> classpath) {
throw new UnsupportedOperationException("Unimplemented method 'setCompileClasspath'");
}

@Override
public void setDestinationDir(File destinationDir) {
throw new UnsupportedOperationException("Unimplemented method 'setDestinationDir'");
}

@Override
public void setRelease(Integer arg0) {
throw new UnsupportedOperationException("Unimplemented method 'setRelease'");
}

@Override
public void setSourceCompatibility(String arg0) {
throw new UnsupportedOperationException("Unimplemented method 'setSourceCompatibility'");
}

@Override
public void setSourceFiles(Iterable<File> sourceFiles) {
throw new UnsupportedOperationException("Unimplemented method 'setSourceFiles'");
}

@Override
public void setSourcesRoots(List<File> sourcesRoots) {
throw new UnsupportedOperationException("Unimplemented method 'setSourcesRoots'");
}

@Override
public void setTargetCompatibility(String arg0) {
throw new UnsupportedOperationException("Unimplemented method 'setTargetCompatibility'");
}

@Override
public void setTempDir(File tempDir) {
throw new UnsupportedOperationException("Unimplemented method 'setTempDir'");
private List<String> getScalaCompilerArgs(ScalaCompile scalaCompile) {
// Gradle changes internal implementation for options handling after 7.0 so manually setup
ScalaCompileOptions options = scalaCompile.getScalaCompileOptions();
List<String> args = new LinkedList<>();
if (options.isDeprecation()) {
args.add("-deprecation");
}

@Override
public void setWorkingDir(File workingDir) {
throw new UnsupportedOperationException("Unimplemented method 'setWorkingDir'");
if (options.isUnchecked()) {
args.add("-unchecked");
}

@Override
public File getAnalysisFile() {
throw new UnsupportedOperationException("Unimplemented method 'getAnalysisFile'");
if (options.getDebugLevel() != null && !options.getDebugLevel().isEmpty()) {
args.add("-g:" + options.getDebugLevel());
}

@Override
public Map<File, File> getAnalysisMap() {
throw new UnsupportedOperationException("Unimplemented method 'getAnalysisMap'");
if (options.isOptimize()) {
args.add("-optimise");
}

@Override
public long getBuildStartTimestamp() {
throw new UnsupportedOperationException("Unimplemented method 'getBuildStartTimestamp'");
if (options.getEncoding() != null && !options.getEncoding().isEmpty()) {
args.add("-encoding");
args.add(options.getEncoding());
}
if (options.getLoggingLevel() != null) {
if ("verbose".equalsIgnoreCase(options.getLoggingLevel())) {
args.add("-verbose");

@Override
public File getClassfileBackupDir() {
throw new UnsupportedOperationException("Unimplemented method 'getClassfileBackupDir'");
} else if ("debug".equalsIgnoreCase(options.getLoggingLevel())) {
args.add("-Ydebug");
}
}

@Override
public MinimalScalaCompileOptions getScalaCompileOptions() {
return new MinimalScalaCompileOptions(scalaCompile.getScalaCompileOptions());
if (options.getLoggingPhases() != null && !options.getLoggingPhases().isEmpty()) {
for (String phase : options.getLoggingPhases()) {
args.add("-Ylog:" + phase);
}
}

@Override
public Iterable<File> getScalaCompilerPlugins() {
return scalaCompile.getScalaCompilerPlugins();
}

@Override
public void setAnalysisFile(File analysisFile) {
throw new UnsupportedOperationException("Unimplemented method 'setAnalysisFile'");
if (options.getAdditionalParameters() != null) {
args.addAll(options.getAdditionalParameters());
}

@Override
public void setAnalysisMap(Map<File, File> analysisMap) {
throw new UnsupportedOperationException("Unimplemented method 'setAnalysisMap'");
// scalaCompilerPlugins was added in Gradle 6.4
try {
Method getScalaCompilerPlugins = ScalaCompile.class
.getDeclaredMethod("getScalaCompilerPlugins");
FileCollection fileCollection = (FileCollection) getScalaCompilerPlugins.invoke(scalaCompile);
for (File file : fileCollection) {
args.add("-Xplugin:" + file.getPath());
}
} catch (NoSuchMethodException | InvocationTargetException
| IllegalArgumentException | IllegalAccessException e) {
// do nothing
}

@Override
public void setClassfileBackupDir(File classfileBackupDir) {
throw new UnsupportedOperationException("Unimplemented method 'setClassfileBackupDir'");
}

@Override
public void setScalaCompilerPlugins(Iterable<File> plugins) {
throw new UnsupportedOperationException("Unimplemented method 'setScalaCompilerPlugins'");
}
return args;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.SourceDirectorySet;
import org.gradle.api.internal.file.copy.DefaultCopySpec;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.SourceSetOutput;
import org.gradle.api.tasks.TaskCollection;
import org.gradle.api.tasks.bundling.AbstractArchiveTask;
import org.gradle.api.tasks.testing.Test;
Expand Down Expand Up @@ -134,10 +134,24 @@ public Object buildAll(String modelName, Project rootProject) {
if (sourceOutputDir != null) {
TaskCollection<Test> testTasks = project.getTasks().withType(Test.class);
for (Test testTask : testTasks) {
FileCollection files = testTask.getTestClassesDirs();
if (files.contains(sourceOutputDir)) {
gradleSourceSet.setHasTests(true);
break;
if (GradleVersion.current().compareTo(GradleVersion.version("4.0")) >= 0) {
FileCollection files = testTask.getTestClassesDirs();
if (files.contains(sourceOutputDir)) {
gradleSourceSet.setHasTests(true);
break;
}
} else {
try {
Method getTestClassesDir = testTask.getClass().getMethod("getTestClassesDir");
Object testClassesDir = getTestClassesDir.invoke(testTask);
if (sourceOutputDir.equals(testClassesDir)) {
gradleSourceSet.setHasTests(true);
break;
}
} catch (NoSuchMethodException | SecurityException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
// ignore
}
}
}
}
Expand Down Expand Up @@ -249,27 +263,30 @@ private void setSourceSetDependencies(SourceSetCache cache) {
}

private SourceSetContainer getSourceSetContainer(Project project) {
if (!project.getPlugins().hasPlugin("java")) {
return null;
}

if (GradleVersion.current().compareTo(GradleVersion.version("7.1")) >= 0) {
JavaPluginExtension javaPlugin = project.getExtensions()
.findByType(JavaPluginExtension.class);
if (javaPlugin != null) {
return javaPlugin.getSourceSets();
if (GradleVersion.current().compareTo(GradleVersion.version("5.0")) >= 0) {
SourceSetContainer sourceSetContainer = project.getExtensions()
.findByType(SourceSetContainer.class);
if (sourceSetContainer != null) {
return sourceSetContainer;
}
} else {
Object javaPluginConvention = project.getConvention().getPlugins().get("java");
if (javaPluginConvention != null) {
try {
Method getSourceSetsMethod = javaPluginConvention.getClass().getMethod("getSourceSets");
return (SourceSetContainer) getSourceSetsMethod.invoke(javaPluginConvention);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
// ignore
}
}
try {
// query the java plugin. This limits support to Java only if other
// languages add their own sourcesets
// use reflection because `getConvention` will be removed in Gradle 9.0
Method getConvention = project.getClass().getMethod("getConvention");
Object convention = getConvention.invoke(project);
Method getPlugins = convention.getClass().getMethod("getPlugins");
Object plugins = getPlugins.invoke(convention);
Method getGet = plugins.getClass().getMethod("get", Object.class);
Object pluginConvention = getGet.invoke(plugins, "java");
if (pluginConvention != null) {
Method getSourceSetsMethod = pluginConvention.getClass().getMethod("getSourceSets");
return (SourceSetContainer) getSourceSetsMethod.invoke(pluginConvention);
}
} catch (NoSuchMethodException | SecurityException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
// ignore
}
return null;
}
Expand Down Expand Up @@ -315,6 +332,15 @@ private File getSourceOutputDir(SourceSet sourceSet) {
| IllegalArgumentException | InvocationTargetException e) {
// ignore
}
} else {
// get all output dirs and filter out resources output
SourceSetOutput output = sourceSet.getOutput();
Set<File> allOutputDirs = output.getFiles();
File resourceOutputDir = output.getResourcesDir();
allOutputDirs.remove(resourceOutputDir);
if (!allOutputDirs.isEmpty()) {
return allOutputDirs.iterator().next();
}
}

return null;
Expand Down Expand Up @@ -353,7 +379,9 @@ private Set<Object> getArchiveSourcePaths(CopySpec copySpec) {
private Set<String> getClasspathConfigurationNames(SourceSet sourceSet) {
Set<String> configurationNames = new HashSet<>();
configurationNames.add(sourceSet.getCompileClasspathConfigurationName());
configurationNames.add(sourceSet.getRuntimeClasspathConfigurationName());
if (GradleVersion.current().compareTo(GradleVersion.version("3.4")) >= 0) {
configurationNames.add(sourceSet.getRuntimeClasspathConfigurationName());
}
return configurationNames;
}
}
Loading

0 comments on commit 013a0b4

Please sign in to comment.