package org.netbeans.gradle.build; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import org.gradle.api.Action; import org.gradle.api.JavaVersion; import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.tasks.compile.CompileOptions; import org.gradle.api.tasks.compile.ForkOptions; import org.gradle.api.tasks.compile.GroovyCompile; import org.gradle.api.tasks.compile.JavaCompile; public final class CompilerUtils { private static final String JAVAC_VERSION_PREFIX = "javac"; private static String tryGetCompilerVersion(ForkOptions forkOptions) { String executable = forkOptions.getExecutable(); if (executable == null || executable.isEmpty()) { return null; } ProcessBuilder processBuilder = new ProcessBuilder(executable, "-version"); processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT); try { Process process = processBuilder.start(); InputStream input = process.getErrorStream(); BufferedReader inputReader = new BufferedReader(new InputStreamReader(input, "ISO-8859-1"), 4096); String result = null; String line = inputReader.readLine(); while (line != null) { if (line.startsWith(JAVAC_VERSION_PREFIX)) { result = line.substring(JAVAC_VERSION_PREFIX.length()).trim(); // Continue reading to prevent dead-locking the process if it // prints something else. } line = inputReader.readLine(); } return result; } catch (IOException ex) { return null; } } public static JavaVersion getTargetCompatibility(Project project) { JavaPluginConvention javaPlugin = project.getConvention().findPlugin(JavaPluginConvention.class); return javaPlugin.getTargetCompatibility(); } public static File findToolsJar(Project project, JavaVersion javaVersion) { String explicitToolsJarProperty = "jdk" + javaVersion.getMajorVersion() + "ToolsJar"; if (project.hasProperty(explicitToolsJarProperty)) { return new File(project.property(explicitToolsJarProperty).toString().trim()); } String foundToolsJar = null; String explicitJavaCompiler = tryGetExplicitJdkCompiler(project, javaVersion); if (explicitJavaCompiler != null) { foundToolsJar = extractToolsJarFromCompiler(explicitJavaCompiler); } if (foundToolsJar == null) { String javaHome = System.getProperty("java.home"); foundToolsJar = extractToolsJarFromJavaHome(javaHome); } if (foundToolsJar == null) { throw new IllegalStateException("Unable to find the JDK's tools.jar."); } return new File(foundToolsJar); } public static String tryGetCompilerVersion(JavaCompile compileTask) { CompileOptions options = compileTask.getOptions(); if (options.isFork()) { ForkOptions forkOptions = options.getForkOptions(); return tryGetCompilerVersion(forkOptions); } else { return System.getProperty("java.version"); } } public static void configureJavaCompilers(Project project) { project.getTasks().withType(JavaCompile.class, new Action<JavaCompile>() { @Override public void execute(JavaCompile compileTask) { configureJavaCompiler(compileTask); } }); project.getTasks().withType(GroovyCompile.class, new Action<GroovyCompile>() { @Override public void execute(GroovyCompile compileTask) { configureJavaCompiler(compileTask); } }); } private static void configureJavaCompiler(final JavaCompile compileTask) { configureJavaCompiler(compileTask, compileTask.getOptions()); } private static void configureJavaCompiler(final GroovyCompile compileTask) { configureJavaCompiler(compileTask, compileTask.getOptions()); } private static void configureJavaCompiler(final Task compileTask, final CompileOptions compilerOptions) { compilerOptions.setEncoding("UTF-8"); addCompilerArgs(compilerOptions, "-Xlint"); TaskConfigurations.lazilyConfiguredTask(compileTask, new Action<Task>() { @Override public void execute(Task task) { configureJavacNow(compileTask, compilerOptions); } }); } public static void addCompilerArgs(CompileOptions options, String... newArgs) { List<String> prevArgs = options.getCompilerArgs(); List<String> args = new ArrayList<>(prevArgs.size() + newArgs.length); args.addAll(prevArgs); args.addAll(Arrays.asList(newArgs)); options.setCompilerArgs(args); } private static void configureJavacNow(Task compileTask, CompileOptions compilerOptions) { final JavaVersion targetCompatibility = getTargetCompatibility(compileTask.getProject()); if (Objects.equals(JavaVersion.current(), targetCompatibility)) { return; } final Project project = compileTask.getProject(); String explicitJavaCompiler = tryGetExplicitJdkCompiler(project, targetCompatibility); if (explicitJavaCompiler != null) { compilerOptions.setFork(true); compilerOptions.getForkOptions().setExecutable(explicitJavaCompiler); } else { compileTask.doFirst(new Action<Task>() { @Override public void execute(Task t) { String jdkProperty = getJdkPropertyName(targetCompatibility); project.getLogger().warn("Warning: " + jdkProperty + " property is missing and" + " not compiling with Java " + targetCompatibility + ". Using " + JavaVersion.current()); } }); } } private static Path subPath(Path base, String... subPaths) { if (base == null) { return null; } Path result = base; for (String subPath: subPaths) { result = result.resolve(subPath); } return result; } private static Path getParent(Path base, int level) { Path result = base; for (int i = 0; i < level && result != null; i++) { result = result.getParent(); } return result; } private static String extractToolsJarFromJDKHome(Path jdkHome) { Path toolsJar = subPath(jdkHome, "lib", "tools.jar"); if (toolsJar == null) { return null; } if (!Files.isRegularFile(toolsJar)) { return null; } return toolsJar.toString(); } private static String extractToolsJarFromJavaHome(String javaHome) { if (javaHome == null) { return null; } Path jdkHome = Paths.get(javaHome).getParent(); return extractToolsJarFromJDKHome(jdkHome); } private static String extractToolsJarFromCompiler(String javac) { if (javac == null) { return null; } Path jdkHome = getParent(Paths.get(javac), 2); return extractToolsJarFromJDKHome(jdkHome); } private static String getJdkPropertyName(JavaVersion javaVersion) { return "jdk" + javaVersion.getMajorVersion() + "Compiler"; } private static String tryGetExplicitJdkCompiler(Project project, JavaVersion javaVersion) { String jdkProperty = getJdkPropertyName(javaVersion); if (project.hasProperty(jdkProperty)) { return project.property(jdkProperty).toString().trim(); } else { return null; } } private CompilerUtils() { throw new AssertionError(); } }