external compiler: building process ruled by BuildTargets instead of modules

This commit is contained in:
nik
2012-09-27 10:42:10 +04:00
parent ce38a78449
commit 035ccb817c
50 changed files with 710 additions and 324 deletions
@@ -170,7 +170,7 @@ public class CompileStepBeforeRun extends BeforeRunTaskProvider<CompileStepBefor
@Nullable
public static RunConfiguration getRunConfiguration(final CompileContext context) {
return context.getCompileScope().getUserData(RUN_CONFIGURATION);
return getRunConfiguration(context.getCompileScope());
}
@Nullable
@@ -21,16 +21,18 @@ public class ModuleChunk {
}
};
private Set<JpsModule> myModules;
private final boolean myTests;
private final boolean myContainsTests;
private Set<ModuleBuildTarget> myTargets;
public ModuleChunk(Set<ModuleBuildTarget> targets, boolean tests) {
myTests = tests;
public ModuleChunk(Set<ModuleBuildTarget> targets) {
boolean containsTests = false;
myTargets = targets;
myModules = new LinkedHashSet<JpsModule>();
for (ModuleBuildTarget target : targets) {
myModules.add(target.getModule());
containsTests |= target.isTests();
}
myContainsTests = containsTests;
}
public String getName() {
@@ -42,8 +44,8 @@ public class ModuleChunk {
return myModules;
}
public boolean isTests() {
return myTests;
public boolean containsTests() {
return myContainsTests;
}
public Set<ModuleBuildTarget> getTargets() {
@@ -1,103 +0,0 @@
package org.jetbrains.jps;
import com.intellij.util.graph.CachingSemiGraph;
import com.intellij.util.graph.DFSTBuilder;
import com.intellij.util.graph.GraphGenerator;
import gnu.trove.TIntArrayList;
import gnu.trove.TIntProcedure;
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
import org.jetbrains.jps.incremental.ModuleBuildTarget;
import org.jetbrains.jps.model.JpsProject;
import org.jetbrains.jps.model.module.JpsModule;
import java.util.*;
/**
* @author nik
*/
public class ProjectChunks {
private List<ModuleChunk> chunks;
private List<ModuleBuildTarget> myAllTargets;
private Map<ModuleBuildTarget, Collection<ModuleBuildTarget>> myTargetDependencies;
private final JpsProject myProject;
public ProjectChunks(JpsProject project) {
myProject = project;
}
public List<ModuleChunk> getChunkList() {
initializeChunks();
return chunks;
}
private void initializeChunks() {
if (chunks != null) {
return;
}
myAllTargets = new ArrayList<ModuleBuildTarget>(myProject.getModules().size()*2);
for (JpsModule module : myProject.getModules()) {
myAllTargets.add(new ModuleBuildTarget(module, JavaModuleBuildTargetType.PRODUCTION));
myAllTargets.add(new ModuleBuildTarget(module, JavaModuleBuildTargetType.TEST));
}
myTargetDependencies = new HashMap<ModuleBuildTarget, Collection<ModuleBuildTarget>>();
for (ModuleBuildTarget target : myAllTargets) {
myTargetDependencies.put(target, target.computeDependencies());
}
GraphGenerator<ModuleBuildTarget> graph = GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph<ModuleBuildTarget>() {
@Override
public Collection<ModuleBuildTarget> getNodes() {
return myAllTargets;
}
@Override
public Iterator<ModuleBuildTarget> getIn(ModuleBuildTarget n) {
return myTargetDependencies.get(n).iterator();
}
}));
final DFSTBuilder<ModuleBuildTarget> builder = new DFSTBuilder<ModuleBuildTarget>(graph);
final TIntArrayList sccs = builder.getSCCs();
chunks = new ArrayList<ModuleChunk>(sccs.size());
sccs.forEach(new TIntProcedure() {
int myTNumber = 0;
public boolean execute(int size) {
final Set<ModuleBuildTarget> chunkNodes = new LinkedHashSet<ModuleBuildTarget>();
boolean test = false;
for (int j = 0; j < size; j++) {
final ModuleBuildTarget node = builder.getNodeByTNumber(myTNumber + j);
test = node.isTests();//production target cannot depend on test so this flag is the same for all nodes in the cycle
chunkNodes.add(node);
}
chunks.add(new ModuleChunk(chunkNodes, test));
myTNumber += size;
return true;
}
});
}
public Collection<ModuleBuildTarget> getAllTargets() {
initializeChunks();
return myAllTargets;
}
public Set<ModuleBuildTarget> getDependenciesRecursively(ModuleBuildTarget target) {
initializeChunks();
LinkedHashSet<ModuleBuildTarget> result = new LinkedHashSet<ModuleBuildTarget>();
for (ModuleBuildTarget dep : myTargetDependencies.get(target)) {
collectDependenciesRecursively(dep, result);
}
return result;
}
private void collectDependenciesRecursively(ModuleBuildTarget target, LinkedHashSet<ModuleBuildTarget> result) {
if (result.add(target)) {
for (ModuleBuildTarget dep : myTargetDependencies.get(target)) {
collectDependenciesRecursively(dep, result);
}
}
}
}
@@ -41,11 +41,11 @@ public class ProjectPaths {
}
public Collection<File> getPlatformCompilationClasspath(ModuleChunk chunk, boolean excludeMainModuleOutput) {
return getClasspathFiles(chunk, JpsJavaClasspathKind.compile(chunk.isTests()), excludeMainModuleOutput, ClasspathPart.BEFORE_JDK, true);
return getClasspathFiles(chunk, JpsJavaClasspathKind.compile(chunk.containsTests()), excludeMainModuleOutput, ClasspathPart.BEFORE_JDK, true);
}
public Collection<File> getCompilationClasspath(ModuleChunk chunk, boolean excludeMainModuleOutput) {
return getClasspathFiles(chunk, JpsJavaClasspathKind.compile(chunk.isTests()), excludeMainModuleOutput, ClasspathPart.AFTER_JDK, true);
return getClasspathFiles(chunk, JpsJavaClasspathKind.compile(chunk.containsTests()), excludeMainModuleOutput, ClasspathPart.AFTER_JDK, true);
}
private Collection<File> getClasspathFiles(ModuleChunk chunk,
@@ -94,7 +94,7 @@ public class ProjectPaths {
* @return mapping "sourceRoot" -> "package prefix" Package prefix uses slashes instead of dots and ends with trailing slash
*/
public static Map<File, String> getSourceRootsWithDependents(ModuleChunk chunk) {
final boolean includeTests = chunk.isTests();
final boolean includeTests = chunk.containsTests();
final Map<File, String> result = new LinkedHashMap<File, String>();
processModulesRecursively(chunk, JpsJavaClasspathKind.compile(includeTests), new Consumer<JpsModule>() {
@Override
@@ -122,7 +122,7 @@ public class ProjectPaths {
}
public static Collection<File> getOutputPathsWithDependents(final ModuleChunk chunk) {
final boolean forTests = chunk.isTests();
final boolean forTests = chunk.containsTests();
final Set<File> sourcePaths = new LinkedHashSet<File>();
processModulesRecursively(chunk, JpsJavaClasspathKind.compile(forTests), new Consumer<JpsModule>() {
@Override
@@ -25,7 +25,7 @@ public abstract class BuildTarget<R extends BuildRootDescriptor> {
return myTargetType;
}
public abstract Collection<? extends BuildTarget<?>> computeDependencies();
public abstract Collection<BuildTarget<?>> computeDependencies();
public void writeConfiguration(PrintWriter out, BuildRootIndex buildRootIndex) {
}
@@ -36,8 +36,11 @@ public abstract class BuildTarget<R extends BuildRootDescriptor> {
@Nullable
public abstract BuildRootDescriptor findRootDescriptor(String rootId, BuildRootIndex rootIndex);
@NotNull
public abstract String getPresentableName();
@Override
public String toString() {
return myTargetType.getTypeId() + " '" + getId() + "'";
return getPresentableName();
}
}
@@ -1,8 +1,11 @@
package org.jetbrains.jps.builders;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.builders.impl.BuildTargetChunk;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* @author nik
@@ -10,5 +13,14 @@ import java.util.Collection;
public interface BuildTargetIndex {
@NotNull
<T extends BuildTarget<?>>
Collection<T> getAllTargets(@NotNull BuildTargetType<T> type);
List<T> getAllTargets(@NotNull BuildTargetType<T> type);
@NotNull
Collection<BuildTarget<?>> getDependencies(@NotNull BuildTarget<?> target);
List<BuildTargetChunk> getSortedTargetChunks();
List<? extends BuildTarget<?>> getAllTargets();
Set<BuildTarget<?>> getDependenciesRecursively(BuildTarget<?> target);
}
@@ -3,7 +3,7 @@ package org.jetbrains.jps.builders;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.JpsModel;
import java.util.Collection;
import java.util.List;
/**
* @author nik
@@ -20,7 +20,7 @@ public abstract class BuildTargetType<T extends BuildTarget<?>> {
}
@NotNull
public abstract Collection<T> computeAllTargets(@NotNull JpsModel model);
public abstract List<T> computeAllTargets(@NotNull JpsModel model);
@NotNull
public abstract BuildTargetLoader<T> createLoader(@NotNull JpsModel model);
@@ -0,0 +1,25 @@
package org.jetbrains.jps.builders.impl;
import org.jetbrains.jps.builders.BuildTarget;
import java.util.Set;
/**
* @author nik
*/
public class BuildTargetChunk {
private Set<BuildTarget<?>> myTargets;
public BuildTargetChunk(Set<BuildTarget<?>> targets) {
myTargets = targets;
}
public Set<BuildTarget<?>> getTargets() {
return myTargets;
}
@Override
public String toString() {
return myTargets.toString();
}
}
@@ -1,5 +1,11 @@
package org.jetbrains.jps.builders.impl;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.graph.CachingSemiGraph;
import com.intellij.util.graph.DFSTBuilder;
import com.intellij.util.graph.GraphGenerator;
import gnu.trove.TIntArrayList;
import gnu.trove.TIntProcedure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.builders.BuildTargetIndex;
@@ -7,27 +13,112 @@ import org.jetbrains.jps.builders.BuildTargetType;
import org.jetbrains.jps.incremental.BuilderRegistry;
import org.jetbrains.jps.model.JpsModel;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
/**
* @author nik
*/
public class BuildTargetIndexImpl implements BuildTargetIndex {
private Map<BuildTargetType<?>, Collection<? extends BuildTarget<?>>> myTargets;
private Map<BuildTargetType<?>, List<? extends BuildTarget<?>>> myTargets;
private Map<BuildTarget<?>, Collection<BuildTarget<?>>> myDependencies;
private List<BuildTargetChunk> myTargetChunks;
private final List<BuildTarget<?>> myAllTargets;
public BuildTargetIndexImpl(@NotNull JpsModel model) {
myTargets = new HashMap<BuildTargetType<?>, Collection<? extends BuildTarget<?>>>();
myTargets = new HashMap<BuildTargetType<?>, List<? extends BuildTarget<?>>>();
List<List<? extends BuildTarget<?>>> targetsByType = new ArrayList<List<? extends BuildTarget<?>>>();
for (BuildTargetType<?> type : BuilderRegistry.getInstance().getTargetTypes()) {
myTargets.put(type, type.computeAllTargets(model));
List<? extends BuildTarget<?>> targets = type.computeAllTargets(model);
myTargets.put(type, targets);
targetsByType.add(targets);
}
myDependencies = new HashMap<BuildTarget<?>, Collection<BuildTarget<?>>>();
myAllTargets = ContainerUtil.concat(targetsByType);
}
@NotNull
@Override
public <T extends BuildTarget<?>> List<T> getAllTargets(@NotNull BuildTargetType<T> type) {
//noinspection unchecked
return (List<T>)myTargets.get(type);
}
@Override
public List<BuildTargetChunk> getSortedTargetChunks() {
initializeChunks();
return myTargetChunks;
}
private synchronized void initializeChunks() {
if (myTargetChunks != null) {
return;
}
for (BuildTarget<?> target : getAllTargets()) {
myDependencies.put(target, target.computeDependencies());
}
GraphGenerator<BuildTarget<?>>
graph = GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph<BuildTarget<?>>() {
@Override
public Collection<BuildTarget<?>> getNodes() {
return myAllTargets;
}
@Override
public Iterator<BuildTarget<?>> getIn(BuildTarget<?> n) {
return myDependencies.get(n).iterator();
}
}));
final DFSTBuilder<BuildTarget<?>> builder = new DFSTBuilder<BuildTarget<?>>(graph);
final TIntArrayList sccs = builder.getSCCs();
myTargetChunks = new ArrayList<BuildTargetChunk>(sccs.size());
sccs.forEach(new TIntProcedure() {
int myTNumber = 0;
public boolean execute(int size) {
final Set<BuildTarget<?>> chunkNodes = new LinkedHashSet<BuildTarget<?>>();
for (int j = 0; j < size; j++) {
final BuildTarget<?> node = builder.getNodeByTNumber(myTNumber + j);
chunkNodes.add(node);
}
myTargetChunks.add(new BuildTargetChunk(chunkNodes));
myTNumber += size;
return true;
}
});
}
@Override
public List<? extends BuildTarget<?>> getAllTargets() {
return myAllTargets;
}
@Override
public Set<BuildTarget<?>> getDependenciesRecursively(BuildTarget<?> target) {
initializeChunks();
LinkedHashSet<BuildTarget<?>> result = new LinkedHashSet<BuildTarget<?>>();
for (BuildTarget<?> dep : myDependencies.get(target)) {
collectDependenciesRecursively(dep, result);
}
return result;
}
private void collectDependenciesRecursively(BuildTarget<?> target, LinkedHashSet<BuildTarget<?>> result) {
if (result.add(target)) {
for (BuildTarget<?> dep : myDependencies.get(target)) {
collectDependenciesRecursively(dep, result);
}
}
}
@NotNull
@Override
public <T extends BuildTarget<?>> Collection<T> getAllTargets(@NotNull BuildTargetType<T> type) {
//noinspection unchecked
return (Collection<T>)myTargets.get(type);
public Collection<BuildTarget<?>> getDependencies(@NotNull BuildTarget<?> target) {
initializeChunks();
return myDependencies.get(target);
}
}
@@ -27,7 +27,7 @@ public class JavaModuleBuildTargetType extends BuildTargetType<ModuleBuildTarget
@NotNull
@Override
public Collection<ModuleBuildTarget> computeAllTargets(@NotNull JpsModel model) {
public List<ModuleBuildTarget> computeAllTargets(@NotNull JpsModel model) {
List<JpsModule> modules = model.getProject().getModules();
List<ModuleBuildTarget> targets = new ArrayList<ModuleBuildTarget>(modules.size());
for (JpsModule module : modules) {
@@ -2,7 +2,7 @@ package org.jetbrains.jps.incremental;
/**
* @see ModuleLevelBuilder
* @see ProjectLevelBuilder
* @see TargetBuilder
*
* @author nik
*/
@@ -18,7 +18,7 @@ public class BuilderRegistry {
static final BuilderRegistry ourInstance = new BuilderRegistry();
}
private final Map<BuilderCategory, List<ModuleLevelBuilder>> myModuleLevelBuilders = new HashMap<BuilderCategory, List<ModuleLevelBuilder>>();
private final List<ProjectLevelBuilder> myProjectLevelBuilders = new ArrayList<ProjectLevelBuilder>();
private final List<TargetBuilder<?>> myTargetBuilders = new ArrayList<TargetBuilder<?>>();
private final Map<String, BuildTargetType<?>> myTargetTypes = new LinkedHashMap<String, BuildTargetType<?>>();
public static BuilderRegistry getInstance() {
@@ -31,7 +31,7 @@ public class BuilderRegistry {
}
for (BuilderService service : JpsServiceManager.getInstance().getExtensions(BuilderService.class)) {
myProjectLevelBuilders.addAll(service.createProjectLevelBuilders());
myTargetBuilders.addAll(service.createBuilders());
final List<? extends ModuleLevelBuilder> moduleLevelBuilders = service.createModuleLevelBuilders();
for (ModuleLevelBuilder builder : moduleLevelBuilders) {
myModuleLevelBuilders.get(builder.getCategory()).add(builder);
@@ -79,7 +79,7 @@ public class BuilderRegistry {
return ContainerUtil.concat(myModuleLevelBuilders.values());
}
public List<ProjectLevelBuilder> getProjectLevelBuilders() {
return myProjectLevelBuilders;
public List<TargetBuilder<?>> getTargetBuilders() {
return myTargetBuilders;
}
}
@@ -20,7 +20,7 @@ public abstract class BuilderService {
}
@NotNull
public List<? extends ProjectLevelBuilder> createProjectLevelBuilders() {
public List<? extends TargetBuilder<?>> createBuilders() {
return Collections.emptyList();
}
}
@@ -4,7 +4,6 @@ import com.intellij.openapi.util.UserDataHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.ProjectChunks;
import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.api.CanceledStatus;
import org.jetbrains.jps.cmdline.ProjectDescriptor;
@@ -47,8 +46,6 @@ public interface CompileContext extends UserDataHolder, MessageHandler {
void setDone(float done);
ProjectChunks getChunks();
long getCompilationStartStamp();
void markNonIncremental(ModuleBuildTarget target);
@@ -29,7 +29,6 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon
private final CompileScope myScope;
private final boolean myIsMake;
private final boolean myIsProjectRebuild;
private final ProjectChunks myChunks;
private final MessageHandler myDelegateMessageHandler;
private final Set<ModuleBuildTarget> myNonIncrementalModules = new HashSet<ModuleBuildTarget>();
@@ -55,7 +54,6 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon
myScope = scope;
myIsProjectRebuild = isProjectRebuild;
myIsMake = !isProjectRebuild && isMake;
myChunks = new ProjectChunks(pd.jpsProject);
myDelegateMessageHandler = delegateMessageHandler;
myProjectPaths = new ProjectPaths(pd.jpsProject);
}
@@ -65,11 +63,6 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon
return myCompilationStartStamp;
}
@Override
public ProjectChunks getChunks() {
return myChunks;
}
@Override
public ProjectPaths getProjectPaths() {
return myProjectPaths;
@@ -7,7 +7,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.JpsPathUtil;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.ProjectChunks;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.builders.impl.BuildTargetChunk;
import org.jetbrains.jps.cmdline.ProjectDescriptor;
import org.jetbrains.jps.incremental.fs.BuildFSState;
import org.jetbrains.jps.incremental.fs.RootDescriptor;
@@ -65,21 +66,26 @@ public class FSOperations {
final Set<ModuleBuildTarget> dirtyTargets = new HashSet<ModuleBuildTarget>(targets);
// now mark all modules that depend on dirty modules
final JpsJavaClasspathKind classpathKind = JpsJavaClasspathKind.compile(chunk.isTests());
final ProjectChunks chunks = context.getChunks();
final JpsJavaClasspathKind classpathKind = JpsJavaClasspathKind.compile(chunk.containsTests());
boolean found = false;
for (ModuleChunk moduleChunk : chunks.getChunkList()) {
for (BuildTargetChunk targetChunk : context.getProjectDescriptor().getBuildTargetIndex().getSortedTargetChunks()) {
if (!found) {
if (moduleChunk.equals(chunk)) {
if (targetChunk.getTargets().equals(chunk.getTargets())) {
found = true;
}
}
else {
for (final JpsModule module : moduleChunk.getModules()) {
final Set<JpsModule> deps = getDependentModulesRecursively(module, classpathKind);
if (Utils.intersects(deps, modules)) {
dirtyTargets.addAll(moduleChunk.getTargets());
break;
for (final BuildTarget<?> target : targetChunk.getTargets()) {
if (target instanceof ModuleBuildTarget) {
final Set<JpsModule> deps = getDependentModulesRecursively(((ModuleBuildTarget)target).getModule(), classpathKind);
if (Utils.intersects(deps, modules)) {
for (BuildTarget<?> buildTarget : targetChunk.getTargets()) {
if (buildTarget instanceof ModuleBuildTarget) {
dirtyTargets.add((ModuleBuildTarget)buildTarget);
}
}
break;
}
}
}
}
@@ -16,14 +16,15 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.JpsPathUtil;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.ProjectChunks;
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.impl.BuildTargetChunk;
import org.jetbrains.jps.builders.java.JavaBuilderUtil;
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
import org.jetbrains.jps.builders.java.dependencyView.Callbacks;
@@ -89,8 +90,8 @@ public class IncProjectBuilder {
}
};
private volatile float myModulesProcessed = 0.0f;
private final float myTotalModulesWork;
private volatile float myTargetsProcessed = 0.0f;
private final float myTotalTargetsWork;
private final int myTotalModuleLevelBuilderCount;
private final List<Future> myAsyncTasks = new ArrayList<Future>();
@@ -101,7 +102,7 @@ public class IncProjectBuilder {
myBuilderParams = builderParams;
myCancelStatus = cs;
myConstantSearch = constantSearch;
myTotalModulesWork = pd.jpsProject.getModules().size() * 2; /* multiply by 2 to reflect production and test sources */
myTotalTargetsWork = pd.getBuildTargetIndex().getAllTargets().size();
myTotalModuleLevelBuilderCount = builderRegistry.getModuleLevelBuilderCount();
}
@@ -202,9 +203,9 @@ public class IncProjectBuilder {
}
private float updateFractionBuilderFinished(final float delta) {
myModulesProcessed += delta;
float processed = myModulesProcessed;
return processed / myTotalModulesWork;
myTargetsProcessed += delta;
float processed = myTargetsProcessed;
return processed / myTotalTargetsWork;
}
private void runBuild(CompileContextImpl context, boolean forceCleanCaches) throws ProjectBuildException {
@@ -212,7 +213,7 @@ public class IncProjectBuilder {
LOG.info("Building project; isRebuild:" + context.isProjectRebuild() + "; isMake:" + context.isMake() + " parallel compilation:" + BuildRunner.PARALLEL_BUILD_ENABLED);
for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) {
for (TargetBuilder builder : myBuilderRegistry.getTargetBuilders()) {
builder.buildStarted(context);
}
for (ModuleLevelBuilder builder : myBuilderRegistry.getModuleLevelBuilders()) {
@@ -228,10 +229,7 @@ public class IncProjectBuilder {
runTasks(context, myBuilderRegistry.getBeforeTasks());
context.processMessage(new ProgressMessage("Checking sources"));
buildChunks(context, context.getChunks());
context.processMessage(new ProgressMessage("Building project"));
runProjectLevelBuilders(context);
buildChunks(context);
context.processMessage(new ProgressMessage("Running 'after' tasks"));
runTasks(context, myBuilderRegistry.getAfterTasks());
@@ -253,7 +251,7 @@ public class IncProjectBuilder {
//}
}
finally {
for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) {
for (TargetBuilder builder : myBuilderRegistry.getTargetBuilders()) {
builder.buildFinished(context);
}
for (ModuleLevelBuilder builder : myBuilderRegistry.getModuleLevelBuilders()) {
@@ -281,7 +279,7 @@ public class IncProjectBuilder {
clearOutputs(context);
}
else {
for (ModuleBuildTarget target : context.getChunks().getAllTargets()) {
for (BuildTarget<?> target : context.getProjectDescriptor().getBuildTargetIndex().getAllTargets()) {
clearOutputFiles(context, target);
}
}
@@ -325,18 +323,20 @@ public class IncProjectBuilder {
final ProjectPaths paths = context.getProjectPaths();
for (ModuleBuildTarget target : context.getChunks().getAllTargets()) {
final File out = paths.getModuleOutputDir(target.getModule(), target.isTests());
if (out != null) {
rootsToDelete.putValue(out, target);
}
for (JavaModuleBuildTargetType type : JavaModuleBuildTargetType.ALL_TYPES) {
for (ModuleBuildTarget target : context.getProjectDescriptor().getBuildTargetIndex().getAllTargets(type)) {
final File out = paths.getModuleOutputDir(target.getModule(), target.isTests());
if (out != null) {
rootsToDelete.putValue(out, target);
}
final ProcessorConfigProfile profile = context.getAnnotationProcessingProfile(target.getModule());
if (profile.isEnabled()) {
File annotationOut =
paths.getAnnotationProcessorGeneratedSourcesOutputDir(target.getModule(), target.isTests(), profile.getGeneratedSourcesDirectoryName());
if (annotationOut != null) {
annotationOutputs.add(annotationOut);
final ProcessorConfigProfile profile = context.getAnnotationProcessingProfile(target.getModule());
if (profile.isEnabled()) {
File annotationOut =
paths.getAnnotationProcessorGeneratedSourcesOutputDir(target.getModule(), target.isTests(), profile.getGeneratedSourcesDirectoryName());
if (annotationOut != null) {
annotationOutputs.add(annotationOut);
}
}
}
}
@@ -390,36 +390,28 @@ public class IncProjectBuilder {
);
}
private static void appendRootInfo(Map<File, Set<ModuleBuildTarget>> rootsToDelete, File out, ModuleBuildTarget target) {
Set<ModuleBuildTarget> infos = rootsToDelete.get(out);
if (infos == null) {
infos = new HashSet<ModuleBuildTarget>();
rootsToDelete.put(out, infos);
}
infos.add(target);
}
private static void runTasks(CompileContext context, final List<BuildTask> tasks) throws ProjectBuildException {
for (BuildTask task : tasks) {
task.build(context);
}
}
private void buildChunks(final CompileContextImpl context, ProjectChunks chunks) throws ProjectBuildException {
private void buildChunks(final CompileContextImpl context) throws ProjectBuildException {
final CompileScope scope = context.getScope();
final ProjectDescriptor pd = context.getProjectDescriptor();
BuildTargetIndex targetIndex = pd.getBuildTargetIndex();
try {
if (BuildRunner.PARALLEL_BUILD_ENABLED) {
final List<ChunkGroup> chunkGroups = buildChunkGroups(chunks);
final List<ChunkGroup> chunkGroups = buildChunkGroups(targetIndex);
for (ChunkGroup group : chunkGroups) {
final List<ModuleChunk> groupChunks = group.getChunks();
final List<BuildTargetChunk> groupChunks = group.getChunks();
final int chunkCount = groupChunks.size();
if (chunkCount == 0) {
continue;
}
try {
if (chunkCount == 1) {
_buildChunk(createContextWrapper(context), scope, groupChunks.iterator().next());
buildChunkIfAffected(createContextWrapper(context), scope, groupChunks.iterator().next());
}
else {
final CountDownLatch latch = new CountDownLatch(chunkCount);
@@ -427,19 +419,19 @@ public class IncProjectBuilder {
if (LOG.isDebugEnabled()) {
final StringBuilder logBuilder = new StringBuilder("Building chunks in parallel: ");
for (ModuleChunk chunk : groupChunks) {
logBuilder.append(chunk.getName()).append("; ");
for (BuildTargetChunk chunk : groupChunks) {
logBuilder.append(chunk.toString()).append("; ");
}
LOG.debug(logBuilder.toString());
}
for (final ModuleChunk chunk : groupChunks) {
for (final BuildTargetChunk chunk : groupChunks) {
final CompileContext chunkLocalContext = createContextWrapper(context);
myParallelBuildExecutor.execute(new Runnable() {
@Override
public void run() {
try {
_buildChunk(chunkLocalContext, scope, chunk);
buildChunkIfAffected(chunkLocalContext, scope, chunk);
}
catch (Throwable e) {
synchronized (exRef) {
@@ -482,9 +474,9 @@ public class IncProjectBuilder {
}
else {
// non-parallel build
for (ModuleChunk chunk : chunks.getChunkList()) {
for (BuildTargetChunk chunk : targetIndex.getSortedTargetChunks()) {
try {
_buildChunk(context, scope, chunk);
buildChunkIfAffected(context, scope, chunk);
}
finally {
pd.dataManager.closeSourceToOutputStorages(Collections.singleton(chunk));
@@ -498,18 +490,18 @@ public class IncProjectBuilder {
}
}
private void _buildChunk(CompileContext context, CompileScope scope, ModuleChunk chunk) throws ProjectBuildException {
private void buildChunkIfAffected(CompileContext context, CompileScope scope, BuildTargetChunk chunk) throws ProjectBuildException {
if (isAffected(scope, chunk)) {
buildChunk(context, chunk);
buildTargetsChunk(context, chunk);
}
else {
final float fraction = updateFractionBuilderFinished(chunk.getModules().size());
final float fraction = updateFractionBuilderFinished(chunk.getTargets().size());
context.setDone(fraction);
}
}
private static boolean isAffected(CompileScope scope, ModuleChunk chunk) {
for (ModuleBuildTarget target : chunk.getTargets()) {
private static boolean isAffected(CompileScope scope, BuildTargetChunk chunk) {
for (BuildTarget<?> target : chunk.getTargets()) {
if (scope.isAffected(target)) {
return true;
}
@@ -517,7 +509,47 @@ public class IncProjectBuilder {
return false;
}
private void buildChunk(CompileContext context, final ModuleChunk chunk) throws ProjectBuildException {
private void buildTargetsChunk(CompileContext context, final BuildTargetChunk chunk) throws ProjectBuildException {
Set<BuildTarget<?>> targets = chunk.getTargets();
if (targets.size() > 1) {
Set<ModuleBuildTarget> moduleTargets = new HashSet<ModuleBuildTarget>();
for (BuildTarget<?> target : targets) {
if (target instanceof ModuleBuildTarget) {
moduleTargets.add((ModuleBuildTarget)target);
}
else {
context.processMessage(new CompilerMessage(BUILD_NAME, BuildMessage.Kind.ERROR, "Cannot build " + target.getPresentableName() + " because it is included into a circular dependency"));
return;
}
}
buildModuleChunk(context, new ModuleChunk(moduleTargets));
}
BuildTarget<?> target = targets.iterator().next();
if (target instanceof ModuleBuildTarget) {
ModuleBuildTarget moduleBuildTarget = (ModuleBuildTarget)target;
buildModuleChunk(context, new ModuleChunk(Collections.singleton(moduleBuildTarget)));
}
else {
buildTarget(target, context);
}
}
private static void buildTarget(BuildTarget<?> target, CompileContext context) throws ProjectBuildException {
for (TargetBuilder<?> builder : BuilderRegistry.getInstance().getTargetBuilders()) {
buildTarget(target, context, builder);
}
}
private static <B extends BuildTarget<?>> void buildTarget(B target, CompileContext context, TargetBuilder<?> builder) throws ProjectBuildException {
if (builder.getTargetTypes().contains(target.getTargetType())) {
//noinspection unchecked
((TargetBuilder<B>)builder).build(target, context);
context.checkCanceled();
}
}
private void buildModuleChunk(CompileContext context, final ModuleChunk chunk) throws ProjectBuildException {
boolean doneSomething = false;
try {
Utils.ERRORS_DETECTED_KEY.set(context, Boolean.FALSE);
@@ -541,7 +573,7 @@ public class IncProjectBuilder {
try {
for (BuilderCategory category : BuilderCategory.values()) {
for (ModuleLevelBuilder builder : myBuilderRegistry.getBuilders(category)) {
builder.cleanupResources(context, chunk);
builder.cleanupChunkResources(context);
}
}
}
@@ -748,9 +780,9 @@ public class IncProjectBuilder {
if (buildResult == ModuleLevelBuilder.ExitCode.ADDITIONAL_PASS_REQUIRED) {
if (!nextPassRequired) {
// recalculate basis
myModulesProcessed -= (buildersPassed * modulesInChunk) / stageCount;
myTargetsProcessed -= (buildersPassed * modulesInChunk) / stageCount;
stageCount += myTotalModuleLevelBuilderCount;
myModulesProcessed += (buildersPassed * modulesInChunk) / stageCount;
myTargetsProcessed += (buildersPassed * modulesInChunk) / stageCount;
}
nextPassRequired = true;
}
@@ -763,7 +795,7 @@ public class IncProjectBuilder {
// forcibly mark all files in the chunk dirty
FSOperations.markDirty(context, chunk);
// reverting to the beginning
myModulesProcessed -= (buildersPassed * modulesInChunk) / stageCount;
myTargetsProcessed -= (buildersPassed * modulesInChunk) / stageCount;
stageCount = myTotalModuleLevelBuilderCount;
buildersPassed = 0;
nextPassRequired = true;
@@ -790,13 +822,6 @@ public class IncProjectBuilder {
return doneSomething;
}
private void runProjectLevelBuilders(CompileContext context) throws ProjectBuildException {
for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) {
builder.build(context);
context.checkCanceled();
}
}
private static void syncOutputFiles(final CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
final BuildDataManager dataManager = context.getProjectDescriptor().dataManager;
try {
@@ -854,19 +879,19 @@ public class IncProjectBuilder {
}
}
private static List<ChunkGroup> buildChunkGroups(ProjectChunks chunks) {
final List<ModuleChunk> allChunks = chunks.getChunkList();
private static List<ChunkGroup> buildChunkGroups(BuildTargetIndex index) {
final List<BuildTargetChunk> allChunks = index.getSortedTargetChunks();
// building aux dependencies map
final Map<ModuleBuildTarget, Set<ModuleBuildTarget>> depsMap = new HashMap<ModuleBuildTarget, Set<ModuleBuildTarget>>();
for (ModuleBuildTarget target : chunks.getAllTargets()) {
depsMap.put(target, chunks.getDependenciesRecursively(target));
final Map<BuildTarget<?>, Set<BuildTarget<?>>> depsMap = new HashMap<BuildTarget<?>, Set<BuildTarget<?>>>();
for (BuildTarget target : index.getAllTargets()) {
depsMap.put(target, index.getDependenciesRecursively(target));
}
final List<ChunkGroup> groups = new ArrayList<ChunkGroup>();
ChunkGroup currentGroup = new ChunkGroup();
groups.add(currentGroup);
for (ModuleChunk chunk : allChunks) {
for (BuildTargetChunk chunk : allChunks) {
if (dependsOnGroup(chunk, currentGroup, depsMap)) {
currentGroup = new ChunkGroup();
groups.add(currentGroup);
@@ -877,10 +902,10 @@ public class IncProjectBuilder {
}
public static boolean dependsOnGroup(ModuleChunk chunk, ChunkGroup group, Map<ModuleBuildTarget, Set<ModuleBuildTarget>> depsMap) {
for (ModuleChunk groupChunk : group.getChunks()) {
final Set<ModuleBuildTarget> groupChunkTargets = groupChunk.getTargets();
for (ModuleBuildTarget target : chunk.getTargets()) {
private static boolean dependsOnGroup(BuildTargetChunk chunk, ChunkGroup group, Map<BuildTarget<?>, Set<BuildTarget<?>>> depsMap) {
for (BuildTargetChunk groupChunk : group.getChunks()) {
final Set<BuildTarget<?>> groupChunkTargets = groupChunk.getTargets();
for (BuildTarget<?> target : chunk.getTargets()) {
if (ContainerUtil.intersects(depsMap.get(target), groupChunkTargets)) {
return true;
}
@@ -999,13 +1024,13 @@ public class IncProjectBuilder {
}
private static class ChunkGroup {
private final List<ModuleChunk> myChunks = new ArrayList<ModuleChunk>();
private final List<BuildTargetChunk> myChunks = new ArrayList<BuildTargetChunk>();
public void addChunk(ModuleChunk chunk) {
public void addChunk(BuildTargetChunk chunk) {
myChunks.add(chunk);
}
public List<ModuleChunk> getChunks() {
public List<BuildTargetChunk> getChunks() {
return myChunks;
}
}
@@ -55,12 +55,12 @@ public class ModuleBuildTarget extends BuildTarget<RootDescriptor> {
}
@Override
public Collection<ModuleBuildTarget> computeDependencies() {
public Collection<BuildTarget<?>> computeDependencies() {
JpsJavaDependenciesEnumerator enumerator = JpsJavaExtensionService.dependencies(myModule).compileOnly();
if (!isTests()) {
enumerator.productionOnly();
}
final List<ModuleBuildTarget> dependencies = new ArrayList<ModuleBuildTarget>();
final List<BuildTarget<?>> dependencies = new ArrayList<BuildTarget<?>>();
enumerator.processModules(new Consumer<JpsModule>() {
@Override
public void consume(JpsModule module) {
@@ -93,6 +93,12 @@ public class ModuleBuildTarget extends BuildTarget<RootDescriptor> {
return ContainerUtil.getFirstItem(descriptors);
}
@NotNull
@Override
public String getPresentableName() {
return "Module '" + myModuleName + "' " + (myTargetType.isTests() ? "production" : "tests");
}
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -31,6 +31,6 @@ public abstract class ModuleLevelBuilder extends Builder {
return myCategory;
}
public void cleanupResources(CompileContext context, ModuleChunk chunk) {
public void cleanupChunkResources(CompileContext context) {
}
}
@@ -1,13 +0,0 @@
package org.jetbrains.jps.incremental;
/**
* Use {@link BuilderService} to register implementations of this class
* @author nik
*/
public abstract class ProjectLevelBuilder extends Builder {
protected ProjectLevelBuilder() {
}
public abstract void build(CompileContext context) throws ProjectBuildException;
}
@@ -0,0 +1,26 @@
package org.jetbrains.jps.incremental;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.builders.BuildTargetType;
import java.util.Collection;
/**
* Use {@link BuilderService} to register implementations of this class
* @author nik
*/
public abstract class TargetBuilder<B extends BuildTarget<?>> extends Builder {
private final Collection<? extends BuildTargetType<? extends B>> myTargetTypes;
protected TargetBuilder(Collection<? extends BuildTargetType<? extends B>> targetTypes) {
myTargetTypes = targetTypes;
}
public Collection<? extends BuildTargetType<? extends B>> getTargetTypes() {
return myTargetTypes;
}
public abstract void build(@NotNull B target, @NotNull CompileContext context) throws ProjectBuildException;
}
@@ -1,21 +1,29 @@
package org.jetbrains.jps.incremental.artifacts;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.builders.BuildRootDescriptor;
import org.jetbrains.jps.builders.BuildRootIndex;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
import org.jetbrains.jps.incremental.ModuleBuildTarget;
import org.jetbrains.jps.incremental.ModuleRootsIndex;
import org.jetbrains.jps.incremental.artifacts.builders.LayoutElementBuildersRegistry;
import org.jetbrains.jps.incremental.artifacts.impl.JpsArtifactUtil;
import org.jetbrains.jps.incremental.artifacts.instructions.*;
import org.jetbrains.jps.model.JpsModel;
import org.jetbrains.jps.model.artifact.JpsArtifact;
import org.jetbrains.jps.model.artifact.elements.JpsCompositePackagingElement;
import org.jetbrains.jps.model.artifact.elements.JpsArtifactOutputPackagingElement;
import org.jetbrains.jps.model.artifact.elements.JpsPackagingElement;
import org.jetbrains.jps.model.java.JpsProductionModuleOutputPackagingElement;
import org.jetbrains.jps.model.java.JpsTestModuleOutputPackagingElement;
import org.jetbrains.jps.model.module.JpsModule;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
/**
@@ -39,8 +47,36 @@ public class ArtifactBuildTarget extends BuildTarget<ArtifactRootDescriptor> {
}
@Override
public Collection<? extends BuildTarget<?>> computeDependencies() {
return Collections.emptyList();
public Collection<BuildTarget<?>> computeDependencies() {
final LinkedHashSet<BuildTarget<?>> dependencies = new LinkedHashSet<BuildTarget<?>>();
JpsArtifactUtil.processPackagingElements(myArtifact.getRootElement(), new Processor<JpsPackagingElement>() {
@Override
public boolean process(JpsPackagingElement element) {
if (element instanceof JpsArtifactOutputPackagingElement) {
JpsArtifact included = ((JpsArtifactOutputPackagingElement)element).getArtifactReference().resolve();
if (included != null && !included.equals(myArtifact)) {
if (!StringUtil.isEmpty(included.getOutputPath())) {
dependencies.add(new ArtifactBuildTarget(included));
return false;
}
}
}
else if (element instanceof JpsProductionModuleOutputPackagingElement) {
JpsModule module = ((JpsProductionModuleOutputPackagingElement)element).getModuleReference().resolve();
if (module != null) {
dependencies.add(new ModuleBuildTarget(module, JavaModuleBuildTargetType.PRODUCTION));
}
}
else if (element instanceof JpsTestModuleOutputPackagingElement) {
JpsModule module = ((JpsTestModuleOutputPackagingElement)element).getModuleReference().resolve();
if (module != null) {
dependencies.add(new ModuleBuildTarget(module, JavaModuleBuildTargetType.TEST));
}
}
return true;
}
});
return dependencies;
}
@Override
@@ -68,11 +104,10 @@ public class ArtifactBuildTarget extends BuildTarget<ArtifactRootDescriptor> {
@Override
public List<ArtifactRootDescriptor> computeRootDescriptors(JpsModel model, ModuleRootsIndex index) {
ArtifactInstructionsBuilderImpl builder = new ArtifactInstructionsBuilderImpl(index, this);
final JpsCompositePackagingElement rootElement = myArtifact.getRootElement();
ArtifactInstructionsBuilderContext context = new ArtifactInstructionsBuilderContextImpl(model, new ProjectPaths(model.getProject()));
String outputPath = StringUtil.notNullize(myArtifact.getOutputPath());//todo[nik] implement simplified instructions generation which only collect roots
String outputPath = StringUtil.notNullize(myArtifact.getOutputPath());
final CopyToDirectoryInstructionCreator instructionCreator = new CopyToDirectoryInstructionCreator(builder, outputPath);
LayoutElementBuildersRegistry.getInstance().generateInstructions(rootElement, instructionCreator, context);
LayoutElementBuildersRegistry.getInstance().generateInstructions(myArtifact, instructionCreator, context);
return builder.getDescriptors();
}
@@ -81,4 +116,10 @@ public class ArtifactBuildTarget extends BuildTarget<ArtifactRootDescriptor> {
BuildRootIndex rootIndex) {
return rootIndex.getTargetRoots(this, null).get(Integer.valueOf(rootId));
}
@NotNull
@Override
public String getPresentableName() {
return "Artifact '" + myArtifact.getName() + "'";
}
}
@@ -1,12 +1,12 @@
package org.jetbrains.jps.incremental.artifacts;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.builders.BuildTargetLoader;
import org.jetbrains.jps.builders.BuildTargetType;
import org.jetbrains.jps.model.JpsModel;
import org.jetbrains.jps.model.artifact.JpsArtifact;
import org.jetbrains.jps.model.artifact.JpsArtifactService;
import java.util.*;
@@ -22,11 +22,13 @@ public class ArtifactBuildTargetType extends BuildTargetType<ArtifactBuildTarget
@NotNull
@Override
public Collection<ArtifactBuildTarget> computeAllTargets(@NotNull JpsModel model) {
public List<ArtifactBuildTarget> computeAllTargets(@NotNull JpsModel model) {
Collection<JpsArtifact> artifacts = JpsBuilderArtifactService.getInstance().getArtifacts(model, true);
List<ArtifactBuildTarget> targets = new ArrayList<ArtifactBuildTarget>(artifacts.size());
for (JpsArtifact artifact : artifacts) {
targets.add(new ArtifactBuildTarget(artifact));
if (!StringUtil.isEmpty(artifact.getOutputPath())) {
targets.add(new ArtifactBuildTarget(artifact));
}
}
return targets;
}
@@ -42,7 +44,7 @@ public class ArtifactBuildTargetType extends BuildTargetType<ArtifactBuildTarget
public Loader(JpsModel model) {
myArtifacts = new HashMap<String, JpsArtifact>();
for (JpsArtifact artifact : JpsArtifactService.getInstance().getArtifacts(model.getProject())) {
for (JpsArtifact artifact : JpsBuilderArtifactService.getInstance().getArtifacts(model, true)) {
myArtifacts.put(artifact.getName(), artifact);
}
}
@@ -3,7 +3,7 @@ package org.jetbrains.jps.incremental.artifacts;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.builders.BuildTargetType;
import org.jetbrains.jps.incremental.BuilderService;
import org.jetbrains.jps.incremental.ProjectLevelBuilder;
import org.jetbrains.jps.incremental.TargetBuilder;
import java.util.Collections;
import java.util.List;
@@ -19,7 +19,7 @@ public class ArtifactBuilderService extends BuilderService {
@NotNull
@Override
public List<? extends ProjectLevelBuilder> createProjectLevelBuilders() {
public List<? extends TargetBuilder<?>> createBuilders() {
return Collections.singletonList(new IncArtifactBuilder());
}
}
@@ -6,6 +6,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.MultiMap;
import gnu.trove.THashSet;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.builders.BuildRootDescriptor;
import org.jetbrains.jps.builders.BuildRootIndex;
import org.jetbrains.jps.cmdline.ProjectDescriptor;
@@ -18,7 +19,6 @@ 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.storage.SourceToOutputMapping;
import org.jetbrains.jps.model.JpsModel;
import org.jetbrains.jps.model.artifact.JpsArtifact;
import java.io.File;
@@ -28,48 +28,31 @@ import java.util.*;
/**
* @author nik
*/
public class IncArtifactBuilder extends ProjectLevelBuilder {
public class IncArtifactBuilder extends TargetBuilder<ArtifactBuildTarget> {
public static final String BUILDER_NAME = "artifacts";
public IncArtifactBuilder() {
super();
super(Collections.singletonList(ArtifactBuildTargetType.INSTANCE));
}
@Override
public void build(CompileContext context) throws ProjectBuildException {
Set<JpsArtifact> affected = new HashSet<JpsArtifact>();
JpsBuilderArtifactService artifactService = JpsBuilderArtifactService.getInstance();
JpsModel model = context.getProjectDescriptor().jpsModel;
for (JpsArtifact artifact : artifactService.getArtifacts(model, false)) {
if (context.getScope().isAffected(new ArtifactBuildTarget(artifact))) {
affected.add(artifact);
}
public void build(@NotNull ArtifactBuildTarget target, @NotNull CompileContext context) throws ProjectBuildException {
JpsArtifact artifact = target.getArtifact();
if (StringUtil.isEmpty(artifact.getOutputPath())) {
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot build '" + artifact.getName() + "' artifact: output path is not specified"));
return;
}
affected.addAll(artifactService.getSyntheticArtifacts(model));
final Set<JpsArtifact> toBuild = ArtifactSorter.addIncludedArtifacts(affected);
final ArtifactSorter sorter = new ArtifactSorter(model);
final Map<JpsArtifact, JpsArtifact> selfIncludingNameMap = sorter.getArtifactToSelfIncludingNameMap();
for (JpsArtifact artifact : sorter.getArtifactsSortedByInclusion()) {
context.checkCanceled();
if (toBuild.contains(artifact)) {
final JpsArtifact selfIncluding = selfIncludingNameMap.get(artifact);
if (selfIncluding != null) {
String name = selfIncluding.equals(artifact) ? "it" : "'" + selfIncluding.getName() + "' artifact";
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot build '" + artifact.getName() + "' artifact: " + name + " includes itself in the output layout"));
break;
}
if (StringUtil.isEmpty(artifact.getOutputPath())) {
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot build '" + artifact.getName() + "' artifact: output path is not specified"));
break;
}
buildArtifact(new ArtifactBuildTarget(artifact), context);
}
}
}
private static void buildArtifact(ArtifactBuildTarget target, final CompileContext context) throws ProjectBuildException {
final ProjectDescriptor pd = context.getProjectDescriptor();
final ArtifactSorter sorter = new ArtifactSorter(pd.jpsModel);
final Map<JpsArtifact, JpsArtifact> selfIncludingNameMap = sorter.getArtifactToSelfIncludingNameMap();
final JpsArtifact selfIncluding = selfIncludingNameMap.get(artifact);
if (selfIncluding != null) {
String name = selfIncluding.equals(artifact) ? "it" : "'" + selfIncluding.getName() + "' artifact";
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot build '" + artifact.getName() + "' artifact: " + name + " includes itself in the output layout"));
return;
}
try {
final ArtifactSourceFilesState state = pd.dataManager.getArtifactsBuildData().getOrCreateState(target, pd);
state.ensureFsStateInitialized(pd.dataManager, context);
@@ -80,7 +63,7 @@ public class IncArtifactBuilder extends ProjectLevelBuilder {
return;
}
context.processMessage(new ProgressMessage("Building artifact '" + target.getArtifact().getName() + "'..."));
context.processMessage(new ProgressMessage("Building artifact '" + artifact.getName() + "'..."));
final SourceToOutputMapping srcOutMapping = pd.dataManager.getSourceToOutputMap(target);
final ArtifactOutputToSourceMapping outSrcMapping = state.getOrCreateOutSrcMapping();
@@ -147,7 +130,8 @@ public class IncArtifactBuilder extends ProjectLevelBuilder {
srcOutMapping, outSrcMapping);
}
else if (outSrcMapping.getState(destination.getOutputFilePath()) == null) {
outSrcMapping.update(destination.getOutputFilePath(), Collections.<ArtifactOutputToSourceMapping.SourcePathAndRootIndex>emptyList());
outSrcMapping
.update(destination.getOutputFilePath(), Collections.<ArtifactOutputToSourceMapping.SourcePathAndRootIndex>emptyList());
changedJars.add(((JarDestinationInfo)destination).getJarInfo());
}
}
@@ -7,6 +7,7 @@ import com.intellij.util.containers.ClassMap;
import org.jetbrains.jps.JpsPathUtil;
import org.jetbrains.jps.incremental.artifacts.instructions.ArtifactCompilerInstructionCreator;
import org.jetbrains.jps.incremental.artifacts.instructions.ArtifactInstructionsBuilderContext;
import org.jetbrains.jps.incremental.artifacts.instructions.CopyToDirectoryInstructionCreator;
import org.jetbrains.jps.model.artifact.JpsArtifact;
import org.jetbrains.jps.model.artifact.elements.*;
import org.jetbrains.jps.model.java.JpsProductionModuleOutputPackagingElement;
@@ -47,7 +48,12 @@ public class LayoutElementBuildersRegistry {
}
}
public void generateInstructions(JpsPackagingElement layoutElement, ArtifactCompilerInstructionCreator instructionCreator,
public void generateInstructions(JpsArtifact artifact, CopyToDirectoryInstructionCreator creator, ArtifactInstructionsBuilderContext context) {
context.enterArtifact(artifact);
generateInstructions(artifact.getRootElement(), creator, context);
}
private void generateInstructions(JpsPackagingElement layoutElement, ArtifactCompilerInstructionCreator instructionCreator,
ArtifactInstructionsBuilderContext builderContext) {
final LayoutElementBuilderService builder = myBuilders.get(layoutElement.getClass());
if (builder != null) {
@@ -230,7 +236,14 @@ public class LayoutElementBuildersRegistry {
final String outputPath = artifact.getOutputPath();
if (StringUtil.isEmpty(outputPath)) {
generateSubstitutionInstructions(element, instructionCreator, builderContext);
try {
if (builderContext.enterArtifact(artifact)) {
generateSubstitutionInstructions(element, instructionCreator, builderContext);
}
}
finally {
builderContext.leaveArtifact(artifact);
}
return;
}
@@ -1,28 +1,41 @@
package org.jetbrains.jps.incremental.artifacts.impl;
import com.intellij.util.Processor;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.artifact.elements.JpsComplexPackagingElement;
import org.jetbrains.jps.model.artifact.elements.JpsCompositePackagingElement;
import org.jetbrains.jps.model.artifact.elements.JpsPackagingElement;
import java.util.Set;
/**
* @author nik
*/
public class JpsArtifactUtil {
public static boolean processPackagingElements(@NotNull JpsPackagingElement element, @NotNull Processor<JpsPackagingElement> processor) {
public static boolean processPackagingElements(@NotNull JpsPackagingElement element,
@NotNull Processor<JpsPackagingElement> processor) {
return processPackagingElements(element, processor, new HashSet<JpsPackagingElement>());
}
private static boolean processPackagingElements(@NotNull JpsPackagingElement element,
@NotNull Processor<JpsPackagingElement> processor,
final Set<JpsPackagingElement> processed) {
if (!processed.add(element)) {
return false;
}
if (!processor.process(element)) {
return false;
}
if (element instanceof JpsCompositePackagingElement) {
for (JpsPackagingElement child : ((JpsCompositePackagingElement)element).getChildren()) {
processPackagingElements(child, processor);
processPackagingElements(child, processor, processed);
}
}
else if (element instanceof JpsComplexPackagingElement) {
for (JpsPackagingElement child : ((JpsComplexPackagingElement)element).getSubstitution()) {
processPackagingElements(child, processor);
processPackagingElements(child, processor, processed);
}
}
return true;
@@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.model.JpsModel;
import org.jetbrains.jps.model.JpsProject;
import org.jetbrains.jps.model.artifact.JpsArtifact;
/**
* @author nik
@@ -16,4 +17,8 @@ public interface ArtifactInstructionsBuilderContext {
JpsProject getJpsProject();
JpsModel getJpsModel();
boolean enterArtifact(JpsArtifact artifact);
void leaveArtifact(JpsArtifact artifact);
}
@@ -4,6 +4,10 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.model.JpsModel;
import org.jetbrains.jps.model.JpsProject;
import org.jetbrains.jps.model.artifact.JpsArtifact;
import java.util.HashSet;
import java.util.Set;
/**
* @author nik
@@ -11,12 +15,14 @@ import org.jetbrains.jps.model.JpsProject;
public class ArtifactInstructionsBuilderContextImpl implements ArtifactInstructionsBuilderContext {
private final JpsProject myJpsProject;
private final ProjectPaths myProjectPaths;
private final Set<JpsArtifact> myParentArtifacts;
private JpsModel myModel;
public ArtifactInstructionsBuilderContextImpl(JpsModel jpsModel, ProjectPaths projectPaths) {
myJpsProject = jpsModel.getProject();
myModel = jpsModel;
myProjectPaths = projectPaths;
myParentArtifacts = new HashSet<JpsArtifact>();
}
@Override
@@ -29,6 +35,16 @@ public class ArtifactInstructionsBuilderContextImpl implements ArtifactInstructi
return myModel;
}
@Override
public boolean enterArtifact(JpsArtifact artifact) {
return myParentArtifacts.add(artifact);
}
@Override
public void leaveArtifact(JpsArtifact artifact) {
myParentArtifacts.remove(artifact);
}
@NotNull
@Override
public ProjectPaths getProjectPaths() {
@@ -339,7 +339,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
final int filesCount = files.size();
boolean compiledOk = true;
if (filesCount > 0) {
LOG.info("Compiling " + filesCount + " java files; module: " + chunkName + (chunk.isTests() ? " (tests)" : ""));
LOG.info("Compiling " + filesCount + " java files; module: " + chunkName + (chunk.containsTests() ? " (tests)" : ""));
if (LOG.isDebugEnabled()) {
LOG.debug(" classpath for " + chunkName + ":");
for (File file : classpath) {
@@ -365,7 +365,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
context.processMessage(new ProgressMessage("Instrumenting forms [" + chunkName + "]"));
instrumentForms(context, chunk, chunkSourcePath, finder, forms, outputSink);
JpsUiDesignerConfiguration configuration = JpsUiDesignerExtensionService.getInstance().getUiDesignerConfiguration(pd.jpsProject);
if (configuration != null && configuration.isCopyFormsRuntimeToOutput() && !chunk.isTests()) {
if (configuration != null && configuration.isCopyFormsRuntimeToOutput() && !chunk.containsTests()) {
for (JpsModule module : chunk.getModules()) {
final File outputDir = paths.getModuleOutputDir(module, false);
if (outputDir != null) {
@@ -760,7 +760,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
}
final File srcOutput = context.getProjectPaths()
.getAnnotationProcessorGeneratedSourcesOutputDir(chunk.getModules().iterator().next(), chunk.isTests(),
.getAnnotationProcessorGeneratedSourcesOutputDir(chunk.getModules().iterator().next(), chunk.containsTests(),
profile.getGeneratedSourcesDirectoryName());
if (srcOutput != null) {
srcOutput.mkdirs();
@@ -874,7 +874,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
}
@Override
public void cleanupResources(CompileContext context, ModuleChunk chunk) {
public void cleanupChunkResources(CompileContext context) {
JavaBuilderUtil.cleanupChunkResources(context);
}
@@ -3,10 +3,9 @@ package org.jetbrains.jps.incremental.storage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.builders.impl.BuildTargetChunk;
import org.jetbrains.jps.builders.java.dependencyView.Mappings;
import org.jetbrains.jps.incremental.ModuleBuildTarget;
import org.jetbrains.jps.incremental.artifacts.ArtifactsBuildData;
import java.io.*;
@@ -170,10 +169,10 @@ public class BuildDataManager implements StorageOwner {
}
}
public void closeSourceToOutputStorages(Collection<ModuleChunk> chunks) throws IOException {
public void closeSourceToOutputStorages(Collection<BuildTargetChunk> chunks) throws IOException {
synchronized (mySourceToOutputLock) {
for (ModuleChunk chunk : chunks) {
for (ModuleBuildTarget target : chunk.getTargets()) {
for (BuildTargetChunk chunk : chunks) {
for (BuildTarget<?> target : chunk.getTargets()) {
final SourceToOutputMapping mapping = mySourceToOutputs.remove(target);
if (mapping != null) {
mapping.close();
@@ -61,7 +61,7 @@ public class ModuleClasspathTest extends JpsRebuildTestCase {
private ModuleChunk createChunk(String moduleName) {
def module = myJpsProject.modules.find {it.name == moduleName}
return new ModuleChunk([new ModuleBuildTarget(module, JavaModuleBuildTargetType.PRODUCTION)] as Set, false)
return new ModuleChunk([new ModuleBuildTarget(module, JavaModuleBuildTargetType.PRODUCTION)] as Set)
}
private def assertClasspath(List<String> expected, List<String> classpath) {
@@ -238,6 +238,15 @@ public class ArtifactBuilderTest extends ArtifactBuilderTestCase {
assertBuildFailed(a);
}
public void testArtifactContainingSelfIncludingArtifactWithoutOutput() {
final JpsArtifact a = addArtifact("a", root());
LayoutElementTestUtil.addArtifactToLayout(a, a);
final JpsArtifact b = addArtifact("b", root().artifact(a));
a.setOutputPath(null);
assertBuildFailed(b);
}
//IDEA-73893
public void testManifestFileIsFirstEntry() throws IOException {
final String firstFile = createFile("src/A.txt");
@@ -887,7 +887,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
public static String notNullize(final String s) {
public static String notNullize(final @Nullable String s) {
return notNullize(s, "");
}
+1
View File
@@ -65,6 +65,7 @@
<orderEntry type="module" module-name="android-common" />
<orderEntry type="module" module-name="android-rt" />
<orderEntry type="module" module-name="java-indexing-api" />
<orderEntry type="module" module-name="jps-builders" />
</component>
</module>
@@ -98,6 +98,8 @@ public class AndroidCommonUtils {
@NonNls public static final String ANDROID_MANIFEST_MERGER_PROPERTY = "manifestmerger.enabled";
@NonNls public static final String PROGUARD_CFG_OUTPUT_FILE_NAME = "proguard.txt";
@NonNls public static final String PROJECT_BUILD_TARGET_TYPE_ID = "android-project";
private AndroidCommonUtils() {
}
@@ -1,9 +1,11 @@
package org.jetbrains.jps.android;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.android.builder.AndroidProjectBuildTarget;
import org.jetbrains.jps.builders.BuildTargetType;
import org.jetbrains.jps.incremental.BuilderService;
import org.jetbrains.jps.incremental.ModuleLevelBuilder;
import org.jetbrains.jps.incremental.ProjectLevelBuilder;
import org.jetbrains.jps.incremental.TargetBuilder;
import java.util.Arrays;
import java.util.List;
@@ -12,6 +14,11 @@ import java.util.List;
* @author Eugene.Kudelevsky
*/
public class AndroidBuilderService extends BuilderService {
@Override
public List<? extends BuildTargetType<?>> getTargetTypes() {
return Arrays.asList(AndroidProjectBuildTarget.TargetType.INSTANCE);
}
@NotNull
@Override
public List<? extends ModuleLevelBuilder> createModuleLevelBuilders() {
@@ -21,7 +28,7 @@ public class AndroidBuilderService extends BuilderService {
@NotNull
@Override
public List<? extends ProjectLevelBuilder> createProjectLevelBuilders() {
public List<? extends TargetBuilder<?>> createBuilders() {
return Arrays.asList(new AndroidDexBuilder(),
new AndroidPackagingBuilder());
}
@@ -30,6 +30,7 @@ import org.jetbrains.android.util.AndroidCompilerMessageKind;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.android.builder.AndroidProjectBuildTarget;
import org.jetbrains.jps.android.model.JpsAndroidModuleExtension;
import org.jetbrains.jps.android.model.JpsAndroidSdkProperties;
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
@@ -52,7 +53,7 @@ import java.util.*;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidDexBuilder extends ProjectLevelBuilder {
public class AndroidDexBuilder extends TargetBuilder<AndroidProjectBuildTarget> {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.android.AndroidDexBuilder");
@NonNls private static final String BUILDER_NAME = "android-dex";
@@ -60,9 +61,13 @@ public class AndroidDexBuilder extends ProjectLevelBuilder {
private static final Key<BuildListener> BUILD_LISTENER_KEY = Key.create("BUILD_LISTENER_KEY");
public static final Key<Set<String>> DIRTY_OUTPUT_DIRS = Key.create("DIRTY_OUTPUT_DIRS");
public AndroidDexBuilder() {
super(Collections.singletonList(AndroidProjectBuildTarget.TargetType.INSTANCE));
}
@Override
public void build(CompileContext context) throws ProjectBuildException {
if (!AndroidJpsUtil.containsAndroidFacet(context.getProjectDescriptor().jpsProject) || AndroidJpsUtil.isLightBuild(context)) {
public void build(@NotNull AndroidProjectBuildTarget target, @NotNull CompileContext context) throws ProjectBuildException {
if (target.getKind() != AndroidProjectBuildTarget.AndroidBuilderKind.DEX && AndroidJpsUtil.isLightBuild(context)) {
return;
}
@@ -47,7 +47,7 @@ import java.util.regex.Matcher;
/**
* @author Eugene.Kudelevsky
*/
class AndroidJpsUtil {
public class AndroidJpsUtil {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.android.AndroidJpsUtil");
@NonNls public static final String ANDROID_STORAGE_DIR = "android";
@@ -30,7 +30,7 @@ public class AndroidLibraryPackagingBuilder extends ModuleLevelBuilder {
@Override
public ExitCode build(CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
if (chunk.isTests() || !AndroidJpsUtil.containsAndroidFacet(chunk) || AndroidJpsUtil.isLightBuild(context)) {
if (chunk.containsTests() || !AndroidJpsUtil.containsAndroidFacet(chunk) || AndroidJpsUtil.isLightBuild(context)) {
return ExitCode.NOTHING_DONE;
}
@@ -16,6 +16,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.JpsPathUtil;
import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.android.builder.AndroidProjectBuildTarget;
import org.jetbrains.jps.android.model.JpsAndroidModuleExtension;
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
import org.jetbrains.jps.incremental.*;
@@ -36,11 +37,15 @@ import java.util.*;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidPackagingBuilder extends ProjectLevelBuilder {
public class AndroidPackagingBuilder extends TargetBuilder<AndroidProjectBuildTarget> {
@NonNls private static final String BUILDER_NAME = "android-packager";
@NonNls private static final String RELEASE_SUFFIX = ".release";
@NonNls private static final String UNSIGNED_SUFFIX = ".unsigned";
public AndroidPackagingBuilder() {
super(Collections.singletonList(AndroidProjectBuildTarget.TargetType.INSTANCE));
}
@Override
public String getName() {
return BUILDER_NAME;
@@ -52,8 +57,8 @@ public class AndroidPackagingBuilder extends ProjectLevelBuilder {
}
@Override
public void build(CompileContext context) throws ProjectBuildException {
if (!AndroidJpsUtil.containsAndroidFacet(context.getProjectDescriptor().jpsProject) || AndroidJpsUtil.isLightBuild(context)) {
public void build(@NotNull AndroidProjectBuildTarget target, @NotNull CompileContext context) throws ProjectBuildException {
if (target.getKind() != AndroidProjectBuildTarget.AndroidBuilderKind.PACKAGING || AndroidJpsUtil.isLightBuild(context)) {
return;
}
final Collection<JpsModule> modules = context.getProjectDescriptor().jpsProject.getModules();
@@ -72,7 +72,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder {
@Override
public ModuleLevelBuilder.ExitCode build(CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
if (chunk.isTests() || !AndroidJpsUtil.containsAndroidFacet(chunk)) {
if (chunk.containsTests() || !AndroidJpsUtil.containsAndroidFacet(chunk)) {
return ExitCode.NOTHING_DONE;
}
@@ -0,0 +1,112 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jps.android.builder;
import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.android.AndroidJpsUtil;
import org.jetbrains.jps.builders.*;
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
import org.jetbrains.jps.incremental.ModuleBuildTarget;
import org.jetbrains.jps.incremental.ModuleRootsIndex;
import org.jetbrains.jps.model.JpsModel;
import org.jetbrains.jps.model.module.JpsModule;
import java.util.*;
/**
* @author nik
*/
public class AndroidProjectBuildTarget extends BuildTarget<BuildRootDescriptor> {
public enum AndroidBuilderKind {DEX, PACKAGING}
private final AndroidBuilderKind myKind;
private final JpsModel myModel;
public AndroidProjectBuildTarget(@NotNull AndroidBuilderKind kind, JpsModel model) {
super(TargetType.INSTANCE);
myKind = kind;
myModel = model;
}
@Override
public String getId() {
return myKind.name();
}
public AndroidBuilderKind getKind() {
return myKind;
}
@Override
public Collection<BuildTarget<?>> computeDependencies() {
List<BuildTarget<?>> result = new ArrayList<BuildTarget<?>>();
for (JpsModule module : myModel.getProject().getModules()) {
if (AndroidJpsUtil.getExtension(module) != null) {
result.add(new ModuleBuildTarget(module, JavaModuleBuildTargetType.PRODUCTION));
}
}
return result;
}
@NotNull
@Override
public List<BuildRootDescriptor> computeRootDescriptors(JpsModel model, ModuleRootsIndex index) {
return Collections.emptyList();
}
@Nullable
@Override
public BuildRootDescriptor findRootDescriptor(String rootId, BuildRootIndex rootIndex) {
return null;
}
@NotNull
@Override
public String getPresentableName() {
return "Android " + myKind.name();
}
public static class TargetType extends BuildTargetType<AndroidProjectBuildTarget> {
public static final TargetType INSTANCE = new TargetType();
public TargetType() {
super(AndroidCommonUtils.PROJECT_BUILD_TARGET_TYPE_ID);
}
@NotNull
@Override
public List<AndroidProjectBuildTarget> computeAllTargets(@NotNull JpsModel model) {
if (!AndroidJpsUtil.containsAndroidFacet(model.getProject())) {
return Collections.emptyList();
}
return Arrays.asList(new AndroidProjectBuildTarget(AndroidBuilderKind.DEX, model),
new AndroidProjectBuildTarget(AndroidBuilderKind.PACKAGING, model));
}
@NotNull
@Override
public BuildTargetLoader<AndroidProjectBuildTarget> createLoader(@NotNull final JpsModel model) {
return new BuildTargetLoader<AndroidProjectBuildTarget>() {
@Nullable
@Override
public AndroidProjectBuildTarget createTarget(@NotNull String targetId) {
return new AndroidProjectBuildTarget(AndroidBuilderKind.valueOf(targetId), model);
}
};
}
}
}
+1
View File
@@ -325,6 +325,7 @@
<compileServer.plugin classpath="jps/android-jps-plugin.jar;android-common.jar;android-rt.jar"/>
<compileServer.plugin classpath="sdklib.jar;common.jar;jarutils.jar;androidprefs.jar"/>
<compiler.buildTargetScopeProvider implementation="org.jetbrains.android.compiler.AndroidTargetBuildScopeProvider"/>
<inlineActionHandler implementation="org.jetbrains.android.refactoring.AndroidInlineStyleHandler"/>
<inlineActionHandler implementation="org.jetbrains.android.refactoring.AndroidInlineLayoutHandler" order="first"/>
@@ -603,7 +603,11 @@ public class AndroidCompileUtil {
}
public static boolean isFullBuild(@NotNull CompileContext context) {
final RunConfiguration c = CompileStepBeforeRun.getRunConfiguration(context);
return isFullBuild(context.getCompileScope());
}
public static boolean isFullBuild(@NotNull CompileScope scope) {
final RunConfiguration c = CompileStepBeforeRun.getRunConfiguration(scope);
return c == null || !AndroidCommonUtils.isTestConfiguration(c.getType().getId());
}
@@ -0,0 +1,44 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.android.compiler;
import com.intellij.compiler.impl.BuildTargetScopeProvider;
import com.intellij.facet.ProjectFacetManager;
import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.compiler.CompilerFilter;
import com.intellij.openapi.project.Project;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope;
import java.util.Collections;
import java.util.List;
/**
* @author nik
*/
public class AndroidTargetBuildScopeProvider extends BuildTargetScopeProvider {
@NotNull
@Override
public List<TargetTypeBuildScope> getBuildTargetScopes(@NotNull CompileScope baseScope, @NotNull CompilerFilter filter, @NotNull Project project) {
if (AndroidCompileUtil.isFullBuild(baseScope) && ProjectFacetManager.getInstance(project).hasFacets(AndroidFacet.ID)) {
return Collections
.singletonList(TargetTypeBuildScope.newBuilder().setTypeId(AndroidCommonUtils.PROJECT_BUILD_TARGET_TYPE_ID).setAllTargets(true).build());
}
return Collections.emptyList();
}
}
+1
View File
@@ -26,6 +26,7 @@
<orderEntry type="module" module-name="idea-ui" scope="TEST" />
<orderEntry type="module" module-name="xml" />
<orderEntry type="library" scope="TEST" name="Groovy" level="project" />
<orderEntry type="module" module-name="jps-builders" />
</component>
</module>
@@ -16,6 +16,7 @@
<junitPatcher implementation="org.jetbrains.idea.devkit.run.JUnitDevKitPatcher"/>
<antBuildGen implementation="org.jetbrains.idea.devkit.build.ant.ChunkBuildPluginExtension"/>
<compiler.buildParticipantProvider implementation="org.jetbrains.idea.devkit.build.PluginBuildParticipantProvider"/>
<compiler.buildTargetScopeProvider implementation="org.jetbrains.idea.devkit.build.PluginModuleBuildScopeProvider"/>
<dom.fileDescription implementation="org.jetbrains.idea.devkit.dom.impl.PluginXmlDomFileDescription"/>
<dom.extender domClass="org.jetbrains.idea.devkit.dom.Extensions"
@@ -0,0 +1,51 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.devkit.build;
import com.intellij.compiler.impl.BuildTargetScopeProvider;
import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.compiler.CompilerFilter;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.devkit.module.PluginModuleType;
import org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope;
import org.jetbrains.jps.incremental.artifacts.ArtifactBuildTargetType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author nik
*/
public class PluginModuleBuildScopeProvider extends BuildTargetScopeProvider {
@NotNull
@Override
public List<TargetTypeBuildScope> getBuildTargetScopes(@NotNull CompileScope baseScope, @NotNull CompilerFilter filter, @NotNull Project project) {
List<String> pluginArtifactTargetIds = new ArrayList<String>();
for (Module module : baseScope.getAffectedModules()) {
if (PluginModuleType.isOfType(module)) {
pluginArtifactTargetIds.add(module.getName()+":plugin");
}
}
if (pluginArtifactTargetIds.isEmpty()) {
return Collections.emptyList();
}
return Collections.singletonList(TargetTypeBuildScope.newBuilder().setTypeId(ArtifactBuildTargetType.INSTANCE.getTypeId()).addAllTargetId(pluginArtifactTargetIds).build());
}
}
@@ -167,7 +167,7 @@ public class GroovyBuilder extends ModuleLevelBuilder {
}
@Override
public void cleanupResources(CompileContext context, ModuleChunk chunk) {
public void cleanupChunkResources(CompileContext context) {
JavaBuilderUtil.cleanupChunkResources(context);
STUB_TO_SRC.set(context, null);
}
@@ -288,7 +288,7 @@ public class GroovyBuilder extends ModuleLevelBuilder {
// IMPORTANT! must be the first in classpath
cp.add(getGroovyRtRoot().getPath());
for (File file : context.getProjectPaths().getCompilationClasspathFiles(chunk, chunk.isTests(), false, false)) {
for (File file : context.getProjectPaths().getCompilationClasspathFiles(chunk, chunk.containsTests(), false, false)) {
cp.add(FileUtil.toCanonicalPath(file.getPath()));
}
return new ArrayList<String>(cp);