From 0fe430f8340cf9c01a947f00197385eced375c7b Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Wed, 30 May 2012 14:46:58 +0200 Subject: [PATCH] out-of-process build: temp roots management --- .../jps/incremental/IncProjectBuilder.java | 9 +++ .../jps/incremental/ModuleRootsIndex.java | 25 ++++++-- .../jps/incremental/fs/RootDescriptor.java | 4 +- .../jps/incremental/java/JavaBuilder.java | 64 +++++++++---------- .../jps/incremental/java/OutputFilesSink.java | 4 +- .../jetbrains/jps/javac/OutputFileObject.java | 9 +++ .../jps/incremental/groovy/GroovyBuilder.java | 4 +- .../groovy/compiler/GroovyCompilerTest.groovy | 2 +- 8 files changed, 76 insertions(+), 45 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 8f3b8491ed95..c6121dcbf8ab 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -416,6 +416,15 @@ public class IncProjectBuilder { throw new ProjectBuildException(e); } finally { + final Collection tempRoots = context.getRootsIndex().clearTempRoots(); + if (!tempRoots.isEmpty()) { + final Set rootFiles = new HashSet(); + for (RootDescriptor rd : tempRoots) { + rootFiles.add(rd.root); + context.getProjectDescriptor().fsState.clearRecompile(rd); + } + FileUtil.asyncDelete(rootFiles); + } try { // restore deleted paths that were not procesesd by 'integrate' diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleRootsIndex.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleRootsIndex.java index 6a21b35fd152..dd918de2c75b 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleRootsIndex.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleRootsIndex.java @@ -41,13 +41,13 @@ public class ModuleRootsIndex { } for (String r : module.getSourceRoots()) { final File root = new File(FileUtil.toCanonicalPath(r)); - final RootDescriptor descriptor = new RootDescriptor(moduleName, root, false, generatedRoots.contains(r)); + final RootDescriptor descriptor = new RootDescriptor(moduleName, root, false, generatedRoots.contains(r), false); myRootToModuleMap.put(root, descriptor); moduleRoots.add(descriptor); } for (String r : module.getTestRoots()) { final File root = new File(FileUtil.toCanonicalPath(r)); - final RootDescriptor descriptor = new RootDescriptor(moduleName, root, true, generatedRoots.contains(r)); + final RootDescriptor descriptor = new RootDescriptor(moduleName, root, true, generatedRoots.contains(r), false); myRootToModuleMap.put(root, descriptor); moduleRoots.add(descriptor); } @@ -79,7 +79,7 @@ public class ModuleRootsIndex { } @NotNull - public RootDescriptor associateRoot(File root, Module module, boolean isTestRoot, final boolean isForGeneratedSources) { + public RootDescriptor associateRoot(File root, Module module, boolean isTestRoot, final boolean isForGeneratedSources, final boolean isTemp) { final RootDescriptor d = myRootToModuleMap.get(root); if (d != null) { return d; @@ -89,12 +89,29 @@ public class ModuleRootsIndex { moduleRoots = new ArrayList(); myModuleToRootsMap.put(module, moduleRoots); } - final RootDescriptor descriptor = new RootDescriptor(module.getName(), root, isTestRoot, isForGeneratedSources); + final RootDescriptor descriptor = new RootDescriptor(module.getName(), root, isTestRoot, isForGeneratedSources, isTemp); myRootToModuleMap.put(root, descriptor); moduleRoots.add(descriptor); return descriptor; } + @NotNull + public Collection clearTempRoots() { + final Set toRemove = new HashSet(); + for (Iterator> iterator = myRootToModuleMap.entrySet().iterator(); iterator.hasNext(); ) { + Map.Entry entry = iterator.next(); + final RootDescriptor rd = entry.getValue(); + if (rd.isTemp) { + toRemove.add(rd); + iterator.remove(); + } + } + for (Map.Entry> entry : myModuleToRootsMap.entrySet()) { + entry.getValue().removeAll(toRemove); + } + return toRemove; + } + @Nullable public RootDescriptor getModuleAndRoot(File file) { File current = file; diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/fs/RootDescriptor.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/fs/RootDescriptor.java index 4274bdd236c1..fd3540da5e9e 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/fs/RootDescriptor.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/fs/RootDescriptor.java @@ -15,12 +15,14 @@ public final class RootDescriptor { public final File root; public final boolean isTestRoot; public final boolean isGeneratedSources; + public final boolean isTemp; - public RootDescriptor(@NotNull final String moduleName, @NotNull File root, boolean isTestRoot, boolean isGenerated) { + public RootDescriptor(@NotNull final String moduleName, @NotNull File root, boolean isTestRoot, boolean isGenerated, boolean isTemp) { this.module = moduleName; this.root = root; this.isTestRoot = isTestRoot; this.isGeneratedSources = isGenerated; + this.isTemp = isTemp; } @Override diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index 139f1bf4858a..644987d4c892 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -89,26 +89,32 @@ public class JavaBuilder extends ModuleLevelBuilder { //add here class processors in the sequence they should be executed myClassProcessors.add(new ClassPostProcessor() { public void process(CompileContext context, OutputFileObject out) { - final Callbacks.Backend callback = DELTA_MAPPINGS_CALLBACK_KEY.get(context); - if (callback != null) { - final OutputFileObject.Content content = out.getContent(); - final File srcFile = out.getSourceFile(); - if (srcFile != null && content != null) { - final String outputPath = FileUtil.toSystemIndependentName(out.getFile().getPath()); - final String sourcePath = FileUtil.toSystemIndependentName(srcFile.getPath()); - final RootDescriptor moduleAndRoot = context.getModuleAndRoot(srcFile); - final BuildDataManager dataManager = context.getDataManager(); - if (moduleAndRoot != null) { + final OutputFileObject.Content content = out.getContent(); + final File srcFile = out.getSourceFile(); + if (srcFile != null && content != null) { + final String outputPath = FileUtil.toSystemIndependentName(out.getFile().getPath()); + final String sourcePath = FileUtil.toSystemIndependentName(srcFile.getPath()); + final RootDescriptor moduleAndRoot = context.getModuleAndRoot(srcFile); + final BuildDataManager dataManager = context.getDataManager(); + boolean isTemp = false; + if (moduleAndRoot != null) { + isTemp = moduleAndRoot.isTemp; + if (!isTemp) { try { - final String moduleName = moduleAndRoot.module; - dataManager.getSourceToOutputMap(moduleName, context.isCompilingTests()).appendData(sourcePath, outputPath); + dataManager.getSourceToOutputMap(moduleAndRoot.module, context.isCompilingTests()).appendData(sourcePath, outputPath); } catch (Exception e) { context.processMessage(new CompilerMessage(BUILDER_NAME, e)); } } - final ClassReader reader = new ClassReader(content.getBuffer(), content.getOffset(), content.getLength()); - callback.associate(outputPath, sourcePath, reader); + } + out.setTemp(isTemp); + if (!isTemp) { + final Callbacks.Backend callback = DELTA_MAPPINGS_CALLBACK_KEY.get(context); + if (callback != null) { + final ClassReader reader = new ClassReader(content.getBuffer(), content.getOffset(), content.getLength()); + callback.associate(outputPath, sourcePath, reader); + } } } } @@ -124,17 +130,6 @@ public class JavaBuilder extends ModuleLevelBuilder { return "Java Builder"; } - private static final Key> TEMPORARY_SOURCE_ROOTS_KEY = Key.create("_additional_source_roots_"); - - public static void addTempSourcePathRoot(CompileContext context, File root) { - Set roots = TEMPORARY_SOURCE_ROOTS_KEY.get(context); - if (roots == null) { - roots = new HashSet(); - TEMPORARY_SOURCE_ROOTS_KEY.set(context, roots); - } - roots.add(root); - } - public ExitCode build(final CompileContext context, final ModuleChunk chunk) throws ProjectBuildException { try { final Set filesToCompile = new HashSet(); @@ -282,7 +277,15 @@ public class JavaBuilder extends ModuleLevelBuilder { try { if (hasSourcesToCompile) { exitCode = ExitCode.OK; - final Set sourcePath = TEMPORARY_SOURCE_ROOTS_KEY.get(context, Collections.emptySet()); + final Set tempRootsSourcePath = new HashSet(); + final ModuleRootsIndex index = context.getRootsIndex(); + for (Module module : chunk.getModules()) { + for (RootDescriptor rd : index.getModuleRoots(module)) { + if (rd.isTemp) { + tempRootsSourcePath.add(rd.root); + } + } + } final String chunkName = getChunkPresentableName(chunk); context.processMessage(new ProgressMessage("Compiling java [" + chunkName + "]")); @@ -291,7 +294,7 @@ public class JavaBuilder extends ModuleLevelBuilder { boolean compiledOk = true; if (filesCount > 0) { LOG.info("Compiling " + filesCount + " java files; module: " + chunkName); - compiledOk = compileJava(chunk, files, classpath, platformCp, sourcePath, outs, context, diagnosticSink, outputSink); + compiledOk = compileJava(chunk, files, classpath, platformCp, tempRootsSourcePath, outs, context, diagnosticSink, outputSink); } context.checkCanceled(); @@ -362,13 +365,6 @@ public class JavaBuilder extends ModuleLevelBuilder { } } - if (exitCode != ExitCode.ADDITIONAL_PASS_REQUIRED) { - final Set tempRoots = TEMPORARY_SOURCE_ROOTS_KEY.get(context); - TEMPORARY_SOURCE_ROOTS_KEY.set(context, null); - if (tempRoots != null && tempRoots.size() > 0) { - FileUtil.asyncDelete(tempRoots); - } - } return exitCode; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/OutputFilesSink.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/OutputFilesSink.java index ea1a68e72b27..f5c29441feb8 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/OutputFilesSink.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/OutputFilesSink.java @@ -19,7 +19,7 @@ import java.util.*; */ class OutputFilesSink implements OutputFileConsumer { private final CompileContext myContext; - private final Set mySuccessfullyCompiled = new HashSet(); + private final Set mySuccessfullyCompiled = new LinkedHashSet(); private final Set myProblematic = new HashSet(); private final List myFileObjects = new ArrayList(); private final Map myCompiledClasses = new HashMap(); @@ -113,7 +113,7 @@ class OutputFilesSink implements OutputFileConsumer { } final File source = fileObject.getSourceFile(); - if (source != null && !myProblematic.contains(source)) { + if (!fileObject.isTemp() && source != null && !myProblematic.contains(source)) { mySuccessfullyCompiled.add(source); final String className = fileObject.getClassName(); if (className != null) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/OutputFileObject.java b/jps/jps-builders/src/org/jetbrains/jps/javac/OutputFileObject.java index e399548a4dcf..c0495aea130e 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/OutputFileObject.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/OutputFileObject.java @@ -25,6 +25,7 @@ public final class OutputFileObject extends SimpleJavaFileObject { @Nullable private final URI mySourceUri; private volatile Content myContent; private final File mySourceFile; + public boolean myIsTemp = false; public OutputFileObject(@NotNull JavacFileManager.Context context, @Nullable File outputRoot, String relativePath, @NotNull File file, @NotNull Kind kind, @Nullable String className, @Nullable final URI sourceUri) { this(context, outputRoot, relativePath, file, kind, className, sourceUri, null); @@ -42,6 +43,14 @@ public final class OutputFileObject extends SimpleJavaFileObject { mySourceFile = srcUri != null? Utils.convertToFile(srcUri) : null; } + public boolean isTemp() { + return myIsTemp; + } + + public void setTemp(boolean isTemp) { + myIsTemp = isTemp; + } + @Nullable public File getOutputRoot() { return myOutputRoot; diff --git a/plugins/groovy/rt/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java b/plugins/groovy/rt/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java index 4c9c20e16ae9..10c1efcbf01b 100644 --- a/plugins/groovy/rt/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java +++ b/plugins/groovy/rt/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java @@ -14,7 +14,6 @@ import org.jetbrains.groovy.compiler.rt.GroovyCompilerWrapper; import org.jetbrains.jps.*; import org.jetbrains.jps.incremental.*; import org.jetbrains.jps.incremental.fs.RootDescriptor; -import org.jetbrains.jps.incremental.java.JavaBuilder; import org.jetbrains.jps.incremental.messages.CompilerMessage; import org.jetbrains.jps.incremental.messages.FileGeneratedEvent; import org.jetbrains.jps.incremental.messages.ProgressMessage; @@ -100,8 +99,7 @@ public class GroovyBuilder extends ModuleLevelBuilder { if (myForStubs) { for (Module module : generationOutputs.keySet()) { File root = new File(generationOutputs.get(module)); - context.getRootsIndex().associateRoot(root, module, context.isCompilingTests(), true); - JavaBuilder.addTempSourcePathRoot(context, root); + context.getRootsIndex().associateRoot(root, module, context.isCompilingTests(), true, true); } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy index 85a3fdd2dd67..e32f2c8ebf4b 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy @@ -640,7 +640,7 @@ public class Main { CompileServerManager.instance.shutdownServer() } - public void "_test make stub-level error and correct it"() { + public void "test make stub-level error and correct it"() { def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo { }') myFixture.addFileToProject('Bar.java', 'class Bar extends Foo {}')