mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
external artifact builder: get list of changed files from IDEA instead of scanning fs on each build
This commit is contained in:
@@ -20,6 +20,8 @@ import org.jetbrains.jps.api.*;
|
||||
import org.jetbrains.jps.idea.IdeaProjectLoader;
|
||||
import org.jetbrains.jps.idea.SystemOutErrorReporter;
|
||||
import org.jetbrains.jps.incremental.*;
|
||||
import org.jetbrains.jps.incremental.artifacts.ArtifactSourceTimestampStorage;
|
||||
import org.jetbrains.jps.incremental.artifacts.instructions.ArtifactRootDescriptor;
|
||||
import org.jetbrains.jps.incremental.fs.BuildFSState;
|
||||
import org.jetbrains.jps.incremental.fs.RootDescriptor;
|
||||
import org.jetbrains.jps.incremental.messages.*;
|
||||
@@ -180,9 +182,7 @@ final class BuildSession implements Runnable, CanceledStatus {
|
||||
|
||||
try {
|
||||
final boolean shouldApplyEvent = loadFsState(fsState, dataStorageRoot, myInitialFSDelta);
|
||||
if (shouldApplyEvent && buildType == BuildType.MAKE && !containsChanges(myInitialFSDelta) && !fsState.hasWorkToDo()
|
||||
&& artifacts.isEmpty()//todo[nik] currently changes in artifacts source files aren't registered in the delta
|
||||
) {
|
||||
if (shouldApplyEvent && buildType == BuildType.MAKE && !containsChanges(myInitialFSDelta) && !fsState.hasWorkToDo()) {
|
||||
applyFSEvent(null, myInitialFSDelta);
|
||||
return;
|
||||
}
|
||||
@@ -333,6 +333,7 @@ final class BuildSession implements Runnable, CanceledStatus {
|
||||
|
||||
if (pd != null) {
|
||||
final Timestamps timestamps = pd.timestamps.getStorage();
|
||||
ArtifactSourceTimestampStorage artifactTimestamps = pd.dataManager.getArtifactsBuildData().getTimestampStorage();
|
||||
|
||||
for (String deleted : event.getDeletedPathsList()) {
|
||||
final File file = new File(deleted);
|
||||
@@ -343,10 +344,18 @@ final class BuildSession implements Runnable, CanceledStatus {
|
||||
}
|
||||
pd.fsState.registerDeleted(rd.module, file, rd.isTestRoot, timestamps);
|
||||
}
|
||||
else {
|
||||
else if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Skipping deleted path: " + file.getPath());
|
||||
}
|
||||
|
||||
Collection<ArtifactRootDescriptor> descriptor = pd.getArtifactRootsIndex().getDescriptors(file);
|
||||
if (!descriptor.isEmpty()) {
|
||||
if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Skipping deleted path: " + file.getPath());
|
||||
LOG.info("Applying deleted path from fs event to artifacts: " + file.getPath());
|
||||
}
|
||||
for (ArtifactRootDescriptor rootDescriptor : descriptor)
|
||||
pd.fsState.registerDeleted(rootDescriptor.getArtifactName(), rootDescriptor.getRootId().getArtifactId(), deleted,
|
||||
artifactTimestamps);
|
||||
}
|
||||
}
|
||||
for (String changed : event.getChangedPathsList()) {
|
||||
@@ -358,9 +367,17 @@ final class BuildSession implements Runnable, CanceledStatus {
|
||||
}
|
||||
pd.fsState.markDirty(null, file, rd, timestamps);
|
||||
}
|
||||
else {
|
||||
else if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Skipping dirty path: " + file.getPath());
|
||||
}
|
||||
|
||||
Collection<ArtifactRootDescriptor> descriptors = pd.getArtifactRootsIndex().getDescriptors(file);
|
||||
if (!descriptors.isEmpty()) {
|
||||
if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Skipping dirty path: " + file.getPath());
|
||||
LOG.info("Applying dirty path from fs event to artifacts: " + file.getPath());
|
||||
}
|
||||
for (ArtifactRootDescriptor descriptor : descriptors) {
|
||||
pd.fsState.markDirty(descriptor, changed, artifactTimestamps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.jetbrains.jps.Project;
|
||||
import org.jetbrains.jps.incremental.BuildLoggingManager;
|
||||
import org.jetbrains.jps.incremental.CompilerEncodingConfiguration;
|
||||
import org.jetbrains.jps.incremental.ModuleRootsIndex;
|
||||
import org.jetbrains.jps.incremental.artifacts.ArtifactRootsIndex;
|
||||
import org.jetbrains.jps.incremental.fs.BuildFSState;
|
||||
import org.jetbrains.jps.incremental.storage.BuildDataManager;
|
||||
import org.jetbrains.jps.incremental.storage.ProjectTimestamps;
|
||||
@@ -31,6 +32,7 @@ public final class ProjectDescriptor {
|
||||
public final BuildDataManager dataManager;
|
||||
private final BuildLoggingManager myLoggingManager;
|
||||
public ModuleRootsIndex rootsIndex;
|
||||
private final ArtifactRootsIndex myArtifactRootsIndex;
|
||||
private int myUseCounter = 1;
|
||||
private Set<JpsTypedLibrary<JpsSdkProperties>> myProjectJavaSdks;
|
||||
private CompilerEncodingConfiguration myEncodingConfiguration;
|
||||
@@ -48,7 +50,8 @@ public final class ProjectDescriptor {
|
||||
this.timestamps = timestamps;
|
||||
this.dataManager = dataManager;
|
||||
myLoggingManager = loggingManager;
|
||||
this.rootsIndex = new ModuleRootsIndex(jpsProject, dataManager);
|
||||
rootsIndex = new ModuleRootsIndex(jpsProject, dataManager);
|
||||
myArtifactRootsIndex = new ArtifactRootsIndex(jpsModel, project, dataManager, rootsIndex);
|
||||
myProjectJavaSdks = new HashSet<JpsTypedLibrary<JpsSdkProperties>>();
|
||||
myEncodingConfiguration = new CompilerEncodingConfiguration(project.getFilePathToCharset(), project.getProjectCharset(), rootsIndex);
|
||||
for (JpsModule module : jpsProject.getModules()) {
|
||||
@@ -73,6 +76,10 @@ public final class ProjectDescriptor {
|
||||
return myLoggingManager;
|
||||
}
|
||||
|
||||
public ArtifactRootsIndex getArtifactRootsIndex() {
|
||||
return myArtifactRootsIndex;
|
||||
}
|
||||
|
||||
public synchronized void incUsageCounter() {
|
||||
myUseCounter++;
|
||||
}
|
||||
|
||||
@@ -13,16 +13,12 @@ import java.util.Set;
|
||||
* Date: 9/17/11
|
||||
*/
|
||||
public class AllProjectScope extends CompileScope {
|
||||
|
||||
private final boolean myIsForcedCompilation;
|
||||
|
||||
public AllProjectScope(Project project, JpsProject jpsProject, Set<JpsArtifact> artifacts, boolean forcedCompilation) {
|
||||
super(project, jpsProject, artifacts);
|
||||
myIsForcedCompilation = forcedCompilation;
|
||||
super(project, jpsProject, artifacts, forcedCompilation);
|
||||
}
|
||||
|
||||
public boolean isRecompilationForced(@NotNull String moduleName) {
|
||||
return myIsForcedCompilation;
|
||||
return myForcedCompilation;
|
||||
}
|
||||
|
||||
public boolean isAffected(@NotNull String moduleName) {
|
||||
|
||||
@@ -15,4 +15,6 @@ public interface BuildListener extends EventListener{
|
||||
* @param paths collection of pairs [output root->relative path to generated file]
|
||||
*/
|
||||
void filesGenerated(Collection<Pair<String, String>> paths);
|
||||
|
||||
void filesDeleted(Collection<String> paths);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,6 @@ public abstract class Builder {
|
||||
public void buildStarted(CompileContext context) {
|
||||
}
|
||||
|
||||
public void buildFinished(CompileContext ICompileContext) {
|
||||
public void buildFinished(CompileContext context) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.jps.*;
|
||||
import org.jetbrains.jps.api.CanceledStatus;
|
||||
import org.jetbrains.jps.cmdline.ProjectDescriptor;
|
||||
import org.jetbrains.jps.incremental.messages.BuildMessage;
|
||||
import org.jetbrains.jps.incremental.messages.FileDeletedEvent;
|
||||
import org.jetbrains.jps.incremental.messages.FileGeneratedEvent;
|
||||
import org.jetbrains.jps.incremental.messages.ProgressMessage;
|
||||
import org.jetbrains.jps.model.module.JpsModule;
|
||||
@@ -209,6 +210,10 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon
|
||||
myListeners.getMulticaster().filesGenerated(paths);
|
||||
}
|
||||
}
|
||||
else if (msg instanceof FileDeletedEvent) {
|
||||
Collection<String> paths = ((FileDeletedEvent)msg).getFilePaths();
|
||||
myListeners.getMulticaster().filesDeleted(paths);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,17 +19,23 @@ public abstract class CompileScope {
|
||||
private final Project myProject;
|
||||
private final JpsProject myJpsProject;
|
||||
private final Set<JpsArtifact> myArtifacts;
|
||||
protected final boolean myForcedCompilation;
|
||||
|
||||
protected CompileScope(@NotNull Project project, JpsProject jpsProject, Set<JpsArtifact> artifacts) {
|
||||
protected CompileScope(@NotNull Project project, JpsProject jpsProject, Set<JpsArtifact> artifacts, boolean forcedCompilation) {
|
||||
myProject = project;
|
||||
myJpsProject = jpsProject;
|
||||
myArtifacts = artifacts;
|
||||
myForcedCompilation = forcedCompilation;
|
||||
}
|
||||
|
||||
public boolean isAffected(JpsArtifact artifact) {
|
||||
return myArtifacts.contains(artifact);
|
||||
}
|
||||
|
||||
public boolean isRecompilationForced(JpsArtifact artifact) {
|
||||
return myForcedCompilation && myArtifacts.contains(artifact);
|
||||
}
|
||||
|
||||
public abstract boolean isAffected(String moduleName, @NotNull File file);
|
||||
|
||||
public abstract boolean isAffected(@NotNull String moduleName);
|
||||
|
||||
@@ -21,10 +21,7 @@ import org.jetbrains.jps.incremental.fs.RootDescriptor;
|
||||
import org.jetbrains.jps.incremental.java.ExternalJavacDescriptor;
|
||||
import org.jetbrains.jps.incremental.java.JavaBuilder;
|
||||
import org.jetbrains.jps.incremental.java.JavaBuilderLogger;
|
||||
import org.jetbrains.jps.incremental.messages.BuildMessage;
|
||||
import org.jetbrains.jps.incremental.messages.CompilerMessage;
|
||||
import org.jetbrains.jps.incremental.messages.ProgressMessage;
|
||||
import org.jetbrains.jps.incremental.messages.UptoDateFilesSavedEvent;
|
||||
import org.jetbrains.jps.incremental.messages.*;
|
||||
import org.jetbrains.jps.incremental.storage.*;
|
||||
import org.jetbrains.jps.model.java.JpsJavaClasspathKind;
|
||||
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
|
||||
@@ -300,10 +297,11 @@ public class IncProjectBuilder {
|
||||
final SourceToOutputMapping map = context.getProjectDescriptor().dataManager.getSourceToOutputMap(moduleName, forTests);
|
||||
for (String srcPath : map.getKeys()) {
|
||||
final Collection<String> outs = map.getState(srcPath);
|
||||
if (outs != null) {
|
||||
if (outs != null && !outs.isEmpty()) {
|
||||
for (String out : outs) {
|
||||
new File(out).delete();
|
||||
}
|
||||
context.processMessage(new FileDeletedEvent(outs));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -655,27 +653,26 @@ public class IncProjectBuilder {
|
||||
// deleting outputs corresponding to non-existing source
|
||||
final Collection<String> outputs = sourceToOutputStorage.getState(deletedSource);
|
||||
|
||||
if (outputs != null) {
|
||||
if (outputs != null && !outputs.isEmpty()) {
|
||||
final JavaBuilderLogger logger = context.getLoggingManager().getJavaBuilderLogger();
|
||||
if (logger.isEnabled()) {
|
||||
if (outputs.size() > 0) {
|
||||
final String[] buffer = new String[outputs.size()];
|
||||
int i = 0;
|
||||
for (final String o : outputs) {
|
||||
buffer[i++] = o;
|
||||
}
|
||||
Arrays.sort(buffer);
|
||||
logger.log("Cleaning output files:");
|
||||
for (final String o : buffer) {
|
||||
logger.log(o);
|
||||
}
|
||||
logger.log("End of files");
|
||||
final String[] buffer = new String[outputs.size()];
|
||||
int i = 0;
|
||||
for (final String o : outputs) {
|
||||
buffer[i++] = o;
|
||||
}
|
||||
Arrays.sort(buffer);
|
||||
logger.log("Cleaning output files:");
|
||||
for (final String o : buffer) {
|
||||
logger.log(o);
|
||||
}
|
||||
logger.log("End of files");
|
||||
}
|
||||
|
||||
for (String output : outputs) {
|
||||
new File(output).delete();
|
||||
}
|
||||
context.processMessage(new FileDeletedEvent(outputs));
|
||||
}
|
||||
|
||||
// check if deleted source was associated with a form
|
||||
@@ -825,6 +822,9 @@ public class IncProjectBuilder {
|
||||
}
|
||||
new File(output).delete();
|
||||
}
|
||||
if (!outputs.isEmpty()) {
|
||||
context.processMessage(new FileDeletedEvent(outputs));
|
||||
}
|
||||
srcToOut.remove(srcPath);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -20,13 +20,11 @@ public class ModulesAndFilesScope extends CompileScope {
|
||||
|
||||
private final Set<String> myModules;
|
||||
private final Map<String, Set<File>> myFiles;
|
||||
private final boolean myForcedCompilation;
|
||||
|
||||
public ModulesAndFilesScope(Project project, JpsProject jpsProject, Collection<JpsModule> modules, Map<String, Set<File>> files,
|
||||
Set<JpsArtifact> artifacts, boolean isForcedCompilation) {
|
||||
super(project, jpsProject, artifacts);
|
||||
super(project, jpsProject, artifacts, isForcedCompilation);
|
||||
myFiles = files;
|
||||
myForcedCompilation = isForcedCompilation;
|
||||
myModules = new HashSet<String>();
|
||||
for (JpsModule module : modules) {
|
||||
myModules.add(module.getName());
|
||||
|
||||
@@ -15,17 +15,14 @@ import java.util.Set;
|
||||
* Date: 9/17/11
|
||||
*/
|
||||
public class ModulesScope extends CompileScope {
|
||||
|
||||
private final Set<String> myModules;
|
||||
private final boolean myForcedCompilation;
|
||||
|
||||
public ModulesScope(Project project, JpsProject jpsProject, Set<JpsModule> modules, Set<JpsArtifact> artifacts, boolean isForcedCompilation) {
|
||||
super(project, jpsProject, artifacts);
|
||||
super(project, jpsProject, artifacts, isForcedCompilation);
|
||||
myModules = new HashSet<String>();
|
||||
for (JpsModule module : modules) {
|
||||
myModules.add(module.getName());
|
||||
}
|
||||
myForcedCompilation = isForcedCompilation;
|
||||
}
|
||||
|
||||
public boolean isRecompilationForced(@NotNull String moduleName) {
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
package org.jetbrains.jps.incremental.artifacts;
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.io.IOUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public class ArtifactFilesDelta {
|
||||
private final Set<String> myDeletedPaths = Collections.synchronizedSet(new THashSet<String>(FileUtil.PATH_HASHING_STRATEGY));
|
||||
private final Map<Integer, Set<String>> myPathsToRecompile = Collections.synchronizedMap(new HashMap<Integer, Set<String>>());
|
||||
|
||||
public void save(DataOutput out) throws IOException {
|
||||
out.writeInt(myDeletedPaths.size());
|
||||
for (String path : myDeletedPaths) {
|
||||
IOUtil.writeString(path, out);
|
||||
}
|
||||
out.writeInt(myPathsToRecompile.size());
|
||||
for (Map.Entry<Integer, Set<String>> entry : myPathsToRecompile.entrySet()) {
|
||||
out.writeInt(entry.getKey());
|
||||
Set<String> paths = entry.getValue();
|
||||
out.writeInt(paths.size());
|
||||
for (String path : paths) {
|
||||
IOUtil.writeString(path, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void load(DataInput in) throws IOException {
|
||||
myDeletedPaths.clear();
|
||||
int deletedCount = in.readInt();
|
||||
while (deletedCount-- > 0) {
|
||||
myDeletedPaths.add(IOUtil.readString(in));
|
||||
}
|
||||
myPathsToRecompile.clear();
|
||||
int changedCount = in.readInt();
|
||||
while (changedCount-- > 0) {
|
||||
int rootIndex = in.readInt();
|
||||
int filesCount = in.readInt();
|
||||
Set<String> changed = new THashSet<String>(FileUtil.PATH_HASHING_STRATEGY);
|
||||
while (filesCount-- > 0) {
|
||||
changed.add(IOUtil.readString(in));
|
||||
}
|
||||
myPathsToRecompile.put(rootIndex, changed);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearDeletedPaths() {
|
||||
myDeletedPaths.clear();
|
||||
}
|
||||
|
||||
public boolean hasChanges() {
|
||||
return !myPathsToRecompile.isEmpty() || !myDeletedPaths.isEmpty();
|
||||
}
|
||||
|
||||
public boolean markRecompile(Integer rootIndex, String filePath) {
|
||||
boolean added = addToRecompile(rootIndex, filePath);
|
||||
if (added) {
|
||||
synchronized (myDeletedPaths) {
|
||||
if (!myDeletedPaths.isEmpty()) {
|
||||
myDeletedPaths.remove(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
return added;
|
||||
}
|
||||
|
||||
private boolean addToRecompile(Integer rootIndex, String filePath) {
|
||||
myDeletedPaths.remove(filePath);
|
||||
synchronized (myPathsToRecompile) {
|
||||
Set<String> changed = myPathsToRecompile.get(rootIndex);
|
||||
if (changed == null) {
|
||||
changed = new THashSet<String>(FileUtil.PATH_HASHING_STRATEGY);
|
||||
myPathsToRecompile.put(rootIndex, changed);
|
||||
}
|
||||
return changed.add(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
public void addDeleted(String filePath) {
|
||||
synchronized (myPathsToRecompile) {
|
||||
for (Set<String> paths : myPathsToRecompile.values()) {
|
||||
paths.remove(filePath);
|
||||
}
|
||||
}
|
||||
myDeletedPaths.add(filePath);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Set<String> clearRecompile(int index) {
|
||||
return myPathsToRecompile.remove(index);
|
||||
}
|
||||
|
||||
public Set<String> getAndClearDeletedPaths() {
|
||||
synchronized (myDeletedPaths) {
|
||||
try {
|
||||
return new HashSet<String>(myDeletedPaths);
|
||||
}
|
||||
finally {
|
||||
myDeletedPaths.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<Integer, Set<String>> getFilesToRecompile() {
|
||||
return myPathsToRecompile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.jetbrains.jps.incremental.artifacts;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public class ArtifactRootId {
|
||||
private final int myArtifactId;
|
||||
private final int myRootIndex;
|
||||
|
||||
public ArtifactRootId(int artifactId, int rootIndex) {
|
||||
myArtifactId = artifactId;
|
||||
myRootIndex = rootIndex;
|
||||
}
|
||||
|
||||
public ArtifactRootId(DataInput input) throws IOException {
|
||||
myArtifactId = input.readInt();
|
||||
myRootIndex = input.readInt();
|
||||
}
|
||||
|
||||
public int getArtifactId() {
|
||||
return myArtifactId;
|
||||
}
|
||||
|
||||
public int getRootIndex() {
|
||||
return myRootIndex;
|
||||
}
|
||||
|
||||
public void save(DataOutput out) throws IOException {
|
||||
out.writeInt(myArtifactId);
|
||||
out.writeInt(myRootIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ArtifactRootId id = (ArtifactRootId)o;
|
||||
return myArtifactId == id.myArtifactId && myRootIndex == id.myRootIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * myArtifactId + myRootIndex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package org.jetbrains.jps.incremental.artifacts;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.Project;
|
||||
import org.jetbrains.jps.ProjectPaths;
|
||||
import org.jetbrains.jps.incremental.ModuleRootsIndex;
|
||||
import org.jetbrains.jps.incremental.artifacts.builders.LayoutElementBuildersRegistry;
|
||||
import org.jetbrains.jps.incremental.artifacts.instructions.*;
|
||||
import org.jetbrains.jps.incremental.storage.BuildDataManager;
|
||||
import org.jetbrains.jps.model.JpsModel;
|
||||
import org.jetbrains.jps.model.artifact.JpsArtifact;
|
||||
import org.jetbrains.jps.model.artifact.JpsArtifactService;
|
||||
import org.jetbrains.jps.model.artifact.elements.JpsCompositePackagingElement;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public class ArtifactRootsIndex {
|
||||
private MultiMap<File, ArtifactRootDescriptor> myRootToDescriptorMap;
|
||||
private Map<ArtifactRootId, ArtifactRootDescriptor> myIdToDescriptorMap;
|
||||
private Map<JpsArtifact, ArtifactInstructionsBuilder> myInstructions;
|
||||
|
||||
public ArtifactRootsIndex(JpsModel model, Project project, BuildDataManager manager, ModuleRootsIndex rootsIndex) {
|
||||
myRootToDescriptorMap = new MultiMap<File, ArtifactRootDescriptor>();
|
||||
myInstructions = new HashMap<JpsArtifact, ArtifactInstructionsBuilder>();
|
||||
myIdToDescriptorMap = new HashMap<ArtifactRootId, ArtifactRootDescriptor>();
|
||||
ArtifactsBuildData data = manager.getArtifactsBuildData();
|
||||
for (JpsArtifact artifact : JpsArtifactService.getInstance().getArtifacts(model.getProject())) {
|
||||
int artifactId = data.getArtifactId(artifact);
|
||||
ArtifactInstructionsBuilderImpl builder = new ArtifactInstructionsBuilderImpl(rootsIndex, project.getIgnoredFilePatterns(), artifactId, artifact.getName());
|
||||
final JpsCompositePackagingElement rootElement = artifact.getRootElement();
|
||||
ArtifactInstructionsBuilderContext context = new ArtifactInstructionsBuilderContextImpl(model, rootsIndex, new ProjectPaths(model.getProject()));
|
||||
String outputPath = StringUtil.notNullize(artifact.getOutputPath());//todo[nik] implement simplified instructions generation which only collect roots
|
||||
final CopyToDirectoryInstructionCreator instructionCreator = new CopyToDirectoryInstructionCreator(builder, outputPath);
|
||||
LayoutElementBuildersRegistry.getInstance().generateInstructions(rootElement, instructionCreator, context);
|
||||
myInstructions.put(artifact, builder);
|
||||
for (Pair<ArtifactRootDescriptor, DestinationInfo> pair : builder.getInstructions()) {
|
||||
ArtifactRootDescriptor descriptor = pair.getFirst();
|
||||
myRootToDescriptorMap.putValue(descriptor.getRootFile(), descriptor);
|
||||
myIdToDescriptorMap.put(descriptor.getRootId(), descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<ArtifactRootDescriptor> getDescriptors(@NotNull File file) {
|
||||
File current = file;
|
||||
Collection<ArtifactRootDescriptor> result = null;
|
||||
while (current != null) {
|
||||
Collection<ArtifactRootDescriptor> descriptors = myRootToDescriptorMap.get(current);
|
||||
if (!descriptors.isEmpty()) {
|
||||
if (result == null) {
|
||||
result = descriptors;
|
||||
}
|
||||
else {
|
||||
result = new ArrayList<ArtifactRootDescriptor>(result);
|
||||
result.addAll(descriptors);
|
||||
}
|
||||
}
|
||||
current = FileUtil.getParentFile(current);
|
||||
}
|
||||
return result != null ? result : Collections.<ArtifactRootDescriptor>emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ArtifactInstructionsBuilder getInstructionsBuilder(@NotNull JpsArtifact artifact) {
|
||||
return myInstructions.get(artifact);
|
||||
}
|
||||
}
|
||||
+61
-111
@@ -1,20 +1,20 @@
|
||||
package org.jetbrains.jps.incremental.artifacts;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.IntArrayList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.Project;
|
||||
import org.jetbrains.jps.ProjectPaths;
|
||||
import org.jetbrains.jps.incremental.ModuleRootsIndex;
|
||||
import org.jetbrains.jps.incremental.artifacts.builders.LayoutElementBuildersRegistry;
|
||||
import org.jetbrains.jps.incremental.artifacts.instructions.*;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.cmdline.ProjectDescriptor;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.artifacts.instructions.ArtifactInstructionsBuilder;
|
||||
import org.jetbrains.jps.incremental.artifacts.instructions.ArtifactRootDescriptor;
|
||||
import org.jetbrains.jps.incremental.artifacts.instructions.DestinationInfo;
|
||||
import org.jetbrains.jps.incremental.artifacts.instructions.SourceFileFilter;
|
||||
import org.jetbrains.jps.incremental.fs.BuildFSState;
|
||||
import org.jetbrains.jps.incremental.messages.UptoDateFilesSavedEvent;
|
||||
import org.jetbrains.jps.incremental.storage.BuildDataManager;
|
||||
import org.jetbrains.jps.incremental.storage.CompositeStorageOwner;
|
||||
import org.jetbrains.jps.incremental.storage.StorageOwner;
|
||||
import org.jetbrains.jps.model.JpsModel;
|
||||
import org.jetbrains.jps.model.artifact.JpsArtifact;
|
||||
import org.jetbrains.jps.model.artifact.elements.JpsCompositePackagingElement;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -24,28 +24,19 @@ import java.util.*;
|
||||
* @author nik
|
||||
*/
|
||||
public class ArtifactSourceFilesState extends CompositeStorageOwner {
|
||||
private final Project myProject;
|
||||
private final JpsArtifact myArtifact;
|
||||
private final int myArtifactId;
|
||||
private final JpsModel myModel;
|
||||
private final ModuleRootsIndex myRootsIndex;
|
||||
private final ArtifactSourceTimestampStorage myTimestampStorage;
|
||||
private Map<String, IntArrayList> myChangedFiles = new HashMap<String, IntArrayList>();
|
||||
private Set<String> myDeletedFiles = new HashSet<String>();
|
||||
private ArtifactInstructionsBuilder myInstructionsBuilder;
|
||||
private ArtifactSourceToOutputMapping mySrcOutMapping;
|
||||
private ArtifactOutputToSourceMapping myOutSrcMapping;
|
||||
private final File mySrcOutMappingsFile;
|
||||
private File myOutSrcMappingsFile;
|
||||
private final ProjectDescriptor myProjectDescriptor;
|
||||
|
||||
public ArtifactSourceFilesState(JpsArtifact artifact, int artifactId, Project project,
|
||||
JpsModel model, ModuleRootsIndex rootsIndex,
|
||||
ArtifactSourceTimestampStorage timestampStorage,
|
||||
public ArtifactSourceFilesState(JpsArtifact artifact, int artifactId, ProjectDescriptor projectDescriptor, ArtifactSourceTimestampStorage timestampStorage,
|
||||
File mappingsDir) {
|
||||
myProject = project;
|
||||
myProjectDescriptor = projectDescriptor;
|
||||
myArtifact = artifact;
|
||||
myModel = model;
|
||||
myRootsIndex = rootsIndex;
|
||||
myTimestampStorage = timestampStorage;
|
||||
myArtifactId = artifactId;
|
||||
mySrcOutMappingsFile = new File(new File(mappingsDir, String.valueOf(artifactId)), "src-out");
|
||||
@@ -71,39 +62,42 @@ public class ArtifactSourceFilesState extends CompositeStorageOwner {
|
||||
return Arrays.asList(mySrcOutMapping, myOutSrcMapping);
|
||||
}
|
||||
|
||||
public Map<String, IntArrayList> getChangedFiles() {
|
||||
return myChangedFiles;
|
||||
}
|
||||
|
||||
public Set<String> getDeletedFiles() {
|
||||
return myDeletedFiles;
|
||||
}
|
||||
|
||||
public void initState(final BuildDataManager dataManager) throws IOException {
|
||||
final Set<String> currentPaths = new HashSet<String>();
|
||||
myChangedFiles.clear();
|
||||
myDeletedFiles.clear();
|
||||
getOrCreateInstructions().processRoots(new ArtifactRootProcessor() {
|
||||
@Override
|
||||
public boolean process(ArtifactSourceRoot root, DestinationInfo destinations) throws IOException {
|
||||
final File rootFile = root.getRootFile();
|
||||
if (rootFile.exists()) {
|
||||
processRecursively(rootFile, root.getRootIndex(), dataManager, root.getFilter(), currentPaths);
|
||||
public void ensureFsStateInitialized(final BuildDataManager dataManager, final CompileContext context) throws IOException {
|
||||
ArtifactInstructionsBuilder builder = myProjectDescriptor.getArtifactRootsIndex().getInstructionsBuilder(myArtifact);
|
||||
BuildFSState fsState = myProjectDescriptor.fsState;
|
||||
String artifactName = myArtifact.getName();
|
||||
if (context.isProjectRebuild() || context.getScope().isRecompilationForced(myArtifact)) {
|
||||
markDirtyFiles(builder, dataManager, null, true);
|
||||
}
|
||||
else if (fsState.markInitialScanPerformed(artifactName)) {
|
||||
final Set<String> currentPaths = new HashSet<String>();
|
||||
fsState.clearDeletedPaths(artifactName);
|
||||
markDirtyFiles(builder, dataManager, currentPaths, false);
|
||||
final ArtifactSourceToOutputMapping mapping = getOrCreateSrcOutMapping();
|
||||
final Iterator<String> iterator = mapping.getKeysIterator();
|
||||
while (iterator.hasNext()) {
|
||||
String path = iterator.next();
|
||||
if (!currentPaths.contains(path)) {
|
||||
fsState.registerDeleted(artifactName, myArtifactId, path, myTimestampStorage);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
final ArtifactSourceToOutputMapping mapping = getOrCreateSrcOutMapping();
|
||||
final Iterator<String> iterator = mapping.getKeysIterator();
|
||||
while (iterator.hasNext()) {
|
||||
String path = iterator.next();
|
||||
if (!currentPaths.contains(path)) {
|
||||
myDeletedFiles.add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processRecursively(File file, int rootIndex, BuildDataManager dataManager, SourceFileFilter filter, Set<String> currentPaths) throws IOException {
|
||||
private void markDirtyFiles(ArtifactInstructionsBuilder builder, BuildDataManager dataManager, @Nullable Set<String> currentPaths,
|
||||
final boolean forceMarkDirty) throws IOException {
|
||||
for (Pair<ArtifactRootDescriptor, DestinationInfo> pair : builder.getInstructions()) {
|
||||
ArtifactRootDescriptor descriptor = pair.getFirst();
|
||||
myProjectDescriptor.fsState.clearRecompile(descriptor);
|
||||
final File rootFile = descriptor.getRootFile();
|
||||
if (rootFile.exists()) {
|
||||
processRecursively(rootFile, descriptor, dataManager, descriptor.getFilter(), currentPaths, forceMarkDirty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processRecursively(File file, ArtifactRootDescriptor descriptor, BuildDataManager dataManager, SourceFileFilter filter,
|
||||
@Nullable Set<String> currentPaths, final boolean forceMarkDirty) throws IOException {
|
||||
final String filePath = FileUtil.toSystemIndependentName(FileUtil.toCanonicalPath(file.getPath()));
|
||||
if (!filter.accept(filePath, dataManager)) return;
|
||||
|
||||
@@ -111,15 +105,17 @@ public class ArtifactSourceFilesState extends CompositeStorageOwner {
|
||||
final File[] children = file.listFiles();
|
||||
if (children != null) {
|
||||
for (File child : children) {
|
||||
processRecursively(child, rootIndex, dataManager, filter, currentPaths);
|
||||
processRecursively(child, descriptor, dataManager, filter, currentPaths, forceMarkDirty);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentPaths.add(filePath);
|
||||
if (currentPaths != null) {
|
||||
currentPaths.add(filePath);
|
||||
}
|
||||
final ArtifactSourceTimestampStorage.PerArtifactTimestamp[] state = myTimestampStorage.getState(filePath);
|
||||
boolean upToDate = false;
|
||||
if (state != null) {
|
||||
if (!forceMarkDirty && state != null) {
|
||||
for (ArtifactSourceTimestampStorage.PerArtifactTimestamp artifactTimestamp : state) {
|
||||
if (artifactTimestamp.myArtifactId == myArtifactId && artifactTimestamp.myTimestamp == file.lastModified()) {
|
||||
upToDate = true;
|
||||
@@ -128,70 +124,24 @@ public class ArtifactSourceFilesState extends CompositeStorageOwner {
|
||||
}
|
||||
}
|
||||
if (!upToDate) {
|
||||
myDeletedFiles.remove(filePath);
|
||||
IntArrayList list = myChangedFiles.get(filePath);
|
||||
if (list == null) {
|
||||
list = new IntArrayList(1);
|
||||
myChangedFiles.put(filePath, list);
|
||||
}
|
||||
list.add(rootIndex);
|
||||
myProjectDescriptor.fsState.markDirty(descriptor, filePath, myTimestampStorage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ArtifactInstructionsBuilder getOrCreateInstructions() {
|
||||
if (myInstructionsBuilder == null) {
|
||||
myInstructionsBuilder = computeInstructions();
|
||||
public void markUpToDate(CompileContext context) throws IOException {
|
||||
BuildFSState fsState = myProjectDescriptor.fsState;
|
||||
if (context.isProjectRebuild()) {
|
||||
fsState.markInitialScanPerformed(myArtifact.getName());
|
||||
}
|
||||
return myInstructionsBuilder;
|
||||
}
|
||||
|
||||
private ArtifactInstructionsBuilder computeInstructions() {
|
||||
final JpsCompositePackagingElement rootElement = myArtifact.getRootElement();
|
||||
ArtifactInstructionsBuilderContext context = new ArtifactInstructionsBuilderContextImpl(myModel, myRootsIndex, new ProjectPaths(myModel.getProject()));
|
||||
final ArtifactInstructionsBuilderImpl instructionsBuilder = new ArtifactInstructionsBuilderImpl(myRootsIndex, myProject.getIgnoredFilePatterns());
|
||||
final CopyToDirectoryInstructionCreator instructionCreator = new CopyToDirectoryInstructionCreator(instructionsBuilder, myArtifact.getOutputPath());
|
||||
LayoutElementBuildersRegistry.getInstance().generateInstructions(rootElement, instructionCreator, context);
|
||||
return instructionsBuilder;
|
||||
}
|
||||
|
||||
public void updateTimestamps() throws IOException {
|
||||
for (String filePath : myDeletedFiles) {
|
||||
final ArtifactSourceTimestampStorage.PerArtifactTimestamp[] state = myTimestampStorage.getState(filePath);
|
||||
if (state == null) continue;
|
||||
for (int i = 0, length = state.length; i < length; i++) {
|
||||
if (state[i].myArtifactId == myArtifactId) {
|
||||
final ArtifactSourceTimestampStorage.PerArtifactTimestamp[] newState = ArrayUtil.remove(state, i);
|
||||
myTimestampStorage.update(filePath, newState.length > 0 ? newState : null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ArtifactInstructionsBuilder builder = myProjectDescriptor.getArtifactRootsIndex().getInstructionsBuilder(myArtifact);
|
||||
boolean marked = false;
|
||||
for (Pair<ArtifactRootDescriptor, DestinationInfo> pair : builder.getInstructions()) {
|
||||
ArtifactRootDescriptor descriptor = pair.getFirst();
|
||||
marked |= fsState.markAllUpToDate(descriptor, myTimestampStorage, context.getCompilationStartStamp());
|
||||
}
|
||||
for (String filePath : myChangedFiles.keySet()) {
|
||||
final ArtifactSourceTimestampStorage.PerArtifactTimestamp[] state = myTimestampStorage.getState(filePath);
|
||||
File file = new File(FileUtil.toSystemDependentName(filePath));
|
||||
final long timestamp = file.lastModified();
|
||||
myTimestampStorage.update(filePath, updateTimestamp(state, timestamp));
|
||||
if (marked) {
|
||||
context.processMessage(UptoDateFilesSavedEvent.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
public void markUpToDate() {
|
||||
myDeletedFiles.clear();
|
||||
myChangedFiles.clear();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ArtifactSourceTimestampStorage.PerArtifactTimestamp[] updateTimestamp(ArtifactSourceTimestampStorage.PerArtifactTimestamp[] oldState, long timestamp) {
|
||||
final ArtifactSourceTimestampStorage.PerArtifactTimestamp newItem = new ArtifactSourceTimestampStorage.PerArtifactTimestamp(myArtifactId, timestamp);
|
||||
if (oldState == null) {
|
||||
return new ArtifactSourceTimestampStorage.PerArtifactTimestamp[]{newItem};
|
||||
}
|
||||
for (int i = 0, length = oldState.length; i < length; i++) {
|
||||
if (oldState[i].myArtifactId == myArtifactId) {
|
||||
oldState[i] = newItem;
|
||||
return oldState;
|
||||
}
|
||||
}
|
||||
return ArrayUtil.append(oldState, newItem);
|
||||
}
|
||||
}
|
||||
|
||||
+36
@@ -1,8 +1,10 @@
|
||||
package org.jetbrains.jps.incremental.artifacts;
|
||||
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.incremental.storage.AbstractStateStorage;
|
||||
|
||||
import java.io.DataInput;
|
||||
@@ -47,6 +49,40 @@ public class ArtifactSourceTimestampStorage extends AbstractStateStorage<String,
|
||||
update(filePath, null);
|
||||
}
|
||||
|
||||
public void removeTimestamp(String filePath, final int artifactId) throws IOException {
|
||||
final PerArtifactTimestamp[] state = getState(filePath);
|
||||
if (state == null) return;
|
||||
for (int i = 0, length = state.length; i < length; i++) {
|
||||
if (state[i].myArtifactId == artifactId) {
|
||||
final PerArtifactTimestamp[] newState = ArrayUtil.remove(state, i);
|
||||
update(filePath, newState.length > 0 ? newState : null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void update(final int artifactId, String filePath, long timestamp) throws IOException {
|
||||
PerArtifactTimestamp[] oldState = getState(filePath);
|
||||
update(filePath, updateTimestamp(oldState, timestamp, artifactId));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PerArtifactTimestamp[] updateTimestamp(PerArtifactTimestamp[] oldState,
|
||||
long timestamp, final int artifactId) {
|
||||
final PerArtifactTimestamp newItem = new PerArtifactTimestamp(
|
||||
artifactId, timestamp);
|
||||
if (oldState == null) {
|
||||
return new PerArtifactTimestamp[]{newItem};
|
||||
}
|
||||
for (int i = 0, length = oldState.length; i < length; i++) {
|
||||
if (oldState[i].myArtifactId == artifactId) {
|
||||
oldState[i] = newItem;
|
||||
return oldState;
|
||||
}
|
||||
}
|
||||
return ArrayUtil.append(oldState, newItem);
|
||||
}
|
||||
|
||||
public static class PerArtifactTimestamp {
|
||||
public final int myArtifactId;
|
||||
public final long myTimestamp;
|
||||
|
||||
+12
-6
@@ -2,11 +2,9 @@ package org.jetbrains.jps.incremental.artifacts;
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.jps.Project;
|
||||
import org.jetbrains.jps.incremental.ModuleRootsIndex;
|
||||
import org.jetbrains.jps.cmdline.ProjectDescriptor;
|
||||
import org.jetbrains.jps.incremental.storage.CompositeStorageOwner;
|
||||
import org.jetbrains.jps.incremental.storage.StorageOwner;
|
||||
import org.jetbrains.jps.model.JpsModel;
|
||||
import org.jetbrains.jps.model.artifact.JpsArtifact;
|
||||
|
||||
import java.io.File;
|
||||
@@ -36,16 +34,20 @@ public class ArtifactsBuildData extends CompositeStorageOwner {
|
||||
}
|
||||
}
|
||||
|
||||
public ArtifactSourceFilesState getOrCreateState(JpsArtifact artifact, Project project, JpsModel model, ModuleRootsIndex index) {
|
||||
public ArtifactSourceFilesState getOrCreateState(JpsArtifact artifact, ProjectDescriptor projectDescriptor) {
|
||||
ArtifactSourceFilesState state = myArtifactState.get(artifact);
|
||||
if (state == null) {
|
||||
final int artifactId = myPersistentData.getId(artifact.getName());
|
||||
state = new ArtifactSourceFilesState(artifact, artifactId, project, model, index, myTimestampStorage, myMappingsDir);
|
||||
final int artifactId = getArtifactId(artifact);
|
||||
state = new ArtifactSourceFilesState(artifact, artifactId, projectDescriptor, myTimestampStorage, myMappingsDir);
|
||||
myArtifactState.put(artifact, state);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
public int getArtifactId(JpsArtifact artifact) {
|
||||
return myPersistentData.getId(artifact.getName());
|
||||
}
|
||||
|
||||
public void clean() throws IOException {
|
||||
myTimestampStorage.wipe();
|
||||
myPersistentData.clean();
|
||||
@@ -71,4 +73,8 @@ public class ArtifactsBuildData extends CompositeStorageOwner {
|
||||
protected Iterable<? extends StorageOwner> getChildStorages() {
|
||||
return ContainerUtil.concat(myArtifactState.values(), Arrays.asList(myTimestampStorage, myPersistentData));
|
||||
}
|
||||
|
||||
public ArtifactSourceTimestampStorage getTimestampStorage() {
|
||||
return myTimestampStorage;
|
||||
}
|
||||
}
|
||||
|
||||
+63
-37
@@ -1,22 +1,20 @@
|
||||
package org.jetbrains.jps.incremental.artifacts;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.IntArrayList;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
import org.jetbrains.jps.cmdline.ProjectDescriptor;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.ProjectBuildException;
|
||||
import org.jetbrains.jps.incremental.ProjectLevelBuilder;
|
||||
import org.jetbrains.jps.incremental.*;
|
||||
import org.jetbrains.jps.incremental.artifacts.impl.ArtifactSorter;
|
||||
import org.jetbrains.jps.incremental.artifacts.impl.JarsBuilder;
|
||||
import org.jetbrains.jps.incremental.artifacts.instructions.*;
|
||||
import org.jetbrains.jps.incremental.fs.BuildFSState;
|
||||
import org.jetbrains.jps.incremental.messages.BuildMessage;
|
||||
import org.jetbrains.jps.incremental.messages.CompilerMessage;
|
||||
import org.jetbrains.jps.incremental.messages.ProgressMessage;
|
||||
import org.jetbrains.jps.incremental.messages.UptoDateFilesSavedEvent;
|
||||
import org.jetbrains.jps.model.artifact.JpsArtifact;
|
||||
import org.jetbrains.jps.model.artifact.JpsArtifactService;
|
||||
|
||||
@@ -67,11 +65,12 @@ public class IncArtifactBuilder extends ProjectLevelBuilder {
|
||||
private static void buildArtifact(JpsArtifact artifact, final CompileContext context) throws ProjectBuildException {
|
||||
final ProjectDescriptor pd = context.getProjectDescriptor();
|
||||
try {
|
||||
final ArtifactSourceFilesState state = pd.dataManager.getArtifactsBuildData().getOrCreateState(artifact, pd.project, pd.jpsModel, pd.rootsIndex);
|
||||
state.initState(pd.dataManager);
|
||||
final Set<String> deletedFiles = state.getDeletedFiles();
|
||||
final Map<String,IntArrayList> changedFiles = state.getChangedFiles();
|
||||
if (deletedFiles.isEmpty() && changedFiles.isEmpty()) {
|
||||
final ArtifactSourceFilesState state = pd.dataManager.getArtifactsBuildData().getOrCreateState(artifact, pd);
|
||||
state.ensureFsStateInitialized(pd.dataManager, context);
|
||||
final Collection<String> deletedFiles = pd.fsState.getAndClearDeletedPaths(artifact.getName());
|
||||
final Map<Integer, Set<String>> filesToRecompile = pd.fsState.getFilesToRecompile(artifact.getName());
|
||||
if (deletedFiles.isEmpty() && filesToRecompile.isEmpty()) {
|
||||
state.markUpToDate(context);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -97,27 +96,28 @@ public class IncArtifactBuilder extends ProjectLevelBuilder {
|
||||
}
|
||||
|
||||
Set<String> changedOutputPaths = new THashSet<String>();
|
||||
for (Map.Entry<String, IntArrayList> entry : changedFiles.entrySet()) {
|
||||
final IntArrayList roots = entry.getValue();
|
||||
final String sourcePath = entry.getKey();
|
||||
for (int i = 0; i < roots.size(); i++) {
|
||||
addFileToProcess(filesToProcess, roots.get(i), sourcePath, deletedFiles);
|
||||
}
|
||||
final List<String> outputPaths = srcOutMapping.getState(sourcePath);
|
||||
if (outputPaths != null) {
|
||||
changedOutputPaths.addAll(outputPaths);
|
||||
for (String outputPath : outputPaths) {
|
||||
final List<ArtifactOutputToSourceMapping.SourcePathAndRootIndex> sources = outSrcMapping.getState(outputPath);
|
||||
if (sources != null) {
|
||||
for (ArtifactOutputToSourceMapping.SourcePathAndRootIndex source : sources) {
|
||||
addFileToProcess(filesToProcess, source.getRootIndex(), source.getPath(), deletedFiles);
|
||||
for (Map.Entry<Integer, Set<String>> entry : filesToRecompile.entrySet()) {
|
||||
int rootIndex = entry.getKey();
|
||||
for (String sourcePath : entry.getValue()) {
|
||||
addFileToProcess(filesToProcess, rootIndex, sourcePath, deletedFiles);
|
||||
final List<String> outputPaths = srcOutMapping.getState(sourcePath);
|
||||
if (outputPaths != null) {
|
||||
changedOutputPaths.addAll(outputPaths);
|
||||
for (String outputPath : outputPaths) {
|
||||
final List<ArtifactOutputToSourceMapping.SourcePathAndRootIndex> sources = outSrcMapping.getState(outputPath);
|
||||
if (sources != null) {
|
||||
for (ArtifactOutputToSourceMapping.SourcePathAndRootIndex source : sources) {
|
||||
addFileToProcess(filesToProcess, source.getRootIndex(), source.getPath(), deletedFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (String sourcePath : changedFiles.keySet()) {
|
||||
srcOutMapping.remove(sourcePath);
|
||||
for (Set<String> paths : filesToRecompile.values()) {
|
||||
for (String sourcePath : paths) {
|
||||
srcOutMapping.remove(sourcePath);
|
||||
}
|
||||
}
|
||||
for (String outputPath : changedOutputPaths) {
|
||||
outSrcMapping.remove(outputPath);
|
||||
@@ -126,19 +126,20 @@ public class IncArtifactBuilder extends ProjectLevelBuilder {
|
||||
deleteOutdatedFiles(filesToDelete, context, srcOutMapping, outSrcMapping);
|
||||
context.checkCanceled();
|
||||
|
||||
final ArtifactInstructionsBuilder instructions = state.getOrCreateInstructions();
|
||||
final ArtifactInstructionsBuilder instructions = pd.getArtifactRootsIndex().getInstructionsBuilder(artifact);
|
||||
final Set<JarInfo> changedJars = new THashSet<JarInfo>();
|
||||
instructions.processRoots(new ArtifactRootProcessor() {
|
||||
@Override
|
||||
public boolean process(ArtifactSourceRoot root, DestinationInfo destination) throws IOException {
|
||||
public boolean process(ArtifactRootDescriptor descriptor, DestinationInfo destination) throws IOException {
|
||||
if (context.getCancelStatus().isCanceled()) return false;
|
||||
|
||||
final Set<String> sourcePaths = filesToProcess.get(root.getRootIndex());
|
||||
final Set<String> sourcePaths = filesToProcess.get(descriptor.getRootIndex());
|
||||
if (sourcePaths == null) return true;
|
||||
|
||||
for (String sourcePath : sourcePaths) {
|
||||
if (destination instanceof ExplodedDestinationInfo) {
|
||||
root.copyFromRoot(sourcePath, root.getRootIndex(), destination.getOutputPath(), context, srcOutMapping, outSrcMapping);
|
||||
descriptor.copyFromRoot(sourcePath, descriptor.getRootIndex(), destination.getOutputPath(), context,
|
||||
srcOutMapping, outSrcMapping);
|
||||
}
|
||||
else if (outSrcMapping.getState(destination.getOutputFilePath()) == null) {
|
||||
outSrcMapping.update(destination.getOutputFilePath(), Collections.<ArtifactOutputToSourceMapping.SourcePathAndRootIndex>emptyList());
|
||||
@@ -152,13 +153,9 @@ public class IncArtifactBuilder extends ProjectLevelBuilder {
|
||||
|
||||
JarsBuilder builder = new JarsBuilder(changedJars, context, srcOutMapping, outSrcMapping, instructions);
|
||||
final boolean processed = builder.buildJars();
|
||||
if (!processed) {
|
||||
return;
|
||||
if (processed && !Utils.errorsDetected(context) && !context.getCancelStatus().isCanceled()) {
|
||||
state.markUpToDate(context);
|
||||
}
|
||||
|
||||
state.updateTimestamps();
|
||||
state.markUpToDate();
|
||||
context.processMessage(UptoDateFilesSavedEvent.INSTANCE);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new ProjectBuildException(e);
|
||||
@@ -168,7 +165,7 @@ public class IncArtifactBuilder extends ProjectLevelBuilder {
|
||||
private static void addFileToProcess(TIntObjectHashMap<Set<String>> filesToProcess,
|
||||
final int rootIndex,
|
||||
final String path,
|
||||
Set<String> deletedFiles) {
|
||||
Collection<String> deletedFiles) {
|
||||
if (deletedFiles.contains(path)) {
|
||||
return;
|
||||
}
|
||||
@@ -219,6 +216,35 @@ public class IncArtifactBuilder extends ProjectLevelBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildStarted(final CompileContext context) {
|
||||
context.addBuildListener(new BuildListener() {
|
||||
@Override
|
||||
public void filesGenerated(Collection<Pair<String, String>> paths) {
|
||||
BuildFSState fsState = context.getProjectDescriptor().fsState;
|
||||
ArtifactRootsIndex rootsIndex = context.getProjectDescriptor().getArtifactRootsIndex();
|
||||
for (Pair<String, String> pair : paths) {
|
||||
File file = new File(pair.getFirst(), pair.getSecond());
|
||||
for (ArtifactRootDescriptor descriptor : rootsIndex.getDescriptors(file)) {
|
||||
fsState.markRecompile(descriptor, FileUtil.toSystemIndependentName(file.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void filesDeleted(Collection<String> paths) {
|
||||
BuildFSState state = context.getProjectDescriptor().fsState;
|
||||
ArtifactRootsIndex index = context.getProjectDescriptor().getArtifactRootsIndex();
|
||||
for (String path : paths) {
|
||||
File file = new File(FileUtil.toSystemDependentName(path));
|
||||
for (ArtifactRootDescriptor descriptor : index.getDescriptors(file)) {
|
||||
state.registerDeleted(descriptor.getArtifactName(), path);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return BUILDER_NAME;
|
||||
|
||||
+16
-19
@@ -33,10 +33,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.JpsPathUtil;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.ProjectBuildException;
|
||||
import org.jetbrains.jps.incremental.artifacts.ArtifactBuilderLogger;
|
||||
import org.jetbrains.jps.incremental.artifacts.ArtifactOutputToSourceMapping;
|
||||
import org.jetbrains.jps.incremental.artifacts.ArtifactSourceToOutputMapping;
|
||||
import org.jetbrains.jps.incremental.artifacts.IncArtifactBuilder;
|
||||
import org.jetbrains.jps.incremental.artifacts.*;
|
||||
import org.jetbrains.jps.incremental.artifacts.instructions.*;
|
||||
import org.jetbrains.jps.incremental.messages.BuildMessage;
|
||||
import org.jetbrains.jps.incremental.messages.CompilerMessage;
|
||||
@@ -162,21 +159,21 @@ public class JarsBuilder {
|
||||
|
||||
for (Pair<String, Object> pair : jar.getContent()) {
|
||||
final String relativePath = pair.getFirst();
|
||||
if (pair.getSecond() instanceof ArtifactSourceRoot) {
|
||||
final ArtifactSourceRoot root = (ArtifactSourceRoot)pair.getSecond();
|
||||
final int rootIndex = root.getRootIndex();
|
||||
if (pair.getSecond() instanceof ArtifactRootDescriptor) {
|
||||
final ArtifactRootDescriptor descriptor = (ArtifactRootDescriptor)pair.getSecond();
|
||||
final int rootIndex = descriptor.getRootIndex();
|
||||
final ArtifactBuilderLogger logger = myContext.getLoggingManager().getArtifactBuilderLogger();
|
||||
if (root instanceof FileBasedArtifactSourceRoot) {
|
||||
addFileToJar(jarOutputStream, jarFile, root.getRootFile(), root.getFilter(), relativePath, targetJarPath, writtenPaths,
|
||||
if (descriptor instanceof FileBasedArtifactRootDescriptor) {
|
||||
addFileToJar(jarOutputStream, jarFile, descriptor.getRootFile(), descriptor.getFilter(), relativePath, targetJarPath, writtenPaths,
|
||||
rootIndex);
|
||||
}
|
||||
else {
|
||||
final String filePath = FileUtil.toSystemIndependentName(root.getRootFile().getAbsolutePath());
|
||||
final String filePath = FileUtil.toSystemIndependentName(descriptor.getRootFile().getAbsolutePath());
|
||||
logger.fileCopied(filePath);
|
||||
mySrcOutMapping.appendData(filePath, Collections.singletonList(targetJarPath));
|
||||
myOutSrcMapping.appendData(targetJarPath, Collections
|
||||
.singletonList(new ArtifactOutputToSourceMapping.SourcePathAndRootIndex(filePath, rootIndex)));
|
||||
extractFileAndAddToJar(jarOutputStream, (JarBasedArtifactSourceRoot)root, relativePath, writtenPaths);
|
||||
extractFileAndAddToJar(jarOutputStream, (JarBasedArtifactRootDescriptor)descriptor, relativePath, writtenPaths);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -207,15 +204,15 @@ public class JarsBuilder {
|
||||
@Nullable
|
||||
private Manifest loadManifest(JarInfo jar, String targetJarPath) throws IOException {
|
||||
for (Pair<String, Object> pair : jar.getContent()) {
|
||||
if (pair.getSecond() instanceof ArtifactSourceRoot) {
|
||||
if (pair.getSecond() instanceof ArtifactRootDescriptor) {
|
||||
final String rootPath = pair.getFirst();
|
||||
if (!JarFile.MANIFEST_NAME.startsWith(rootPath)) {
|
||||
continue;
|
||||
}
|
||||
final String manifestPath = JpsPathUtil.trimForwardSlashes(JarFile.MANIFEST_NAME.substring(rootPath.length()));
|
||||
final ArtifactSourceRoot root = (ArtifactSourceRoot)pair.getSecond();
|
||||
if (root instanceof FileBasedArtifactSourceRoot) {
|
||||
final File manifestFile = new File(root.getRootFile(), manifestPath);
|
||||
final ArtifactRootDescriptor descriptor = (ArtifactRootDescriptor)pair.getSecond();
|
||||
if (descriptor instanceof FileBasedArtifactRootDescriptor) {
|
||||
final File manifestFile = new File(descriptor.getRootFile(), manifestPath);
|
||||
if (manifestFile.exists()) {
|
||||
final String fullManifestPath = FileUtil.toSystemIndependentName(manifestFile.getAbsolutePath());
|
||||
myContext.getLoggingManager().getArtifactBuilderLogger().fileCopied(fullManifestPath);
|
||||
@@ -226,11 +223,11 @@ public class JarsBuilder {
|
||||
}
|
||||
else {
|
||||
final Ref<Manifest> manifestRef = Ref.create(null);
|
||||
((JarBasedArtifactSourceRoot)root).processEntries(new JarBasedArtifactSourceRoot.EntryProcessor() {
|
||||
((JarBasedArtifactRootDescriptor)descriptor).processEntries(new JarBasedArtifactRootDescriptor.EntryProcessor() {
|
||||
@Override
|
||||
public void process(@Nullable InputStream inputStream, @NotNull String relativePath) throws IOException {
|
||||
if (manifestRef.isNull() && relativePath.equals(manifestPath) && inputStream != null) {
|
||||
manifestRef.set(createManifest(inputStream, root.getRootFile()));
|
||||
manifestRef.set(createManifest(inputStream, descriptor.getRootFile()));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -261,11 +258,11 @@ public class JarsBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private static void extractFileAndAddToJar(final JarOutputStream jarOutputStream, final JarBasedArtifactSourceRoot root,
|
||||
private static void extractFileAndAddToJar(final JarOutputStream jarOutputStream, final JarBasedArtifactRootDescriptor root,
|
||||
final String relativeOutputPath, final Set<String> writtenPaths)
|
||||
throws IOException {
|
||||
final long timestamp = root.getRootFile().lastModified();
|
||||
root.processEntries(new JarBasedArtifactSourceRoot.EntryProcessor() {
|
||||
root.processEntries(new JarBasedArtifactRootDescriptor.EntryProcessor() {
|
||||
@Override
|
||||
public void process(@Nullable InputStream inputStream, @NotNull String relativePath) throws IOException {
|
||||
String pathInJar = addParentDirectories(jarOutputStream, writtenPaths, JpsPathUtil.appendToPath(relativeOutputPath, relativePath));
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ public abstract class ArtifactCompilerInstructionCreatorBase implements Artifact
|
||||
addDirectoryCopyInstructions(myInstructionsBuilder.createJarBasedRoot(jarFile, pathInJar, filter));
|
||||
}
|
||||
|
||||
protected abstract void addDirectoryCopyInstructions(ArtifactSourceRoot root);
|
||||
protected abstract void addDirectoryCopyInstructions(ArtifactRootDescriptor descriptor);
|
||||
|
||||
@Override
|
||||
public abstract ArtifactCompilerInstructionCreatorBase subFolder(@NotNull String directoryName);
|
||||
|
||||
+5
@@ -1,10 +1,15 @@
|
||||
package org.jetbrains.jps.incremental.artifacts.instructions;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public interface ArtifactInstructionsBuilder {
|
||||
void processRoots(ArtifactRootProcessor processor) throws IOException;
|
||||
|
||||
List<Pair<ArtifactRootDescriptor, DestinationInfo>> getInstructions();
|
||||
}
|
||||
|
||||
+22
-13
@@ -18,29 +18,33 @@ import java.util.Map;
|
||||
*/
|
||||
public class ArtifactInstructionsBuilderImpl implements ArtifactInstructionsBuilder {
|
||||
private final Map<String, JarInfo> myJarByPath;
|
||||
private final List<Pair<ArtifactSourceRoot, DestinationInfo>> myInstructions;
|
||||
private final List<Pair<ArtifactRootDescriptor, DestinationInfo>> myInstructions;
|
||||
private final ModuleRootsIndex myRootsIndex;
|
||||
private final IgnoredFilePatterns myIgnoredFilePatterns;
|
||||
private final int myArtifactId;
|
||||
private final String myArtifactName;
|
||||
private int myRootIndex;
|
||||
|
||||
public ArtifactInstructionsBuilderImpl(ModuleRootsIndex rootsIndex, IgnoredFilePatterns patterns) {
|
||||
public ArtifactInstructionsBuilderImpl(ModuleRootsIndex rootsIndex, IgnoredFilePatterns patterns, int artifactId, String artifactName) {
|
||||
myRootsIndex = rootsIndex;
|
||||
myIgnoredFilePatterns = patterns;
|
||||
myArtifactId = artifactId;
|
||||
myArtifactName = artifactName;
|
||||
myJarByPath = new HashMap<String, JarInfo>();
|
||||
myInstructions = new ArrayList<Pair<ArtifactSourceRoot, DestinationInfo>>();
|
||||
myInstructions = new ArrayList<Pair<ArtifactRootDescriptor, DestinationInfo>>();
|
||||
}
|
||||
|
||||
public IgnoredFilePatterns getIgnoredFilePatterns() {
|
||||
return myIgnoredFilePatterns;
|
||||
}
|
||||
|
||||
public boolean addDestination(@NotNull ArtifactSourceRoot root, @NotNull DestinationInfo destinationInfo) {
|
||||
if (destinationInfo instanceof ExplodedDestinationInfo && root instanceof FileBasedArtifactSourceRoot
|
||||
&& root.getRootFile().equals(new File(FileUtil.toSystemDependentName(destinationInfo.getOutputFilePath())))) {
|
||||
public boolean addDestination(@NotNull ArtifactRootDescriptor descriptor, @NotNull DestinationInfo destinationInfo) {
|
||||
if (destinationInfo instanceof ExplodedDestinationInfo && descriptor instanceof FileBasedArtifactRootDescriptor
|
||||
&& descriptor.getRootFile().equals(new File(FileUtil.toSystemDependentName(destinationInfo.getOutputFilePath())))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
myInstructions.add(Pair.create(root, destinationInfo));
|
||||
myInstructions.add(Pair.create(descriptor, destinationInfo));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -58,21 +62,26 @@ public class ArtifactInstructionsBuilderImpl implements ArtifactInstructionsBuil
|
||||
|
||||
@Override
|
||||
public void processRoots(ArtifactRootProcessor processor) throws IOException {
|
||||
for (Pair<ArtifactSourceRoot, DestinationInfo> pair : myInstructions) {
|
||||
for (Pair<ArtifactRootDescriptor, DestinationInfo> pair : myInstructions) {
|
||||
if (!processor.process(pair.getFirst(), pair.getSecond())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FileBasedArtifactSourceRoot createFileBasedRoot(@NotNull File file,
|
||||
@NotNull SourceFileFilter filter) {
|
||||
return new FileBasedArtifactSourceRoot(file, filter, myRootIndex++);
|
||||
@Override
|
||||
public List<Pair<ArtifactRootDescriptor, DestinationInfo>> getInstructions() {
|
||||
return myInstructions;
|
||||
}
|
||||
|
||||
public JarBasedArtifactSourceRoot createJarBasedRoot(@NotNull File jarFile,
|
||||
public FileBasedArtifactRootDescriptor createFileBasedRoot(@NotNull File file,
|
||||
@NotNull SourceFileFilter filter) {
|
||||
return new FileBasedArtifactRootDescriptor(file, filter, myRootIndex++, myArtifactId, myArtifactName);
|
||||
}
|
||||
|
||||
public JarBasedArtifactRootDescriptor createJarBasedRoot(@NotNull File jarFile,
|
||||
@NotNull String pathInJar,
|
||||
@NotNull SourceFileFilter filter) {
|
||||
return new JarBasedArtifactSourceRoot(jarFile, pathInJar, filter, myRootIndex++);
|
||||
return new JarBasedArtifactRootDescriptor(jarFile, pathInJar, filter, myRootIndex, myArtifactId, myArtifactName);
|
||||
}
|
||||
}
|
||||
|
||||
+21
-6
@@ -3,6 +3,7 @@ package org.jetbrains.jps.incremental.artifacts.instructions;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.artifacts.ArtifactOutputToSourceMapping;
|
||||
import org.jetbrains.jps.incremental.artifacts.ArtifactRootId;
|
||||
import org.jetbrains.jps.incremental.artifacts.ArtifactSourceToOutputMapping;
|
||||
|
||||
import java.io.File;
|
||||
@@ -11,17 +12,31 @@ import java.io.IOException;
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public abstract class ArtifactSourceRoot {
|
||||
public abstract class ArtifactRootDescriptor {
|
||||
protected final File myRoot;
|
||||
private final SourceFileFilter myFilter;
|
||||
private final int myRootIndex;
|
||||
private final ArtifactRootId myRootId;
|
||||
private final String myArtifactName;
|
||||
|
||||
protected ArtifactSourceRoot(@NotNull SourceFileFilter filter, int index) {
|
||||
protected ArtifactRootDescriptor(File root, @NotNull SourceFileFilter filter, int index, int artifactId, String artifactName) {
|
||||
myRoot = root;
|
||||
myFilter = filter;
|
||||
myRootIndex = index;
|
||||
myArtifactName = artifactName;
|
||||
myRootId = new ArtifactRootId(artifactId, index);
|
||||
}
|
||||
|
||||
public final String getArtifactName() {
|
||||
return myArtifactName;
|
||||
}
|
||||
|
||||
public final ArtifactRootId getRootId() {
|
||||
return myRootId;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract File getRootFile();
|
||||
public final File getRootFile() {
|
||||
return myRoot;
|
||||
}
|
||||
|
||||
public abstract void copyFromRoot(String filePath,
|
||||
int rootIndex, String outputPath,
|
||||
@@ -33,6 +48,6 @@ public abstract class ArtifactSourceRoot {
|
||||
}
|
||||
|
||||
public int getRootIndex() {
|
||||
return myRootIndex;
|
||||
return myRootId.getRootIndex();
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -1,11 +1,10 @@
|
||||
package org.jetbrains.jps.incremental.artifacts.instructions;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public interface ArtifactRootProcessor {
|
||||
boolean process(ArtifactSourceRoot root, DestinationInfo destinations) throws IOException;
|
||||
boolean process(ArtifactRootDescriptor descriptor, DestinationInfo destinations) throws IOException;
|
||||
}
|
||||
|
||||
+2
-2
@@ -35,8 +35,8 @@ public class CopyToDirectoryInstructionCreator extends ArtifactCompilerInstructi
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDirectoryCopyInstructions(ArtifactSourceRoot root) {
|
||||
myInstructionsBuilder.addDestination(root, new ExplodedDestinationInfo(myOutputPath));
|
||||
protected void addDirectoryCopyInstructions(ArtifactRootDescriptor descriptor) {
|
||||
myInstructionsBuilder.addDestination(descriptor, new ExplodedDestinationInfo(myOutputPath));
|
||||
}
|
||||
|
||||
public CopyToDirectoryInstructionCreator subFolder(@NotNull String directoryName) {
|
||||
|
||||
+8
-13
@@ -14,23 +14,18 @@ import java.util.Collections;
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public class FileBasedArtifactSourceRoot extends ArtifactSourceRoot {
|
||||
private final File myFile;
|
||||
|
||||
public FileBasedArtifactSourceRoot(@NotNull File file, @NotNull SourceFileFilter filter, int index) {
|
||||
super(filter, index);
|
||||
myFile = file;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public File getRootFile() {
|
||||
return myFile;
|
||||
public class FileBasedArtifactRootDescriptor extends ArtifactRootDescriptor {
|
||||
public FileBasedArtifactRootDescriptor(@NotNull File file,
|
||||
@NotNull SourceFileFilter filter,
|
||||
int index,
|
||||
int artifactId,
|
||||
String artifactName) {
|
||||
super(file, filter, index, artifactId, artifactName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myFile.getPath();
|
||||
return myRoot.getPath();
|
||||
}
|
||||
|
||||
public void copyFromRoot(String filePath,
|
||||
+9
-13
@@ -19,25 +19,21 @@ import java.util.zip.ZipFile;
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public class JarBasedArtifactSourceRoot extends ArtifactSourceRoot {
|
||||
private final File myJarFile;
|
||||
public class JarBasedArtifactRootDescriptor extends ArtifactRootDescriptor {
|
||||
private final String myPathInJar;
|
||||
|
||||
public JarBasedArtifactSourceRoot(@NotNull File jarFile, @NotNull String pathInJar, @NotNull SourceFileFilter filter, int index) {
|
||||
super(filter, index);
|
||||
myJarFile = jarFile;
|
||||
public JarBasedArtifactRootDescriptor(@NotNull File jarFile,
|
||||
@NotNull String pathInJar,
|
||||
@NotNull SourceFileFilter filter,
|
||||
int index,
|
||||
int artifactId, String artifactName) {
|
||||
super(jarFile, filter, index, artifactId, artifactName);
|
||||
myPathInJar = pathInJar;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public File getRootFile() {
|
||||
return myJarFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myJarFile.getPath() + JarPathUtil.JAR_SEPARATOR + myPathInJar;
|
||||
return myRoot.getPath() + JarPathUtil.JAR_SEPARATOR + myPathInJar;
|
||||
}
|
||||
|
||||
public void processEntries(EntryProcessor processor) throws IOException {
|
||||
@@ -47,7 +43,7 @@ public class JarBasedArtifactSourceRoot extends ArtifactSourceRoot {
|
||||
prefix = "";
|
||||
}
|
||||
|
||||
ZipFile zipFile = new ZipFile(myJarFile);
|
||||
ZipFile zipFile = new ZipFile(myRoot);
|
||||
try {
|
||||
final Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
|
||||
+2
-2
@@ -34,8 +34,8 @@ public class JarInfo {
|
||||
myContent = new ArrayList<Pair<String, Object>>();
|
||||
}
|
||||
|
||||
public void addContent(String pathInJar, ArtifactSourceRoot sourceFile) {
|
||||
myContent.add(Pair.create(pathInJar, (Object)sourceFile));
|
||||
public void addContent(String pathInJar, ArtifactRootDescriptor descriptor) {
|
||||
myContent.add(Pair.create(pathInJar, (Object)descriptor));
|
||||
}
|
||||
|
||||
public void addJar(String pathInJar, JarInfo jarInfo) {
|
||||
|
||||
+5
-5
@@ -36,17 +36,17 @@ public class PackIntoArchiveInstructionCreator extends ArtifactCompilerInstructi
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDirectoryCopyInstructions(ArtifactSourceRoot root) {
|
||||
addCopyInstruction(myPathInJar, root);
|
||||
protected void addDirectoryCopyInstructions(ArtifactRootDescriptor descriptor) {
|
||||
addCopyInstruction(myPathInJar, descriptor);
|
||||
}
|
||||
|
||||
public void addFileCopyInstruction(@NotNull File file, @NotNull String outputFileName) {
|
||||
addCopyInstruction(childPathInJar(outputFileName), myInstructionsBuilder.createFileBasedRoot(file, SourceFileFilter.ALL));
|
||||
}
|
||||
|
||||
private void addCopyInstruction(String pathInJar, final ArtifactSourceRoot root) {
|
||||
if (myInstructionsBuilder.addDestination(root, new JarDestinationInfo(pathInJar, myJarInfo, myJarDestination))) {
|
||||
myJarInfo.addContent(pathInJar, root);
|
||||
private void addCopyInstruction(String pathInJar, final ArtifactRootDescriptor descriptor) {
|
||||
if (myInstructionsBuilder.addDestination(descriptor, new JarDestinationInfo(pathInJar, myJarInfo, myJarDestination))) {
|
||||
myJarInfo.addContent(pathInJar, descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ public class SkipAllInstructionCreator extends ArtifactCompilerInstructionCreato
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDirectoryCopyInstructions(ArtifactSourceRoot root) {
|
||||
protected void addDirectoryCopyInstructions(ArtifactRootDescriptor descriptor) {
|
||||
}
|
||||
|
||||
public SkipAllInstructionCreator subFolder(@NotNull String directoryName) {
|
||||
|
||||
@@ -11,6 +11,9 @@ import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.CompileScope;
|
||||
import org.jetbrains.jps.incremental.FileProcessor;
|
||||
import org.jetbrains.jps.incremental.Utils;
|
||||
import org.jetbrains.jps.incremental.artifacts.ArtifactFilesDelta;
|
||||
import org.jetbrains.jps.incremental.artifacts.ArtifactSourceTimestampStorage;
|
||||
import org.jetbrains.jps.incremental.artifacts.instructions.ArtifactRootDescriptor;
|
||||
import org.jetbrains.jps.incremental.storage.Timestamps;
|
||||
import org.jetbrains.jps.model.module.JpsModule;
|
||||
|
||||
@@ -45,6 +48,11 @@ public class BuildFSState extends FSState {
|
||||
return myAlwaysScanFS || super.markInitialScanPerformed(moduleName, forTests);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markInitialScanPerformed(String artifactName) {
|
||||
return myAlwaysScanFS || super.markInitialScanPerformed(artifactName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<File, Set<File>> getSourcesToRecompile(@NotNull CompileContext context, final String moduleName, boolean forTests) {
|
||||
final FilesDelta lastRoundDelta = getRoundDelta(LAST_ROUND_DELTA_KEY, context);
|
||||
@@ -54,6 +62,10 @@ public class BuildFSState extends FSState {
|
||||
return super.getSourcesToRecompile(context, moduleName, forTests);
|
||||
}
|
||||
|
||||
public Map<Integer, Set<String>> getFilesToRecompile(String artifactName) {
|
||||
return getDelta(artifactName).getFilesToRecompile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markDirty(@Nullable CompileContext context, File file, final RootDescriptor rd, @Nullable Timestamps tsStorage) throws IOException {
|
||||
final FilesDelta roundDelta = getRoundDelta(CURRENT_ROUND_DELTA_KEY, context);
|
||||
@@ -174,6 +186,27 @@ public class BuildFSState extends FSState {
|
||||
return marked;
|
||||
}
|
||||
|
||||
public boolean markAllUpToDate(ArtifactRootDescriptor descriptor, ArtifactSourceTimestampStorage storage, long compilationStartStamp)
|
||||
throws IOException {
|
||||
boolean marked = false;
|
||||
ArtifactFilesDelta delta = getDelta(descriptor.getArtifactName());
|
||||
Set<String> paths = delta.clearRecompile(descriptor.getRootIndex());
|
||||
if (paths != null) {
|
||||
for (String path : paths) {
|
||||
File file = new File(FileUtil.toSystemDependentName(path));
|
||||
long stamp = file.lastModified();
|
||||
if (stamp > compilationStartStamp + 1000) {//todo[nik] this is added to fix tests on Linux
|
||||
delta.markRecompile(descriptor.getRootIndex(), path);
|
||||
}
|
||||
else {
|
||||
marked = true;
|
||||
storage.update(descriptor.getRootId().getArtifactId(), path, stamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return marked;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Set<String> getContextModules(@Nullable CompileContext context) {
|
||||
return context != null? CONTEXT_MODULES_KEY.get(context, Collections.<String>emptySet()) : Collections.<String>emptySet();
|
||||
|
||||
@@ -4,9 +4,12 @@ import com.intellij.util.io.IOUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.artifacts.ArtifactFilesDelta;
|
||||
import org.jetbrains.jps.incremental.artifacts.ArtifactSourceTimestampStorage;
|
||||
import org.jetbrains.jps.incremental.artifacts.instructions.ArtifactRootDescriptor;
|
||||
import org.jetbrains.jps.incremental.storage.Timestamps;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -21,6 +24,8 @@ public class FSState {
|
||||
private final Map<String, FilesDelta> myTestDeltas = Collections.synchronizedMap(new HashMap<String, FilesDelta>());
|
||||
protected final Set<String> myInitialTestsScanPerformed = Collections.synchronizedSet(new HashSet<String>());
|
||||
protected final Set<String> myInitialProductionScanPerformed = Collections.synchronizedSet(new HashSet<String>());
|
||||
private final Map<String, ArtifactFilesDelta> myArtifactDeltas = Collections.synchronizedMap(new HashMap<String, ArtifactFilesDelta>());
|
||||
private final Set<String> myArtifactInitialScanPerformed = Collections.synchronizedSet(new HashSet<String>());
|
||||
|
||||
public void save(DataOutput out) throws IOException {
|
||||
out.writeInt(myInitialTestsScanPerformed.size());
|
||||
@@ -34,9 +39,14 @@ public class FSState {
|
||||
IOUtil.writeString(moduleName, out);
|
||||
getDelta(moduleName, false).save(out);
|
||||
}
|
||||
out.writeInt(myArtifactInitialScanPerformed.size());
|
||||
for (String artifactName : myArtifactInitialScanPerformed) {
|
||||
IOUtil.writeString(artifactName, out);
|
||||
getDelta(artifactName).save(out);
|
||||
}
|
||||
}
|
||||
|
||||
public void load(DataInput in) throws IOException {
|
||||
public void load(DataInputStream in) throws IOException {
|
||||
int testsDeltaCount = in.readInt();
|
||||
while (testsDeltaCount-- > 0) {
|
||||
final String moduleName = IOUtil.readString(in);
|
||||
@@ -50,17 +60,41 @@ public class FSState {
|
||||
getDelta(moduleName, false).load(in);
|
||||
myInitialProductionScanPerformed.add(moduleName);
|
||||
}
|
||||
if (in.available() > 0) {//todo[nik] remove this check after version change
|
||||
int artifactRootsCount = in.readInt();
|
||||
while (artifactRootsCount-- > 0) {
|
||||
String name = IOUtil.readString(in);
|
||||
getDelta(name).load(in);
|
||||
myArtifactInitialScanPerformed.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected ArtifactFilesDelta getDelta(String artifactName) {
|
||||
synchronized (myArtifactDeltas) {
|
||||
ArtifactFilesDelta delta = myArtifactDeltas.get(artifactName);
|
||||
if (delta == null) {
|
||||
delta = new ArtifactFilesDelta();
|
||||
myArtifactDeltas.put(artifactName, delta);
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
}
|
||||
|
||||
public void clearAll() {
|
||||
myProductionDeltas.clear();
|
||||
myTestDeltas.clear();
|
||||
myArtifactDeltas.clear();
|
||||
}
|
||||
|
||||
public final void clearRecompile(final RootDescriptor rd) {
|
||||
getDelta(rd.module, rd.isTestRoot).clearRecompile(rd.root);
|
||||
}
|
||||
|
||||
public void clearRecompile(ArtifactRootDescriptor descriptor) {
|
||||
getDelta(descriptor.getArtifactName()).clearRecompile(descriptor.getRootIndex());
|
||||
}
|
||||
|
||||
public boolean markDirty(@Nullable CompileContext context, final File file, final RootDescriptor rd, final @Nullable Timestamps tsStorage) throws IOException {
|
||||
final FilesDelta mainDelta = getDelta(rd.module, rd.isTestRoot);
|
||||
final boolean marked = mainDelta.markRecompile(rd.root, file);
|
||||
@@ -81,6 +115,15 @@ public class FSState {
|
||||
return marked;
|
||||
}
|
||||
|
||||
public void markDirty(ArtifactRootDescriptor descriptor, String filePath, ArtifactSourceTimestampStorage timestamps) throws IOException {
|
||||
markRecompile(descriptor, filePath);
|
||||
timestamps.removeTimestamp(filePath, descriptor.getRootId().getArtifactId());
|
||||
}
|
||||
|
||||
public void markRecompile(ArtifactRootDescriptor descriptor, String filePath) {
|
||||
getDelta(descriptor.getArtifactName()).markRecompile(descriptor.getRootIndex(), filePath);
|
||||
}
|
||||
|
||||
public void registerDeleted(final String moduleName, final File file, final boolean forTests, @Nullable Timestamps tsStorage) throws IOException {
|
||||
getDelta(moduleName, forTests).addDeleted(file);
|
||||
if (tsStorage != null) {
|
||||
@@ -88,6 +131,16 @@ public class FSState {
|
||||
}
|
||||
}
|
||||
|
||||
public void registerDeleted(final String artifactName, final int artifactId, String filePath,
|
||||
ArtifactSourceTimestampStorage timestampStorage) throws IOException {
|
||||
registerDeleted(artifactName, filePath);
|
||||
timestampStorage.removeTimestamp(filePath, artifactId);
|
||||
}
|
||||
|
||||
public void registerDeleted(String artifactName, String filePath) {
|
||||
getDelta(artifactName).addDeleted(filePath);
|
||||
}
|
||||
|
||||
public Map<File, Set<File>> getSourcesToRecompile(@NotNull CompileContext context, final String moduleName, boolean forTests) {
|
||||
return getDelta(moduleName, forTests).getSourcesToRecompile();
|
||||
}
|
||||
@@ -99,6 +152,13 @@ public class FSState {
|
||||
}
|
||||
}
|
||||
|
||||
public void clearDeletedPaths(String artifactName) {
|
||||
ArtifactFilesDelta delta = myArtifactDeltas.get(artifactName);
|
||||
if (delta != null) {
|
||||
delta.clearDeletedPaths();
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, FilesDelta> getDeltas(boolean forTests) {
|
||||
return forTests ? myTestDeltas : myProductionDeltas;
|
||||
}
|
||||
@@ -111,6 +171,14 @@ public class FSState {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public Collection<String> getAndClearDeletedPaths(String artifactName) {
|
||||
ArtifactFilesDelta delta = myArtifactDeltas.get(artifactName);
|
||||
if (delta != null) {
|
||||
return delta.getAndClearDeletedPaths();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected final FilesDelta getDelta(final String moduleName, boolean forTests) {
|
||||
Map<String, FilesDelta> deltas = getDeltas(forTests);
|
||||
@@ -125,17 +193,26 @@ public class FSState {
|
||||
}
|
||||
|
||||
public boolean hasWorkToDo() {
|
||||
return hasWorkToDo(false) || hasWorkToDo(true);
|
||||
return hasWorkToDoWithModules(false) || hasWorkToDoWithModules(true) || hasWorkToDoWithArtifacts();
|
||||
}
|
||||
|
||||
private boolean hasWorkToDo(final boolean forTests) {
|
||||
private boolean hasWorkToDoWithArtifacts() {
|
||||
for (Map.Entry<String, ArtifactFilesDelta> entry : myArtifactDeltas.entrySet()) {
|
||||
if (!myArtifactInitialScanPerformed.contains(entry.getKey()) || entry.getValue().hasChanges()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasWorkToDoWithModules(final boolean forTests) {
|
||||
for (Map.Entry<String, FilesDelta> entry : getDeltas(forTests).entrySet()) {
|
||||
final String moduleName = entry.getKey();
|
||||
if (!myInitialProductionScanPerformed.contains(moduleName) || !myInitialTestsScanPerformed.contains(moduleName)) {
|
||||
if (!getInitialScanPerformedSet(forTests).contains(moduleName)) {
|
||||
return true;
|
||||
}
|
||||
final FilesDelta delta = entry.getValue();
|
||||
if (delta.hasPathsToDelete() || delta.hasSourcesToRecompile()) {
|
||||
if (delta.hasChanges()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -143,6 +220,14 @@ public class FSState {
|
||||
}
|
||||
|
||||
public boolean markInitialScanPerformed(final String moduleName, boolean forTests) {
|
||||
return (forTests ? myInitialTestsScanPerformed : myInitialProductionScanPerformed).add(moduleName);
|
||||
return getInitialScanPerformedSet(forTests).add(moduleName);
|
||||
}
|
||||
|
||||
private Set<String> getInitialScanPerformedSet(boolean forTests) {
|
||||
return forTests ? myInitialTestsScanPerformed : myInitialProductionScanPerformed;
|
||||
}
|
||||
|
||||
public boolean markInitialScanPerformed(String artifactName) {
|
||||
return myArtifactInitialScanPerformed.add(artifactName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,10 @@ final class FilesDelta {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasChanges() {
|
||||
return hasPathsToDelete() || hasSourcesToRecompile();
|
||||
}
|
||||
|
||||
|
||||
private static Set<File> createSetOfFiles() {
|
||||
return new THashSet<File>(new TObjectHashingStrategy<File>() {
|
||||
@@ -151,7 +155,7 @@ final class FilesDelta {
|
||||
return myFilesToRecompile;
|
||||
}
|
||||
|
||||
public boolean hasSourcesToRecompile() {
|
||||
private boolean hasSourcesToRecompile() {
|
||||
synchronized (myFilesToRecompile) {
|
||||
if(!myFilesToRecompile.isEmpty()) {
|
||||
for (Set<File> files : myFilesToRecompile.values()) {
|
||||
@@ -164,16 +168,10 @@ final class FilesDelta {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasPathsToDelete() {
|
||||
private boolean hasPathsToDelete() {
|
||||
return !myDeletedPaths.isEmpty();
|
||||
}
|
||||
|
||||
public Set<String> getDeletedPaths() {
|
||||
synchronized (myDeletedPaths) {
|
||||
return myDeletedPaths.isEmpty()? Collections.<String>emptySet() : new HashSet<String>(myDeletedPaths);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Set<File> clearRecompile(File root) {
|
||||
return myFilesToRecompile.remove(root);
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.jetbrains.jps.incremental.messages;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public class FileDeletedEvent extends BuildMessage {
|
||||
private Collection<String> myFilePaths;
|
||||
|
||||
public FileDeletedEvent(Collection<String> filePaths) {
|
||||
super("", Kind.INFO);
|
||||
myFilePaths = filePaths;
|
||||
}
|
||||
|
||||
public Collection<String> getFilePaths() {
|
||||
return myFilePaths;
|
||||
}
|
||||
}
|
||||
@@ -286,6 +286,10 @@ public class AndroidDexBuilder extends ProjectLevelBuilder {
|
||||
dirtyOutputDirs.add(path.first);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void filesDeleted(Collection<String> paths) {
|
||||
}
|
||||
};
|
||||
context.putUserData(DIRTY_OUTPUT_DIRS, dirtyOutputDirs);
|
||||
context.putUserData(BUILD_LISTENER_KEY, listener);
|
||||
|
||||
Reference in New Issue
Block a user