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 5f746dbc7c75..dc3284c1bf9c 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -3,6 +3,7 @@ package org.jetbrains.jps.incremental; import com.intellij.openapi.Forceable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.LowMemoryWatcher; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.io.MappingFailedException; @@ -234,6 +235,23 @@ public class IncProjectBuilder { private void cleanOutputRoots(CompileContext context) throws ProjectBuildException { // whole project is affected + final boolean shouldClear = context.getProject().getCompilerConfiguration().isClearOutputDirectoryOnRebuild(); + try { + if (shouldClear) { + clearOutputs(context); + } + else { + for (Module module : context.getProject().getModules().values()) { + final String moduleName = module.getName(); + clearOutputFiles(context, moduleName, true); + clearOutputFiles(context, moduleName, false); + } + } + } + catch (IOException e) { + throw new ProjectBuildException("Error cleaning output files", e); + } + try { context.getTimestamps().clean(); } @@ -247,19 +265,33 @@ public class IncProjectBuilder { throw new ProjectBuildException("Error cleaning compiler storages", e); } myProjectDescriptor.fsState.clearAll(); + } + private static void clearOutputFiles(CompileContext context, final String moduleName, boolean forTests) throws IOException { + final SourceToOutputMapping map = context.getDataManager().getSourceToOutputMap(moduleName, forTests); + for (String srcPath : map.getKeys()) { + final Collection outs = map.getState(srcPath); + if (outs != null) { + for (String out : outs) { + new File(out).delete(); + } + } + } + } + + private static void clearOutputs(CompileContext context) throws ProjectBuildException, IOException { final Collection modulesToClean = context.getProject().getModules().values(); - final Set rootsToDelete = new HashSet(); + final Map>> rootsToDelete = new HashMap>>(); // map: outputRoot-> setOfPairs([module, isTest]) final Set allSourceRoots = new HashSet(); for (Module module : modulesToClean) { final File out = context.getProjectPaths().getModuleOutputDir(module, false); if (out != null) { - rootsToDelete.add(out); + appendRootInfo(rootsToDelete, out, module, false); } final File testOut = context.getProjectPaths().getModuleOutputDir(module, true); if (testOut != null) { - rootsToDelete.add(testOut); + appendRootInfo(rootsToDelete, testOut, module, true); } final List moduleRoots = context.getModuleRoots(module); for (RootDescriptor d : moduleRoots) { @@ -269,9 +301,10 @@ public class IncProjectBuilder { // check that output and source roots are not overlapping final List filesToDelete = new ArrayList(); - for (File outputRoot : rootsToDelete) { + for (Map.Entry>> entry : rootsToDelete.entrySet()) { context.checkCanceled(); boolean okToDelete = true; + final File outputRoot = entry.getKey(); if (PathUtil.isUnder(allSourceRoots, outputRoot)) { okToDelete = false; } @@ -293,6 +326,10 @@ public class IncProjectBuilder { } else { context.processMessage(new CompilerMessage(COMPILE_SERVER_NAME, BuildMessage.Kind.WARNING, "Output path " + outputRoot.getPath() + " intersects with a source root. The output cannot be cleaned.")); + // clean only those files we are aware of + for (Pair info : entry.getValue()) { + clearOutputFiles(context, info.first, info.second); + } } } @@ -300,6 +337,15 @@ public class IncProjectBuilder { FileUtil.asyncDelete(filesToDelete); } + private static void appendRootInfo(Map>> rootsToDelete, File out, Module module, boolean isTest) { + Set> infos = rootsToDelete.get(out); + if (infos == null) { + infos = new HashSet>(); + rootsToDelete.put(out, infos); + } + infos.add(Pair.create(module.getName(), isTest)); + } + private static void runTasks(CompileContext context, final List tasks) throws ProjectBuildException { for (BuildTask task : tasks) { task.build(context);