external compiler: extracted interface to process dirty files

This commit is contained in:
nik
2012-10-02 14:57:59 +04:00
parent c48515a81d
commit 5b775b56ea
21 changed files with 192 additions and 170 deletions
@@ -261,7 +261,7 @@ public abstract class BaseCompilerTestCase extends ModuleTestCase {
return set;
}
protected void changeFile(VirtualFile file) throws Exception {
protected void changeFile(VirtualFile file) {
changeFile(file, null);
}
@@ -1,6 +1,7 @@
package org.jetbrains.jps.builders;
import java.io.File;
import java.io.FileFilter;
/**
* @author nik
@@ -11,4 +12,6 @@ public abstract class BuildRootDescriptor {
public abstract File getRootFile();
public abstract BuildTarget<?> getTarget();
public abstract FileFilter createFileFilter();
}
@@ -6,6 +6,7 @@ import org.jetbrains.jps.incremental.CompileContext;
import org.jetbrains.jps.incremental.fs.RootDescriptor;
import java.io.File;
import java.io.FileFilter;
import java.util.Collection;
import java.util.List;
@@ -21,7 +22,7 @@ public interface BuildRootIndex {
<R extends BuildRootDescriptor> List<R> getTempTargetRoots(@NotNull BuildTarget<R> target, @NotNull CompileContext context);
@NotNull
<R extends BuildRootDescriptor> List<R> getRootDescriptors(@NotNull File root, @NotNull Collection<? extends BuildTargetType<? extends BuildTarget<R>>> types,
<R extends BuildRootDescriptor> List<R> getRootDescriptors(@NotNull File root, @Nullable Collection<? extends BuildTargetType<? extends BuildTarget<R>>> types,
@Nullable CompileContext context);
<R extends BuildRootDescriptor> void associateTempRoot(@NotNull CompileContext context, @NotNull BuildTarget<R> target, @NotNull R root);
@@ -35,9 +36,15 @@ public interface BuildRootIndex {
@NotNull
<R extends BuildRootDescriptor> Collection<R> findAllParentDescriptors(@NotNull File file,
@NotNull Collection<? extends BuildTargetType<? extends BuildTarget<R>>> types,
@Nullable Collection<? extends BuildTargetType<? extends BuildTarget<R>>> types,
@Nullable CompileContext context);
@NotNull
<R extends BuildRootDescriptor> Collection<R> findAllParentDescriptors(@NotNull File file, @Nullable CompileContext context);
@Nullable
RootDescriptor getModuleAndRoot(@Nullable CompileContext context, File file);
@NotNull
FileFilter getRootFilter(@NotNull BuildRootDescriptor descriptor);
}
@@ -0,0 +1,12 @@
package org.jetbrains.jps.builders;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
/**
* @author nik
*/
public interface DirtyFilesHolder<R extends BuildRootDescriptor, T extends BuildTarget<R>> {
void processDirtyFiles(@NotNull FileProcessor<R, T> processor) throws IOException;
}
@@ -1,4 +1,4 @@
package org.jetbrains.jps.incremental;
package org.jetbrains.jps.builders;
import java.io.File;
import java.io.IOException;
@@ -7,9 +7,9 @@ import java.io.IOException;
* @author Eugene Zhuravlev
* Date: 9/21/11
*/
public interface FileProcessor {
public interface FileProcessor<R extends BuildRootDescriptor, T extends BuildTarget<R>> {
/**
* @return true if processing should continue, false if should stop
*/
boolean apply(ModuleBuildTarget target, File file, String sourceRoot) throws IOException;
boolean apply(T target, File file, R root) throws IOException;
}
@@ -3,6 +3,7 @@ package org.jetbrains.jps.builders.impl;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ConcurrentHashMap;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -17,7 +18,9 @@ import org.jetbrains.jps.model.JpsModel;
import org.jetbrains.jps.service.JpsServiceManager;
import java.io.File;
import java.io.FileFilter;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
/**
* @author nik
@@ -27,6 +30,7 @@ public class BuildRootIndexImpl implements BuildRootIndex {
private static final Key<Map<BuildTarget<?>, List<? extends BuildRootDescriptor>>> TEMP_TARGET_ROOTS_MAP = Key.create("_module_to_root_map");
private HashMap<BuildTarget<?>, List<? extends BuildRootDescriptor>> myRootsByTarget;
private THashMap<File,List<BuildRootDescriptor>> myRootToDescriptor;
private ConcurrentMap<BuildRootDescriptor, FileFilter> myFileFilters;
public BuildRootIndexImpl(BuildTargetIndex targetIndex,
JpsModel model,
@@ -34,6 +38,7 @@ public class BuildRootIndexImpl implements BuildRootIndex {
File dataStorageRoot, final IgnoredFileIndex ignoredFileIndex) {
myRootsByTarget = new HashMap<BuildTarget<?>, List<? extends BuildRootDescriptor>>();
myRootToDescriptor = new THashMap<File, List<BuildRootDescriptor>>(FileUtil.FILE_HASHING_STRATEGY);
myFileFilters = new ConcurrentHashMap<BuildRootDescriptor, FileFilter>();
final Iterable<AdditionalRootsProviderService> rootsProviders = JpsServiceManager.getInstance().getExtensions(AdditionalRootsProviderService.class);
for (BuildTargetType<?> targetType : BuilderRegistry.getInstance().getTargetTypes()) {
for (BuildTarget<?> target : targetIndex.getAllTargets(targetType)) {
@@ -73,13 +78,13 @@ public class BuildRootIndexImpl implements BuildRootIndex {
@NotNull
@Override
public <R extends BuildRootDescriptor> List<R> getRootDescriptors(@NotNull File root,
@NotNull Collection<? extends BuildTargetType<? extends BuildTarget<R>>> types,
@Nullable Collection<? extends BuildTargetType<? extends BuildTarget<R>>> types,
@Nullable CompileContext context) {
List<BuildRootDescriptor> descriptors = myRootToDescriptor.get(root);
List<R> result = new SmartList<R>();
if (descriptors != null) {
for (BuildRootDescriptor descriptor : descriptors) {
if (types.contains(descriptor.getTarget().getTargetType())) {
if (types == null || types.contains(descriptor.getTarget().getTargetType())) {
//noinspection unchecked
result.add((R)descriptor);
}
@@ -89,7 +94,7 @@ public class BuildRootIndexImpl implements BuildRootIndex {
final Map<File, BuildRootDescriptor> contextMap = ROOT_DESCRIPTOR_MAP.get(context);
if (contextMap != null) {
BuildRootDescriptor descriptor = contextMap.get(root);
if (descriptor != null && types.contains(descriptor.getTarget().getTargetType())) {
if (descriptor != null && (types == null || types.contains(descriptor.getTarget().getTargetType()))) {
//noinspection unchecked
result.add((R)descriptor);
}
@@ -172,10 +177,12 @@ public class BuildRootIndexImpl implements BuildRootIndex {
return null;
}
@Override
@NotNull
public <R extends BuildRootDescriptor> Collection<R> findAllParentDescriptors(@NotNull File file,
@NotNull Collection<? extends BuildTargetType<? extends BuildTarget<R>>> types,
@Nullable Collection<? extends BuildTargetType<? extends BuildTarget<R>>> types,
@Nullable CompileContext context) {
File current = file;
Collection<R> result = null;
@@ -195,6 +202,12 @@ public class BuildRootIndexImpl implements BuildRootIndex {
return result != null ? result : Collections.<R>emptyList();
}
@NotNull
@Override
public <R extends BuildRootDescriptor> Collection<R> findAllParentDescriptors(@NotNull File file, @Nullable CompileContext context) {
return findAllParentDescriptors(file, null, context);
}
@Override
@NotNull
public Collection<? extends BuildRootDescriptor> clearTempRoots(@NotNull CompileContext context) {
@@ -213,4 +226,15 @@ public class BuildRootIndexImpl implements BuildRootIndex {
public RootDescriptor getModuleAndRoot(@Nullable CompileContext context, File file) {
return findParentDescriptor(file, JavaModuleBuildTargetType.ALL_TYPES, context);
}
@NotNull
@Override
public FileFilter getRootFilter(@NotNull BuildRootDescriptor descriptor) {
FileFilter filter = myFileFilters.get(descriptor);
if (filter == null) {
filter = descriptor.createFileFilter();
myFileFilters.put(descriptor, filter);
}
return filter;
}
}
@@ -7,24 +7,24 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.api.BuildType;
import org.jetbrains.jps.api.CanceledStatus;
import org.jetbrains.jps.api.GlobalOptions;
import org.jetbrains.jps.builders.BuildRootDescriptor;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.builders.BuildTargetLoader;
import org.jetbrains.jps.builders.BuildTargetType;
import org.jetbrains.jps.builders.impl.BuildRootIndexImpl;
import org.jetbrains.jps.builders.impl.BuildTargetIndexImpl;
import org.jetbrains.jps.indices.impl.IgnoredFileIndexImpl;
import org.jetbrains.jps.indices.impl.ModuleExcludeIndexImpl;
import org.jetbrains.jps.indices.ModuleExcludeIndex;
import org.jetbrains.jps.builders.java.dependencyView.Callbacks;
import org.jetbrains.jps.incremental.*;
import org.jetbrains.jps.incremental.fs.BuildFSState;
import org.jetbrains.jps.incremental.fs.RootDescriptor;
import org.jetbrains.jps.incremental.messages.BuildMessage;
import org.jetbrains.jps.incremental.messages.CompilerMessage;
import org.jetbrains.jps.incremental.storage.BuildDataManager;
import org.jetbrains.jps.incremental.storage.BuildTargetsState;
import org.jetbrains.jps.incremental.storage.ProjectTimestamps;
import org.jetbrains.jps.incremental.storage.Timestamps;
import org.jetbrains.jps.indices.ModuleExcludeIndex;
import org.jetbrains.jps.indices.impl.IgnoredFileIndexImpl;
import org.jetbrains.jps.indices.impl.ModuleExcludeIndexImpl;
import org.jetbrains.jps.model.JpsModel;
import java.io.File;
@@ -171,16 +171,16 @@ public class BuildRunner {
files = new HashMap<BuildTarget<?>, Set<File>>();
for (String path : paths) {
final File file = new File(path);
final RootDescriptor rd = pd.getBuildRootIndex().getModuleAndRoot(null, file);
if (rd != null) {
Set<File> fileSet = files.get(rd.target);
final Collection<BuildRootDescriptor> descriptors = pd.getBuildRootIndex().findAllParentDescriptors(file, null);
for (BuildRootDescriptor descriptor : descriptors) {
Set<File> fileSet = files.get(descriptor.getTarget());
if (fileSet == null) {
fileSet = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
files.put(rd.target, fileSet);
files.put(descriptor.getTarget(), fileSet);
}
fileSet.add(file);
if (buildType == BuildType.FORCED_COMPILATION) {
pd.fsState.markDirty(null, file, rd, timestamps);
pd.fsState.markDirty(null, file, descriptor, timestamps);
}
}
}
@@ -11,16 +11,14 @@ import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.Channels;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.api.*;
import org.jetbrains.jps.builders.BuildRootDescriptor;
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
import org.jetbrains.jps.builders.java.dependencyView.Callbacks;
import org.jetbrains.jps.incremental.MessageHandler;
import org.jetbrains.jps.incremental.ModuleBuildTarget;
import org.jetbrains.jps.incremental.Utils;
import org.jetbrains.jps.incremental.artifacts.ArtifactBuildTargetType;
import org.jetbrains.jps.incremental.artifacts.instructions.ArtifactRootDescriptor;
import org.jetbrains.jps.incremental.fs.BuildFSState;
import org.jetbrains.jps.incremental.fs.FSState;
import org.jetbrains.jps.incremental.fs.RootDescriptor;
import org.jetbrains.jps.incremental.messages.*;
import org.jetbrains.jps.incremental.storage.Timestamps;
import org.jetbrains.jps.model.module.JpsModule;
@@ -263,49 +261,33 @@ final class BuildSession implements Runnable, CanceledStatus {
for (String deleted : event.getDeletedPathsList()) {
final File file = new File(deleted);
final RootDescriptor rd = pd.getBuildRootIndex().getModuleAndRoot(null, file);
if (rd != null) {
Collection<BuildRootDescriptor> descriptor = pd.getBuildRootIndex().findAllParentDescriptors(file, null, null);
if (!descriptor.isEmpty()) {
if (Utils.IS_TEST_MODE) {
LOG.info("Applying deleted path from fs event: " + file.getPath());
}
pd.fsState.registerDeleted(rd.target, file, timestamps);
for (BuildRootDescriptor rootDescriptor : descriptor) {
pd.fsState.registerDeleted(rootDescriptor.getTarget(), file, timestamps);
}
}
else if (Utils.IS_TEST_MODE) {
LOG.info("Skipping deleted path: " + file.getPath());
}
Collection<ArtifactRootDescriptor> descriptor = pd.getBuildRootIndex().findAllParentDescriptors(file, Collections.singletonList(ArtifactBuildTargetType.INSTANCE), null);
if (!descriptor.isEmpty()) {
if (Utils.IS_TEST_MODE) {
LOG.info("Applying deleted path from fs event to artifacts: " + file.getPath());
}
for (ArtifactRootDescriptor rootDescriptor : descriptor)
pd.fsState.registerDeleted(rootDescriptor.getTarget(), file, timestamps);
}
}
for (String changed : event.getChangedPathsList()) {
final File file = new File(changed);
final RootDescriptor rd = pd.getBuildRootIndex().getModuleAndRoot(null, file);
if (rd != null) {
Collection<BuildRootDescriptor> descriptors = pd.getBuildRootIndex().findAllParentDescriptors(file, null, null);
if (!descriptors.isEmpty()) {
if (Utils.IS_TEST_MODE) {
LOG.info("Applying dirty path from fs event: " + file.getPath());
}
pd.fsState.markDirty(null, file, rd, timestamps);
for (BuildRootDescriptor descriptor : descriptors) {
pd.fsState.markDirty(null, file, descriptor, timestamps);
}
}
else if (Utils.IS_TEST_MODE) {
LOG.info("Skipping dirty path: " + file.getPath());
}
Collection<ArtifactRootDescriptor> descriptors = pd.getBuildRootIndex().findAllParentDescriptors(file, Collections
.singletonList(ArtifactBuildTargetType.INSTANCE), null);
if (!descriptors.isEmpty()) {
if (Utils.IS_TEST_MODE) {
LOG.info("Applying dirty path from fs event to artifacts: " + file.getPath());
}
for (ArtifactRootDescriptor descriptor : descriptors) {
pd.fsState.markDirty(null, file, descriptor, timestamps);
}
}
}
}
@@ -8,16 +8,16 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.JpsPathUtil;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.builders.FileProcessor;
import org.jetbrains.jps.builders.impl.BuildTargetChunk;
import org.jetbrains.jps.indices.ModuleExcludeIndex;
import org.jetbrains.jps.cmdline.ProjectDescriptor;
import org.jetbrains.jps.incremental.fs.BuildFSState;
import org.jetbrains.jps.incremental.fs.RootDescriptor;
import org.jetbrains.jps.incremental.storage.Timestamps;
import org.jetbrains.jps.indices.ModuleExcludeIndex;
import org.jetbrains.jps.model.java.JpsJavaClasspathKind;
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
import org.jetbrains.jps.model.module.JpsModule;
import org.jetbrains.jps.model.module.JpsModuleType;
import java.io.File;
import java.io.IOException;
@@ -114,19 +114,6 @@ public class FSOperations {
processFilesToRecompile(context, chunk, Condition.TRUE, processor);
}
public static void processFilesToRecompile(final CompileContext context,
final ModuleChunk chunk,
final JpsModuleType moduleType,
final FileProcessor processor) throws IOException {
final Condition<JpsModule> moduleFilter = new Condition<JpsModule>() {
public boolean value(final JpsModule module) {
return module.getModuleType() == moduleType;
}
};
processFilesToRecompile(context, chunk, moduleFilter, processor);
}
public static void processFilesToRecompile(final CompileContext context,
final ModuleChunk chunk,
final Condition<JpsModule> moduleFilter,
@@ -1,45 +0,0 @@
package org.jetbrains.jps.incremental;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
/**
* @author Eugene Zhuravlev
* Date: 9/21/11
*/
public class FilesCollector implements FileProcessor{
public static FileFilter ALL_FILES = new FileFilter() {
public boolean accept(File pathname) {
return true;
}
};
private final Collection<File> myContainer;
private final FileFilter myFilter;
public FilesCollector() {
this(ALL_FILES);
}
public FilesCollector(FileFilter filter) {
this(new ArrayList<File>(), filter);
}
public FilesCollector(Collection<File> container, FileFilter filter) {
myFilter = filter;
myContainer = container;
}
public Collection<File> getFiles() {
return myContainer;
}
public boolean apply(ModuleBuildTarget target, File file, String sourceRoot) throws IOException {
if (myFilter.accept(file)) {
myContainer.add(file);
}
return true;
}
}
@@ -20,10 +20,7 @@ import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.api.CanceledStatus;
import org.jetbrains.jps.api.GlobalOptions;
import org.jetbrains.jps.api.RequestFuture;
import org.jetbrains.jps.builders.BuildRootDescriptor;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.builders.BuildTargetIndex;
import org.jetbrains.jps.builders.BuildTargetType;
import org.jetbrains.jps.builders.*;
import org.jetbrains.jps.builders.impl.BuildTargetChunk;
import org.jetbrains.jps.builders.java.JavaBuilderUtil;
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
@@ -752,7 +749,7 @@ public class IncProjectBuilder {
}
// return true if changed something, false otherwise
private boolean runModuleLevelBuilders(final CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
private boolean runModuleLevelBuilders(final CompileContext context, final ModuleChunk chunk) throws ProjectBuildException {
boolean doneSomething = false;
boolean rebuildFromScratchRequested = false;
float stageCount = myTotalModuleLevelBuilderCount;
@@ -763,8 +760,14 @@ public class IncProjectBuilder {
nextPassRequired = false;
myProjectDescriptor.fsState.beforeNextRoundStart(context, chunk);
DirtyFilesHolder<RootDescriptor, ModuleBuildTarget> dirtyFilesHolder = new DirtyFilesHolder<RootDescriptor, ModuleBuildTarget>() {
@Override
public void processDirtyFiles(@NotNull FileProcessor<RootDescriptor, ModuleBuildTarget> processor) throws IOException {
FSOperations.processFilesToRecompile(context, chunk, processor);
}
};
if (!context.isProjectRebuild()) {
syncOutputFiles(context, chunk);
syncOutputFiles(context, dirtyFilesHolder);
}
BUILDER_CATEGORY_LOOP:
@@ -778,7 +781,7 @@ public class IncProjectBuilder {
if (context.isMake()) {
processDeletedPaths(context, chunk);
}
final ModuleLevelBuilder.ExitCode buildResult = builder.build(context, chunk);
final ModuleLevelBuilder.ExitCode buildResult = builder.build(context, chunk, dirtyFilesHolder);
doneSomething |= (buildResult != ModuleLevelBuilder.ExitCode.NOTHING_DONE);
@@ -830,16 +833,17 @@ public class IncProjectBuilder {
return doneSomething;
}
private static void syncOutputFiles(final CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
private static void syncOutputFiles(final CompileContext context,
DirtyFilesHolder<RootDescriptor, ModuleBuildTarget> dirtyFilesHolder) throws ProjectBuildException {
final BuildDataManager dataManager = context.getProjectDescriptor().dataManager;
try {
final Collection<String> allOutputs = new LinkedList<String>();
FSOperations.processFilesToRecompile(context, chunk, new FileProcessor() {
dirtyFilesHolder.processDirtyFiles(new FileProcessor<RootDescriptor, ModuleBuildTarget>() {
private final Map<ModuleBuildTarget, SourceToOutputMapping> storageMap = new HashMap<ModuleBuildTarget, SourceToOutputMapping>();
@Override
public boolean apply(ModuleBuildTarget target, File file, String sourceRoot) throws IOException {
public boolean apply(ModuleBuildTarget target, File file, RootDescriptor sourceRoot) throws IOException {
SourceToOutputMapping srcToOut = storageMap.get(target);
if (srcToOut == null) {
srcToOut = dataManager.getSourceToOutputMap(target);
@@ -940,7 +944,7 @@ public class IncProjectBuilder {
}
final Timestamps timestamps = pd.timestamps.getStorage();
for (RootDescriptor rd : pd.getBuildRootIndex().getTargetRoots(target, context)) {
marked |= fsState.markAllUpToDate(context.getProjectDescriptor().jpsProject, context.getScope(), rd, timestamps, context.getCompilationStartStamp());
marked |= fsState.markAllUpToDate(context, rd, timestamps);
}
}
@@ -1,6 +1,8 @@
package org.jetbrains.jps.incremental;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.builders.DirtyFilesHolder;
import org.jetbrains.jps.incremental.fs.RootDescriptor;
import java.io.File;
@@ -21,7 +23,9 @@ public abstract class ModuleLevelBuilder extends Builder {
NOTHING_DONE, OK, ABORT, ADDITIONAL_PASS_REQUIRED, CHUNK_REBUILD_REQUIRED
}
public abstract ExitCode build(CompileContext context, ModuleChunk chunk) throws ProjectBuildException;
public abstract ExitCode build(CompileContext context,
ModuleChunk chunk,
DirtyFilesHolder<RootDescriptor, ModuleBuildTarget> dirtyFilesHolder) throws ProjectBuildException;
public boolean shouldHonorFileEncodingForCompilation(File file) {
return false;
@@ -43,12 +43,13 @@ public class ResourcePatterns {
}
}
public boolean isResourceFile(File file, @NotNull final String srcRoot) {
public boolean isResourceFile(File file, @NotNull final File srcRoot) {
final String name = file.getName();
final String relativePathToParent;
final String parentPath = file.getParent();
if (parentPath != null) {
relativePathToParent = "/" + FileUtil.getRelativePath(srcRoot, FileUtil.toSystemIndependentName(parentPath), '/', SystemInfo.isFileSystemCaseSensitive);
relativePathToParent = "/" + FileUtil.getRelativePath(FileUtil.toSystemIndependentName(srcRoot.getAbsolutePath()),
FileUtil.toSystemIndependentName(parentPath), '/', SystemInfo.isFileSystemCaseSensitive);
}
else {
relativePathToParent = null;
@@ -8,6 +8,7 @@ import org.jetbrains.jps.incremental.artifacts.ArtifactBuildTarget;
import org.jetbrains.jps.incremental.artifacts.ArtifactOutputToSourceMapping;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.PrintWriter;
@@ -15,6 +16,12 @@ import java.io.PrintWriter;
* @author nik
*/
public abstract class ArtifactRootDescriptor extends BuildRootDescriptor {
private static final FileFilter ALL_FILES_FILTER = new FileFilter() {
@Override
public boolean accept(File file) {
return true;
}
};
protected final File myRoot;
private final SourceFileFilter myFilter;
private final int myRootIndex;
@@ -53,6 +60,11 @@ public abstract class ArtifactRootDescriptor extends BuildRootDescriptor {
return myTarget;
}
@Override
public FileFilter createFileFilter() {
return ALL_FILES_FILTER;
}
@NotNull
public final File getRootFile() {
return myRoot;
@@ -3,20 +3,22 @@ package org.jetbrains.jps.incremental.fs;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileSystemUtil;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.builders.BuildRootDescriptor;
import org.jetbrains.jps.builders.BuildRootIndex;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.incremental.*;
import org.jetbrains.jps.builders.FileProcessor;
import org.jetbrains.jps.incremental.CompileContext;
import org.jetbrains.jps.incremental.CompileScope;
import org.jetbrains.jps.incremental.ModuleBuildTarget;
import org.jetbrains.jps.incremental.Utils;
import org.jetbrains.jps.incremental.artifacts.instructions.ArtifactRootDescriptor;
import org.jetbrains.jps.incremental.storage.Timestamps;
import org.jetbrains.jps.model.JpsProject;
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
import org.jetbrains.jps.model.java.compiler.JpsCompilerExcludes;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
@@ -110,23 +112,20 @@ public class BuildFSState extends FSState {
setRoundDelta(CURRENT_ROUND_DELTA_KEY, context, new FilesDelta());
}
public boolean processFilesToRecompile(CompileContext context, final ModuleBuildTarget target, final FileProcessor processor) throws IOException {
public <R extends RootDescriptor, T extends BuildTarget<R>> boolean processFilesToRecompile(CompileContext context, final T target, final FileProcessor<R, T> processor) throws IOException {
final Map<BuildRootDescriptor, Set<File>> data = getSourcesToRecompile(context, target);
JpsProject project = context.getProjectDescriptor().jpsProject;
final JpsCompilerExcludes excludes = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(project).getCompilerExcludes();
BuildRootIndex rootIndex = context.getProjectDescriptor().getBuildRootIndex();
final CompileScope scope = context.getScope();
synchronized (data) {
for (Map.Entry<BuildRootDescriptor, Set<File>> entry : data.entrySet()) {
File rootFile = entry.getKey().getRootFile();
final String rootPath = FileUtil.toSystemIndependentName(rootFile.getPath());
//noinspection unchecked
R root = (R)entry.getKey();
FileFilter filter = rootIndex.getRootFilter(root);
for (File file : entry.getValue()) {
if (!scope.isAffected(target, file)) {
if (!scope.isAffected(target, file) || !filter.accept(file)) {
continue;
}
if (excludes.isExcluded(file)) {
continue;
}
if (!processor.apply(target, file, rootPath)) {
if (!processor.apply(target, file, root)) {
return false;
}
}
@@ -138,18 +137,16 @@ public class BuildFSState extends FSState {
/**
* @return true if marked something, false otherwise
*/
public boolean markAllUpToDate(JpsProject project,
CompileScope scope,
final RootDescriptor rd,
final Timestamps stamps,
final long compilationStartStamp) throws IOException {
public boolean markAllUpToDate(CompileContext context, final RootDescriptor rd, final Timestamps stamps) throws IOException {
boolean marked = false;
final FilesDelta delta = getDelta(rd.target);
final Set<File> files = delta.clearRecompile(rd);
if (files != null) {
final JpsCompilerExcludes excludes = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(project).getCompilerExcludes();
FileFilter filter = context.getProjectDescriptor().getBuildRootIndex().getRootFilter(rd);
CompileScope scope = context.getScope();
final long compilationStartStamp = context.getCompilationStartStamp();
for (File file : files) {
if (!excludes.isExcluded(file)) {
if (filter.accept(file)) {
if (scope.isAffected(rd.target, file)) {
final long stamp = FileSystemUtil.lastModified(file);
if (!rd.isGeneratedSources && stamp > compilationStartStamp) {
@@ -5,8 +5,11 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.builders.BuildRootDescriptor;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.incremental.ModuleBuildTarget;
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
import org.jetbrains.jps.model.java.compiler.JpsCompilerExcludes;
import java.io.File;
import java.io.FileFilter;
/**
* @author Eugene Zhuravlev
@@ -50,4 +53,15 @@ public final class RootDescriptor extends BuildRootDescriptor {
public BuildTarget<?> getTarget() {
return target;
}
@Override
public FileFilter createFileFilter() {
final JpsCompilerExcludes excludes = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(target.getModule().getProject()).getCompilerExcludes();
return new FileFilter() {
@Override
public boolean accept(File file) {
return !excludes.isExcluded(file);
}
};
}
}
@@ -32,6 +32,8 @@ import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.api.GlobalOptions;
import org.jetbrains.jps.api.RequestFuture;
import org.jetbrains.jps.builders.BuildRootIndex;
import org.jetbrains.jps.builders.DirtyFilesHolder;
import org.jetbrains.jps.builders.FileProcessor;
import org.jetbrains.jps.builders.java.JavaBuilderUtil;
import org.jetbrains.jps.builders.java.dependencyView.Callbacks;
import org.jetbrains.jps.builders.java.dependencyView.Mappings;
@@ -168,13 +170,15 @@ public class JavaBuilder extends ModuleLevelBuilder {
return "Java Builder";
}
public ExitCode build(final CompileContext context, final ModuleChunk chunk) throws ProjectBuildException {
public ExitCode build(final CompileContext context,
final ModuleChunk chunk,
DirtyFilesHolder<RootDescriptor, ModuleBuildTarget> dirtyFilesHolder) throws ProjectBuildException {
try {
final Set<File> filesToCompile = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
final Set<File> formsToCompile = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
FSOperations.processFilesToRecompile(context, chunk, new FileProcessor() {
public boolean apply(ModuleBuildTarget target, File file, String sourceRoot) throws IOException {
dirtyFilesHolder.processDirtyFiles(new FileProcessor<RootDescriptor, ModuleBuildTarget>() {
public boolean apply(ModuleBuildTarget target, File file, RootDescriptor sourceRoot) throws IOException {
if (JAVA_SOURCES_FILTER.accept(file)) {
filesToCompile.add(file);
}
@@ -6,8 +6,11 @@ import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.jps.JpsPathUtil;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.builders.DirtyFilesHolder;
import org.jetbrains.jps.builders.FileProcessor;
import org.jetbrains.jps.builders.storage.SourceToOutputMapping;
import org.jetbrains.jps.incremental.*;
import org.jetbrains.jps.incremental.fs.RootDescriptor;
import org.jetbrains.jps.incremental.messages.BuildMessage;
import org.jetbrains.jps.incremental.messages.CompilerMessage;
import org.jetbrains.jps.incremental.messages.ProgressMessage;
@@ -44,7 +47,9 @@ public class ResourcesBuilder extends ModuleLevelBuilder {
}
}
public ExitCode build(final CompileContext context, final ModuleChunk chunk) throws ProjectBuildException {
public ExitCode build(final CompileContext context,
final ModuleChunk chunk,
DirtyFilesHolder<RootDescriptor, ModuleBuildTarget> dirtyFilesHolder) throws ProjectBuildException {
final ResourcePatterns patterns = ResourcePatterns.KEY.get(context);
assert patterns != null;
try {
@@ -61,9 +66,9 @@ public class ResourcesBuilder extends ModuleLevelBuilder {
}
};
FSOperations.processFilesToRecompile(context, chunk, moduleFilter, new FileProcessor() {
public boolean apply(final ModuleBuildTarget target, final File file, final String sourceRoot) throws IOException {
if (patterns.isResourceFile(file, sourceRoot)) {
FSOperations.processFilesToRecompile(context, chunk, moduleFilter, new FileProcessor<RootDescriptor, ModuleBuildTarget>() {
public boolean apply(final ModuleBuildTarget target, final File file, final RootDescriptor sourceRoot) throws IOException {
if (patterns.isResourceFile(file, sourceRoot.root)) {
try {
context.processMessage(new ProgressMessage("Copying " + file.getPath()));
doneSomething.set(true);
@@ -94,14 +99,15 @@ public class ResourcesBuilder extends ModuleLevelBuilder {
private static void copyResource(CompileContext context,
JpsModule module,
File file,
String sourceRoot,
RootDescriptor sourceRoot,
final SourceToOutputMapping outputToSourceMapping, final boolean tests) throws IOException {
final String outputRootUrl = JpsJavaExtensionService.getInstance().getOutputUrl(module, tests);
if (outputRootUrl == null) {
return;
}
final String relativePath = FileUtil.getRelativePath(sourceRoot, FileUtil.toSystemIndependentName(file.getPath()), '/');
final String prefix = JpsJavaExtensionService.getInstance().getSourcePrefix(module, JpsPathUtil.pathToUrl(sourceRoot));
String rootPath = FileUtil.toSystemIndependentName(sourceRoot.root.getAbsolutePath());
final String relativePath = FileUtil.getRelativePath(rootPath, FileUtil.toSystemIndependentName(file.getPath()), '/');
final String prefix = JpsJavaExtensionService.getInstance().getSourcePrefix(module, JpsPathUtil.pathToUrl(rootPath));
final StringBuilder targetPath = new StringBuilder();
targetPath.append(JpsPathUtil.urlToPath(outputRootUrl));
@@ -7,10 +7,9 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.android.model.JpsAndroidModuleExtension;
import org.jetbrains.jps.incremental.BuilderCategory;
import org.jetbrains.jps.incremental.CompileContext;
import org.jetbrains.jps.incremental.ModuleLevelBuilder;
import org.jetbrains.jps.incremental.ProjectBuildException;
import org.jetbrains.jps.builders.DirtyFilesHolder;
import org.jetbrains.jps.incremental.*;
import org.jetbrains.jps.incremental.fs.RootDescriptor;
import org.jetbrains.jps.incremental.messages.ProgressMessage;
import org.jetbrains.jps.model.module.JpsModule;
@@ -29,7 +28,7 @@ public class AndroidLibraryPackagingBuilder extends ModuleLevelBuilder {
}
@Override
public ExitCode build(CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
public ExitCode build(CompileContext context, ModuleChunk chunk, DirtyFilesHolder<RootDescriptor, ModuleBuildTarget> dirtyFilesHolder) throws ProjectBuildException {
if (chunk.containsTests() || !AndroidJpsUtil.containsAndroidFacet(chunk) || AndroidJpsUtil.isLightBuild(context)) {
return ExitCode.NOTHING_DONE;
}
@@ -21,6 +21,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.android.model.JpsAndroidModuleExtension;
import org.jetbrains.jps.builders.DirtyFilesHolder;
import org.jetbrains.jps.builders.FileProcessor;
import org.jetbrains.jps.builders.storage.SourceToOutputMapping;
import org.jetbrains.jps.incremental.*;
import org.jetbrains.jps.incremental.fs.RootDescriptor;
@@ -71,20 +73,24 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder {
}
@Override
public ModuleLevelBuilder.ExitCode build(CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
public ModuleLevelBuilder.ExitCode build(CompileContext context,
ModuleChunk chunk,
DirtyFilesHolder<RootDescriptor, ModuleBuildTarget> dirtyFilesHolder) throws ProjectBuildException {
if (chunk.containsTests() || !AndroidJpsUtil.containsAndroidFacet(chunk)) {
return ExitCode.NOTHING_DONE;
}
try {
return doBuild(context, chunk);
return doBuild(context, chunk, dirtyFilesHolder);
}
catch (Exception e) {
return AndroidJpsUtil.handleException(context, e, BUILDER_NAME);
}
}
private static ModuleLevelBuilder.ExitCode doBuild(CompileContext context, ModuleChunk chunk) throws IOException {
private static ModuleLevelBuilder.ExitCode doBuild(CompileContext context,
ModuleChunk chunk,
DirtyFilesHolder<RootDescriptor, ModuleBuildTarget> dirtyFilesHolder) throws IOException {
final Map<JpsModule, MyModuleData> moduleDataMap = computeModuleDatas(chunk.getModules(), context);
if (moduleDataMap == null || moduleDataMap.size() == 0) {
return ExitCode.ABORT;
@@ -104,9 +110,9 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder {
final Map<File, ModuleBuildTarget> idlFilesToCompile = new HashMap<File, ModuleBuildTarget>();
final Map<File, ModuleBuildTarget> rsFilesToCompile = new HashMap<File, ModuleBuildTarget>();
FSOperations.processFilesToRecompile(context, chunk, new FileProcessor() {
dirtyFilesHolder.processDirtyFiles(new FileProcessor<RootDescriptor, ModuleBuildTarget>() {
@Override
public boolean apply(ModuleBuildTarget target, File file, String sourceRoot) throws IOException {
public boolean apply(ModuleBuildTarget target, File file, RootDescriptor sourceRoot) throws IOException {
final JpsAndroidModuleExtension extension = AndroidJpsUtil.getExtension(target.getModule());
if (extension == null) {
@@ -11,6 +11,8 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.ClassReader;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.builders.BuildRootIndex;
import org.jetbrains.jps.builders.DirtyFilesHolder;
import org.jetbrains.jps.builders.FileProcessor;
import org.jetbrains.jps.builders.java.JavaBuilderUtil;
import org.jetbrains.jps.builders.java.dependencyView.Callbacks;
import org.jetbrains.jps.builders.java.dependencyView.Mappings;
@@ -63,9 +65,11 @@ public class GroovyBuilder extends ModuleLevelBuilder {
return myBuilderName;
}
public ModuleLevelBuilder.ExitCode build(final CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
public ModuleLevelBuilder.ExitCode build(final CompileContext context,
ModuleChunk chunk,
DirtyFilesHolder<RootDescriptor, ModuleBuildTarget> dirtyFilesHolder) throws ProjectBuildException {
try {
final List<File> toCompile = collectChangedFiles(context, chunk);
final List<File> toCompile = collectChangedFiles(context, dirtyFilesHolder);
if (toCompile.isEmpty()) {
return ExitCode.NOTHING_DONE;
}
@@ -233,14 +237,15 @@ public class GroovyBuilder extends ModuleLevelBuilder {
return isGroovyFile(file.getAbsolutePath());
}
private static List<File> collectChangedFiles(CompileContext context, ModuleChunk chunk) throws IOException {
private static List<File> collectChangedFiles(CompileContext context,
DirtyFilesHolder<RootDescriptor, ModuleBuildTarget> dirtyFilesHolder) throws IOException {
final ResourcePatterns patterns = ResourcePatterns.KEY.get(context);
assert patterns != null;
final List<File> toCompile = new ArrayList<File>();
FSOperations.processFilesToRecompile(context, chunk, new FileProcessor() {
public boolean apply(ModuleBuildTarget target, File file, String sourceRoot) throws IOException {
dirtyFilesHolder.processDirtyFiles(new FileProcessor<RootDescriptor, ModuleBuildTarget>() {
public boolean apply(ModuleBuildTarget target, File file, RootDescriptor sourceRoot) throws IOException {
final String path = file.getPath();
if (isGroovyFile(path) && !patterns.isResourceFile(file, sourceRoot)) { //todo file type check
if (isGroovyFile(path) && !patterns.isResourceFile(file, sourceRoot.root)) { //todo file type check
toCompile.add(file);
}
return true;