external compiler: delete output directories on rebuild for all targets

This commit is contained in:
nik
2012-10-09 10:55:54 +04:00
parent c2eed131b1
commit a720290993
9 changed files with 92 additions and 49 deletions
@@ -7,6 +7,7 @@ import org.jetbrains.jps.indices.IgnoredFileIndex;
import org.jetbrains.jps.indices.ModuleExcludeIndex;
import org.jetbrains.jps.model.JpsModel;
import java.io.File;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.List;
@@ -44,6 +45,9 @@ public abstract class BuildTarget<R extends BuildRootDescriptor> {
@NotNull
public abstract String getPresentableName();
@Nullable
public abstract File getOutputDir(BuildDataPaths paths);
@Override
public String toString() {
return getPresentableName();
@@ -305,31 +305,19 @@ public class IncProjectBuilder {
}
private void clearOutputs(CompileContext context) throws ProjectBuildException, IOException {
final MultiMap<File, ModuleBuildTarget> rootsToDelete = new MultiMapBasedOnSet<File, ModuleBuildTarget>();
final Set<File> annotationOutputs = new HashSet<File>(); // separate collection because no root intersection checks needed for annotation generated sources
final MultiMap<File, BuildTarget<?>> rootsToDelete = new MultiMapBasedOnSet<File,BuildTarget<?>>();
final Set<File> allSourceRoots = new HashSet<File>();
final ProjectPaths paths = context.getProjectPaths();
for (JavaModuleBuildTargetType type : JavaModuleBuildTargetType.ALL_TYPES) {
for (ModuleBuildTarget target : context.getProjectDescriptor().getBuildTargetIndex().getAllTargets(type)) {
final File out = paths.getModuleOutputDir(target.getModule(), target.isTests());
if (out != null) {
rootsToDelete.putValue(out, target);
}
final ProcessorConfigProfile profile = context.getAnnotationProcessingProfile(target.getModule());
if (profile.isEnabled()) {
File annotationOut =
paths.getAnnotationProcessorGeneratedSourcesOutputDir(target.getModule(), target.isTests(), profile.getGeneratedSourcesDirectoryName());
if (annotationOut != null) {
annotationOutputs.add(annotationOut);
}
}
ProjectDescriptor projectDescriptor = context.getProjectDescriptor();
for (BuildTarget<?> target : projectDescriptor.getBuildTargetIndex().getAllTargets()) {
File outputDir = target.getOutputDir(projectDescriptor.dataManager.getDataPaths());
if (outputDir != null) {
rootsToDelete.putValue(outputDir, target);
}
}
ProjectDescriptor projectDescriptor = context.getProjectDescriptor();
for (BuildTargetType<?> type : JavaModuleBuildTargetType.ALL_TYPES) {
for (BuildTarget<?> target : projectDescriptor.getBuildTargetIndex().getAllTargets(type)) {
for (BuildRootDescriptor descriptor : projectDescriptor.getBuildRootIndex().getTargetRoots(target, context)) {
@@ -340,7 +328,7 @@ public class IncProjectBuilder {
// check that output and source roots are not overlapping
final List<File> filesToDelete = new ArrayList<File>();
for (Map.Entry<File, Collection<ModuleBuildTarget>> entry : rootsToDelete.entrySet()) {
for (Map.Entry<File, Collection<BuildTarget<?>>> entry : rootsToDelete.entrySet()) {
context.checkCanceled();
boolean okToDelete = true;
final File outputRoot = entry.getKey();
@@ -366,12 +354,24 @@ public class IncProjectBuilder {
else {
context.processMessage(new CompilerMessage(BUILD_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 (ModuleBuildTarget target : entry.getValue()) {
for (BuildTarget<?> target : entry.getValue()) {
clearOutputFiles(context, target);
}
}
}
final Set<File> annotationOutputs = new HashSet<File>(); // separate collection because no root intersection checks needed for annotation generated sources
for (JavaModuleBuildTargetType type : JavaModuleBuildTargetType.ALL_TYPES) {
for (ModuleBuildTarget target : projectDescriptor.getBuildTargetIndex().getAllTargets(type)) {
final ProcessorConfigProfile profile = context.getAnnotationProcessingProfile(target.getModule());
if (profile.isEnabled()) {
File annotationOut = paths.getAnnotationProcessorGeneratedSourcesOutputDir(target.getModule(), target.isTests(), profile.getGeneratedSourcesDirectoryName());
if (annotationOut != null) {
annotationOutputs.add(annotationOut);
}
}
}
}
for (File annotationOutput : annotationOutputs) {
// do not delete output root itself to avoid lots of unnecessary "roots_changed" events in IDEA
final File[] children = annotationOutput.listFiles();
@@ -649,26 +649,23 @@ public class IncProjectBuilder {
}
private static void createClasspathIndex(final ModuleChunk chunk) {
final Set<File> outputPaths = new LinkedHashSet<File>();
final Set<File> outputDirs = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
for (ModuleBuildTarget target : chunk.getTargets()) {
final File outputDir = JpsJavaExtensionService.getInstance().getOutputDirectory(target.getModule(), target.isTests());
if (outputDir != null) {
outputPaths.add(outputDir);
}
}
for (File outputRoot : outputPaths) {
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(outputRoot, CLASSPATH_INDEX_FINE_NAME)));
File outputDir = target.getOutputDir();
if (outputDir != null && outputDirs.add(outputDir)) {
try {
writeIndex(writer, outputRoot, "");
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(outputDir, CLASSPATH_INDEX_FINE_NAME)));
try {
writeIndex(writer, outputDir, "");
}
finally {
writer.close();
}
}
finally {
writer.close();
catch (IOException e) {
// Ignore. Failed to create optional classpath index
}
}
catch (IOException e) {
// Ignore. Failed to create optional classpath index
}
}
}
@@ -964,7 +961,7 @@ public class IncProjectBuilder {
if (context.isMake()) {
if (pd.fsState.markInitialScanPerformed(target)) {
boolean forceMarkDirty = false;
final File currentOutput = context.getProjectPaths().getModuleOutputDir(target.getModule(), target.isTests());
final File currentOutput = target.getOutputDir();
if (currentOutput != null) {
final Pair<String, String> outputsPair = pd.dataManager.getOutputRootsLayout().getState(target.getModuleName());
if (outputsPair != null) {
@@ -1011,7 +1008,7 @@ public class IncProjectBuilder {
}
private static void updateOutputRootsLayout(CompileContext context, ModuleBuildTarget target) throws IOException {
final File currentOutput = context.getProjectPaths().getModuleOutputDir(target.getModule(), target.isTests());
final File currentOutput = target.getOutputDir();
if (currentOutput == null) {
return;
}
@@ -3,12 +3,12 @@ package org.jetbrains.jps.incremental;
import com.intellij.util.Consumer;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.builders.storage.BuildDataPaths;
import org.jetbrains.jps.util.JpsPathUtil;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.builders.BuildRootIndex;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor;
import org.jetbrains.jps.builders.storage.BuildDataPaths;
import org.jetbrains.jps.indices.IgnoredFileIndex;
import org.jetbrains.jps.indices.ModuleExcludeIndex;
import org.jetbrains.jps.model.JpsModel;
@@ -19,6 +19,7 @@ import org.jetbrains.jps.model.java.JpsJavaDependenciesEnumerator;
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
import org.jetbrains.jps.model.module.JpsModule;
import org.jetbrains.jps.model.module.JpsTypedModuleSourceRoot;
import org.jetbrains.jps.util.JpsPathUtil;
import java.io.File;
import java.util.ArrayList;
@@ -41,6 +42,17 @@ public class ModuleBuildTarget extends BuildTarget<JavaSourceRootDescriptor> {
myModule = module;
}
@Nullable
public File getOutputDir() {
return JpsJavaExtensionService.getInstance().getOutputDirectory(myModule, myTargetType.isTests());
}
@Nullable
@Override
public File getOutputDir(BuildDataPaths paths) {
return getOutputDir();
}
@NotNull
public JpsModule getModule() {
return myModule;
@@ -1,8 +1,10 @@
package org.jetbrains.jps.incremental.artifacts;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.builders.BuildRootDescriptor;
import org.jetbrains.jps.builders.BuildRootIndex;
import org.jetbrains.jps.builders.BuildTarget;
@@ -17,6 +19,7 @@ import org.jetbrains.jps.model.artifact.JpsArtifact;
import org.jetbrains.jps.model.artifact.elements.JpsArtifactOutputPackagingElement;
import org.jetbrains.jps.model.artifact.elements.JpsPackagingElement;
import java.io.File;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.LinkedHashSet;
@@ -110,4 +113,11 @@ public class ArtifactBuildTarget extends BuildTarget<ArtifactRootDescriptor> {
public String getPresentableName() {
return "Artifact '" + myArtifact.getName() + "'";
}
@Nullable
@Override
public File getOutputDir(BuildDataPaths paths) {
String outputPath = myArtifact.getOutputPath();
return !StringUtil.isEmpty(outputPath) ? new File(FileUtil.toSystemDependentName(outputPath)) : null;
}
}
@@ -368,11 +368,13 @@ public class JavaBuilder extends ModuleLevelBuilder {
instrumentForms(context, chunk, chunkSourcePath, finder, forms, outputSink);
JpsUiDesignerConfiguration configuration = JpsUiDesignerExtensionService.getInstance().getUiDesignerConfiguration(
pd.getProject());
if (configuration != null && configuration.isCopyFormsRuntimeToOutput() && !chunk.containsTests()) {
for (JpsModule module : chunk.getModules()) {
final File outputDir = paths.getModuleOutputDir(module, false);
if (outputDir != null) {
CopyResourcesUtil.copyFormsRuntime(outputDir.getAbsolutePath(), false);
if (configuration != null && configuration.isCopyFormsRuntimeToOutput()) {
for (ModuleBuildTarget target : chunk.getTargets()) {
if (!target.isTests()) {
final File outputDir = target.getOutputDir();
if (outputDir != null) {
CopyResourcesUtil.copyFormsRuntime(outputDir.getAbsolutePath(), false);
}
}
}
}
@@ -888,7 +890,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
private static Map<File, Set<File>> buildOutputDirectoriesMap(CompileContext context, ModuleChunk chunk) {
final Map<File, Set<File>> map = new LinkedHashMap<File, Set<File>>();
for (ModuleBuildTarget target : chunk.getTargets()) {
final File outputDir = JpsJavaExtensionService.getInstance().getOutputDirectory(target.getModule(), target.isTests());
final File outputDir = target.getOutputDir();
if (outputDir == null) {
continue;
}
@@ -2,10 +2,10 @@ package org.jetbrains.jps.incremental.artifacts;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.PathUtil;
import org.jetbrains.jps.util.JpsPathUtil;
import org.jetbrains.jps.model.artifact.JpsArtifact;
import org.jetbrains.jps.model.library.JpsLibrary;
import org.jetbrains.jps.model.module.JpsModule;
import org.jetbrains.jps.util.JpsPathUtil;
import java.io.File;
import java.io.IOException;
@@ -269,4 +269,15 @@ public class ArtifactBuilderTest extends ArtifactBuilderTestCase {
}
}
public void testClearOutputOnRebuild() throws IOException {
String file = createFile("d/a.txt");
JpsArtifact a = addArtifact(root().parentDirCopy(file));
buildAll();
new File(a.getOutputPath(), "b.txt").createNewFile();
buildAllAndAssertUpToDate();
assertOutput(a, fs().file("a.txt").file("b.txt"));
rebuildAll();
assertOutput(a, fs().file("a.txt"));
}
}
@@ -18,7 +18,7 @@ import java.util.*;
public class JpsJavaCompilerConfigurationImpl extends JpsCompositeElementBase<JpsJavaCompilerConfigurationImpl> implements JpsJavaCompilerConfiguration {
public static final JpsElementChildRole<JpsJavaCompilerConfiguration> ROLE = JpsElementChildRoleBase.create("compiler configuration");
private boolean myAddNotNullAssertions = true;
private boolean myClearOutputDirectoryOnRebuild;
private boolean myClearOutputDirectoryOnRebuild = true;
private JpsCompilerExcludes myCompilerExcludes = new JpsCompilerExcludesImpl();
private List<String> myResourcePatterns = new ArrayList<String>();
private List<ProcessorConfigProfile> myAnnotationProcessingProfiles = new ArrayList<ProcessorConfigProfile>();
@@ -29,6 +29,7 @@ import org.jetbrains.jps.indices.ModuleExcludeIndex;
import org.jetbrains.jps.model.JpsModel;
import org.jetbrains.jps.model.module.JpsModule;
import java.io.File;
import java.util.*;
/**
@@ -105,7 +106,13 @@ public class AndroidProjectBuildTarget extends BuildTarget<BuildRootDescriptor>
public String getPresentableName() {
return "Android " + myKind.name();
}
@Nullable
@Override
public File getOutputDir(BuildDataPaths paths) {
return null;
}
public static class TargetType extends BuildTargetType<AndroidProjectBuildTarget> {
public static final TargetType INSTANCE = new TargetType();
@@ -189,7 +189,7 @@ public class GroovyBuilder extends ModuleLevelBuilder {
private static Map<ModuleBuildTarget, String> getCanonicalModuleOutputs(CompileContext context, ModuleChunk chunk) {
Map<ModuleBuildTarget, String> finalOutputs = new HashMap<ModuleBuildTarget, String>();
for (ModuleBuildTarget target : chunk.getTargets()) {
File moduleOutputDir = context.getProjectPaths().getModuleOutputDir(target.getModule(), target.isTests());
File moduleOutputDir = target.getOutputDir();
if (moduleOutputDir == null) {
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Output directory not specified for module " + target.getModuleName()));
return null;