private Collection<File> getClasspathFiles( ModuleChunk chunk, JpsJavaClasspathKind kind, final boolean excludeMainModuleOutput, ClasspathPart classpathPart, final boolean exportedOnly) { final Set<File> files = new LinkedHashSet<File>(); for (JpsModule module : chunk.getModules()) { JpsJavaDependenciesEnumerator enumerator = JpsJavaExtensionService.dependencies(module).includedIn(kind).recursively(); if (exportedOnly) { enumerator = enumerator.exportedOnly(); } if (classpathPart == ClasspathPart.BEFORE_JDK) { enumerator = enumerator.satisfying(new BeforeJavaSdkItemFilter(module)); } else if (classpathPart == ClasspathPart.AFTER_JDK) { enumerator = enumerator.satisfying(new AfterJavaSdkItemFilter(module)); } JpsJavaDependenciesRootsEnumerator rootsEnumerator = enumerator.classes(); if (excludeMainModuleOutput) { rootsEnumerator = rootsEnumerator.withoutSelfModuleOutput(); } files.addAll(rootsEnumerator.getRoots()); } if (classpathPart == ClasspathPart.BEFORE_JDK) { for (JpsModule module : chunk.getModules()) { JpsSdk<JpsDummyElement> sdk = module.getSdk(JpsJavaSdkType.INSTANCE); if (sdk != null) { files.addAll(sdk.getParent().getFiles(JpsOrderRootType.COMPILED)); } } } return files; }
private static Map<String, String> buildClassToSourceMap( ModuleChunk chunk, CompileContext context, Set<String> toCompilePaths, String moduleOutputPath) throws IOException { final Map<String, String> class2Src = new HashMap<String, String>(); for (Module module : chunk.getModules()) { final String moduleName = module.getName().toLowerCase(Locale.US); final SourceToOutputMapping srcToOut = context.getDataManager().getSourceToOutputMap(moduleName, context.isCompilingTests()); for (String src : srcToOut.getKeys()) { if (!toCompilePaths.contains(src) && isGroovyFile(src)) { final Collection<String> outs = srcToOut.getState(src); if (outs != null) { for (String out : outs) { if (out.endsWith(".class") && out.startsWith(moduleOutputPath)) { final String className = out.substring(moduleOutputPath.length(), out.length() - ".class".length()) .replace('/', '.'); class2Src.put(className, src); } } } } } } return class2Src; }
private static String getJavaExecutable(ModuleChunk chunk) { Sdk sdk = chunk.getModules().iterator().next().getSdk(); if (sdk instanceof JavaSdk) { return ((JavaSdk) sdk).getJavaExecutable(); } return SystemProperties.getJavaHome() + "/bin/java"; }
/** * @param chunk * @return mapping "sourceRoot" -> "package prefix" Package prefix uses slashes instead of dots * and ends with trailing slash */ public static Map<File, String> getSourceRootsWithDependents(ModuleChunk chunk) { final boolean includeTests = chunk.containsTests(); final Map<File, String> result = new LinkedHashMap<File, String>(); processModulesRecursively( chunk, JpsJavaClasspathKind.compile(includeTests), new Consumer<JpsModule>() { @Override public void consume(JpsModule module) { for (JpsModuleSourceRoot root : module.getSourceRoots()) { if (root.getRootType().equals(JavaSourceRootType.SOURCE) || includeTests && root.getRootType().equals(JavaSourceRootType.TEST_SOURCE)) { JavaSourceRootProperties properties = (JavaSourceRootProperties) ((JpsSimpleElement<?>) root.getProperties()).getData(); String prefix = properties.getPackagePrefix(); if (!prefix.isEmpty()) { prefix = prefix.replace('.', '/'); if (!prefix.endsWith("/")) { prefix += "/"; } } else { prefix = null; } result.put(JpsPathUtil.urlToFile(root.getUrl()), prefix); } } } }); return result; }
private static void processModulesRecursively( ModuleChunk chunk, JpsJavaClasspathKind kind, Consumer<JpsModule> processor) { JpsJavaExtensionService.getInstance() .enumerateDependencies(chunk.getModules()) .includedIn(kind) .recursively() .processModules(processor); }
public Collection<File> getCompilationClasspath( ModuleChunk chunk, boolean excludeMainModuleOutput) { return getClasspathFiles( chunk, JpsJavaClasspathKind.compile(chunk.containsTests()), excludeMainModuleOutput, ClasspathPart.AFTER_JDK, true); }
private static String getModuleOutput(CompileContext context, ModuleChunk chunk) { final Module representativeModule = chunk.getModules().iterator().next(); File moduleOutputDir = context .getProjectPaths() .getModuleOutputDir(representativeModule, context.isCompilingTests()); assert moduleOutputDir != null; String moduleOutputPath = FileUtil.toCanonicalPath(moduleOutputDir.getPath()); return moduleOutputPath.endsWith("/") ? moduleOutputPath : moduleOutputPath + "/"; }
public static Collection<File> getOutputPathsWithDependents(final ModuleChunk chunk) { final boolean forTests = chunk.containsTests(); final Set<File> sourcePaths = new LinkedHashSet<File>(); processModulesRecursively( chunk, JpsJavaClasspathKind.compile(forTests), new Consumer<JpsModule>() { @Override public void consume(JpsModule module) { addFile( sourcePaths, JpsJavaExtensionService.getInstance().getOutputUrl(module, forTests)); } }); return sourcePaths; }
public ModuleLevelBuilder.ExitCode build(final CompileContext context, ModuleChunk chunk) throws ProjectBuildException { try { final List<File> toCompile = collectChangedFiles(context, chunk); if (toCompile.isEmpty()) { return ExitCode.NOTHING_DONE; } String moduleOutput = getModuleOutput(context, chunk); String compilerOutput = getCompilerOutput(moduleOutput); final Set<String> toCompilePaths = new LinkedHashSet<String>(); for (File file : toCompile) { toCompilePaths.add(FileUtil.toSystemIndependentName(file.getPath())); } Map<String, String> class2Src = buildClassToSourceMap(chunk, context, toCompilePaths, moduleOutput); String ideCharset = chunk.getProject().getProjectCharset(); String encoding = !Comparing.equal(CharsetToolkit.getDefaultSystemCharset().name(), ideCharset) ? ideCharset : null; List<String> patchers = Collections.emptyList(); // todo patchers final File tempFile = GroovycOSProcessHandler.fillFileWithGroovycParameters( compilerOutput, toCompilePaths, FileUtil.toSystemDependentName(moduleOutput), class2Src, encoding, patchers); // todo different outputs in a chunk // todo xmx final List<String> cmd = ExternalProcessUtil.buildJavaCommandLine( getJavaExecutable(chunk), "org.jetbrains.groovy.compiler.rt.GroovycRunner", Collections.<String>emptyList(), new ArrayList<String>(generateClasspath(context, chunk)), Arrays.asList( "-Xmx384m", "-Dfile.encoding=" + CharsetToolkit.getDefaultSystemCharset().name() /*, "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5239"*/), Arrays.<String>asList(myForStubs ? "stubs" : "groovyc", tempFile.getPath())); final Process process = Runtime.getRuntime().exec(ArrayUtil.toStringArray(cmd)); GroovycOSProcessHandler handler = GroovycOSProcessHandler.runGroovyc( process, new Consumer<String>() { public void consume(String s) { context.processMessage(new ProgressMessage(s)); } }); if (handler.shouldRetry()) { if (CHUNK_REBUILD_ORDERED.get(context) != null) { CHUNK_REBUILD_ORDERED.set(context, null); } else { CHUNK_REBUILD_ORDERED.set(context, Boolean.TRUE); return ExitCode.CHUNK_REBUILD_REQUIRED; } } if (myForStubs) { JavaBuilder.addTempSourcePathRoot(context, new File(compilerOutput)); } for (CompilerMessage message : handler.getCompilerMessages()) { context.processMessage(message); } if (!myForStubs && updateDependencies( context, chunk, toCompile, moduleOutput, handler.getSuccessfullyCompiled())) { return ExitCode.ADDITIONAL_PASS_REQUIRED; } return ExitCode.OK; } catch (Exception e) { throw new ProjectBuildException(e); } }
public BuildStatus build(final Collection<Module> modules, final Flags flags) { boolean incremental = flags.incremental(); final List<ModuleChunk> chunks = myProjectBuilder.getChunks(flags.tests()).getChunkList(); for (final ModuleChunk c : chunks) { final Set<Module> chunkModules = c.getElements(); if (!DefaultGroovyMethods.intersect(modules, chunkModules).isEmpty()) { final Set<String> removedSources = new HashSet<String>(); if (incremental) { final Set<String> chunkSources = new HashSet<String>(); final Set<String> outdatedSources = new HashSet<String>(); for (Module m : chunkModules) { final ModuleWrapper mw = getModule(m.getName()); outdatedSources.addAll(mw.getOutdatedFiles(flags.tests())); chunkSources.addAll(mw.getSources(flags.tests())); removedSources.addAll(mw.getRemovedFiles(flags.tests())); } final BuildStatus result = iterativeCompile(c, chunkSources, outdatedSources, removedSources, flags); incremental = result == BuildStatus.INCREMENTAL; if (result == BuildStatus.FAILURE) { return result; } } else { new Logger(flags) { @Override public void log(PrintStream stream) { stream.println("Compiling chunk " + c.getName() + " non-incrementally."); } }.log(); for (Module m : chunkModules) { final ModuleWrapper mw = getModule(m.getName()); removedSources.addAll(flags.tests() ? mw.getRemovedTests() : mw.getRemovedSources()); } final Set<Module> toClean = new HashSet<Module>(); for (Module m : chunkModules) { if (!cleared.contains(m)) { toClean.add(m); } } if (!toClean.isEmpty() && !flags.tests()) { builder.clearChunk(new ModuleChunk(toClean), null, ProjectWrapper.this); cleared.addAll(toClean); } final Mappings delta = dependencyMapping.createDelta(); final Callbacks.Backend deltaCallback = delta.getCallback(); try { builder.buildChunk(c, flags.tests(), null, deltaCallback, ProjectWrapper.this); } catch (Exception e) { e.printStackTrace(); return BuildStatus.FAILURE; } final Set<String> allFiles = new HashSet<String>(); for (Module m : c.getElements()) { final ModuleWrapper module = getModule(m.getName()); affectedFiles.removeAll(module.getSources(flags.tests())); allFiles.addAll(module.getSources(flags.tests())); } final Collection<File> files = new HashSet<File>(); for (String f : allFiles) { files.add(new File(f)); } dependencyMapping.integrate(delta, files, removedSources); for (Module m : chunkModules) { Reporter.reportBuildSuccess(m, flags.tests()); } } } } return BuildStatus.INCREMENTAL; }
BuildStatus iterativeCompile( final ModuleChunk chunk, final Set<String> sources, final Set<String> outdated, final Set<String> removed, final Flags flags) { final Collection<String> filesToCompile = DefaultGroovyMethods.intersect(affectedFiles, sources); if (outdated != null) { for (String s : outdated) { assert (s != null); } filesToCompile.addAll(outdated); } filesToCompile.removeAll(compiledFiles); if (!filesToCompile.isEmpty() || removed != null) { final Set<String> outputFiles = new HashSet<String>(); for (String f : filesToCompile) { final Set<ClassRepr> classes = dependencyMapping.getClasses(f); if (classes != null) { for (ClassRepr cr : classes) { outputFiles.add(cr.getFileName()); } } } if (removed != null) { for (String f : removed) { final Set<ClassRepr> classes = dependencyMapping.getClasses(f); if (classes != null) { for (ClassRepr cr : classes) { outputFiles.add(cr.getFileName()); } } } } if (!outputFiles.isEmpty()) { new Logger(flags) { @Override public void log(PrintStream stream) { stream.println("Cleaning output files:"); logFilePaths(stream, outputFiles); stream.println("End of files"); } }.log(); builder.clearChunk(chunk, outputFiles, ProjectWrapper.this); } final Mappings delta = dependencyMapping.createDelta(); final Callbacks.Backend deltaBackend = delta.getCallback(); new Logger(flags) { @Override public void log(PrintStream stream) { stream.println("Compiling files:"); logFilePaths(stream, filesToCompile); stream.println("End of files"); } }.log(); boolean buildException = false; try { builder.buildChunk( chunk, flags.tests(), filesToCompile, deltaBackend, ProjectWrapper.this); } catch (Exception e) { e.printStackTrace(); buildException = true; } if (!buildException) { compiledFiles.addAll(filesToCompile); affectedFiles.removeAll(filesToCompile); final Collection<File> files = new HashSet<File>(); final Collection<File> compiled = new HashSet<File>(); for (String f : filesToCompile) { files.add(new File(f)); } for (String f : compiledFiles) { compiled.add(new File(f)); } final Collection<File> affected = new HashSet<File>(); final boolean incremental = dependencyMapping.differentiate(delta, removed, files, compiled, affected); for (File a : affected) { affectedFiles.add(FileUtil.toSystemIndependentName(a.getAbsolutePath())); } dependencyMapping.integrate(delta, files, removed); if (!incremental) { affectedFiles.addAll(sources); affectedFiles.removeAll(compiledFiles); final BuildStatus result = iterativeCompile(chunk, sources, null, null, flags); if (result == BuildStatus.FAILURE) { return result; } return BuildStatus.CONSERVATIVE; } return iterativeCompile(chunk, sources, null, null, flags); } else { return BuildStatus.FAILURE; } } else { for (Module m : chunk.getElements()) { Reporter.reportBuildSuccess(m, flags.tests()); } } return BuildStatus.INCREMENTAL; }