package org.intellij.errorProne; import com.intellij.compiler.CompilerConfiguration; import com.intellij.compiler.CompilerConfigurationImpl; import com.intellij.compiler.impl.javaCompiler.BackendCompiler; import com.intellij.compiler.server.BuildProcessParametersProvider; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileFilters; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtilRt; import com.intellij.util.ObjectUtils; import com.intellij.util.text.VersionComparatorUtil; import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; /** * @author nik */ public class ErrorProneClasspathProvider extends BuildProcessParametersProvider { private static final Logger LOG = Logger.getInstance(ErrorProneClasspathProvider.class); private static final String VERSION_PROPERTY = "idea.error.prone.version";//duplicates ErrorProneJavaCompilingTool.VERSION_PROPERTY private final Project myProject; public ErrorProneClasspathProvider(Project project) { myProject = project; } public static File getCompilerFilesDir(String version) { return new File(getDownloadCacheDir(), version); } @NotNull private static File getDownloadCacheDir() { return new File(PathManager.getSystemPath(), "download-cache/error-prone"); } private static File[] getLatestCompilerJars() { File[] files = getDownloadCacheDir().listFiles(); if (files != null && files.length > 0) { return StreamEx.of(files).map(dir -> new Pair<>(dir, getJarFiles(dir))) .filter(pair -> pair.second.length > 0) .max(Comparator.comparing(pair -> pair.getFirst().getName(), VersionComparatorUtil.COMPARATOR)) .map(pair -> pair.getSecond()) .orElse(new File[0]); } return new File[0]; } public static File[] getJarFiles(File dir) { return ObjectUtils.notNull(dir.listFiles(FileFilters.filesWithExtension("jar")), ArrayUtilRt.EMPTY_FILE_ARRAY); } @NotNull @Override public List<String> getVMArguments() { if (isErrorProneCompilerSelected(myProject)) { File[] jars = getLatestCompilerJars(); LOG.assertTrue(jars.length > 0, "error-prone compiler jars not found in directory: " + getDownloadCacheDir()); List<String> classpath = new ArrayList<>(); for (File file : jars) { classpath.add(file.getAbsolutePath()); } List<String> arguments = new ArrayList<>(); arguments.add("-Xbootclasspath/a:" + StringUtil.join(classpath, File.pathSeparator)); StreamEx.of(jars).map(ErrorProneClasspathProvider::readVersion).nonNull().findFirst().ifPresent( version -> arguments.add("-D" + VERSION_PROPERTY + "=" + version) ); return arguments; } return Collections.emptyList(); } private static String readVersion(File jarFile) { try { try (FileSystem zipFS = FileSystems.newFileSystem(jarFile.toPath(), null)) { Path propertiesPath = zipFS.getPath("META-INF/maven/com.google.errorprone/error_prone_core/pom.properties"); if (Files.exists(propertiesPath)) { Properties properties = new Properties(); try (InputStream input = Files.newInputStream(propertiesPath)) { properties.load(input); return properties.getProperty("version"); } } } } catch (IOException e) { LOG.debug(e); } return null; } static boolean isErrorProneCompilerSelected(@NotNull Project project) { BackendCompiler compiler = ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(project)).getDefaultCompiler(); return compiler instanceof ErrorProneJavaBackendCompiler; } }