diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java index 63d8efaf6931..f3a523a402ff 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java +++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java @@ -145,6 +145,7 @@ final class BuildSession implements Runnable, CanceledStatus { } private void runBuild(String projectPath, BuildType buildType, Set modules, Collection artifacts, Map builderParams, Collection paths, final MessageHandler msgHandler, CanceledStatus cs) throws Throwable{ + boolean forceCleanCaches = false; ProjectDescriptor pd; final Project project = loadProject(projectPath); final BuildFSState fsState = new BuildFSState(false); @@ -154,49 +155,70 @@ final class BuildSession implements Runnable, CanceledStatus { try { timestamps = new ProjectTimestamps(dataStorageRoot); dataManager = new BuildDataManager(dataStorageRoot, true); + if (dataManager.versionDiffers()) { + forceCleanCaches = true; + msgHandler.processMessage(new CompilerMessage("build", BuildMessage.Kind.INFO, "Dependency data format has changed, project rebuild required")); + } } catch (Exception e) { // second try - e.printStackTrace(System.err); + LOG.info(e); if (timestamps != null) { timestamps.close(); } if (dataManager != null) { dataManager.close(); } - buildType = BuildType.PROJECT_REBUILD; // force project rebuild + forceCleanCaches = true; FileUtil.delete(dataStorageRoot); timestamps = new ProjectTimestamps(dataStorageRoot); dataManager = new BuildDataManager(dataStorageRoot, true); // second attempt succeded - msgHandler.processMessage(new CompilerMessage("compile-server", BuildMessage.Kind.INFO, "Project rebuild forced: " + e.getMessage())); + msgHandler.processMessage(new CompilerMessage("build", BuildMessage.Kind.INFO, "Project rebuild forced: " + e.getMessage())); } pd = new ProjectDescriptor(project, fsState, timestamps, dataManager, BuildLoggingManager.DEFAULT); try { - final CompileScope compileScope = createCompilationScope(buildType, pd, modules, artifacts, paths); - final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), builderParams, cs); - if (msgHandler != null) { + for (int attempt = 0; attempt < 2; attempt++) { + if (forceCleanCaches && modules.isEmpty() && paths.isEmpty()) { + // if compilation scope is the whole project and cache rebuild is forced, use PROJECT_REBUILD for faster compilation + buildType = BuildType.PROJECT_REBUILD; + } + final CompileScope compileScope = createCompilationScope(buildType, pd, modules, artifacts, paths); + final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), builderParams, cs); builder.addMessageHandler(msgHandler); - } - switch (buildType) { - case PROJECT_REBUILD: - builder.build(compileScope, false, true); - break; + try { + switch (buildType) { + case PROJECT_REBUILD: + builder.build(compileScope, false, true, forceCleanCaches); + break; - case FORCED_COMPILATION: - builder.build(compileScope, false, false); - break; + case FORCED_COMPILATION: + builder.build(compileScope, false, false, forceCleanCaches); + break; - case MAKE: - builder.build(compileScope, true, false); - break; + case MAKE: + builder.build(compileScope, true, false, forceCleanCaches); + break; - case CLEAN: - //todo[nik] - // new ProjectBuilder(new GantBinding(), project).clean(); - break; + case CLEAN: + //todo[nik] + // new ProjectBuilder(new GantBinding(), project).clean(); + break; + } + break; // break attempts loop + } + catch (RebuildRequestedException e) { + // todo: do not try second attempt here; just notify the calling process about "rebuild requested" and end the session + if (attempt == 0) { + LOG.info(e); + forceCleanCaches = true; + } + else { + throw e; + } + } } } finally { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 14547b226f94..c5bf0ff0ab18 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -79,7 +79,7 @@ public class IncProjectBuilder { myMessageHandlers.add(handler); } - public void build(CompileScope scope, final boolean isMake, final boolean isProjectRebuild) { + public void build(CompileScope scope, final boolean isMake, final boolean isProjectRebuild, boolean forceCleanCaches) throws RebuildRequestedException{ final LowMemoryWatcher memWatcher = LowMemoryWatcher.register(new Forceable() { @Override public boolean isDirty() { @@ -94,47 +94,30 @@ public class IncProjectBuilder { }); CompileContext context = null; try { - try { - if (myProjectDescriptor.dataManager.versionDiffers()) { - myMessageDispatcher.processMessage(new CompilerMessage( - COMPILE_SERVER_NAME, BuildMessage.Kind.INFO, "Dependency data format has changed, project rebuild required" - )); - context = createContextForForcedRebuild(scope, isMake, isProjectRebuild); - } - else { - context = createContext(scope, isMake, isProjectRebuild); - } - runBuild(context); - } - catch (ProjectBuildException e) { - final Throwable cause = e.getCause(); - if (cause instanceof PersistentEnumerator.CorruptedException || cause instanceof MappingFailedException || cause instanceof IOException) { - // force rebuild - myMessageDispatcher.processMessage(new CompilerMessage( - COMPILE_SERVER_NAME, BuildMessage.Kind.INFO, - "Internal caches are corrupted or have outdated format, forcing project rebuild: " + - e.getMessage()) - ); - flushContext(context); - context = createContextForForcedRebuild(scope, isMake, isProjectRebuild); - runBuild(context); - } - else { - throw e; - } - } + context = createContext(scope, isMake, isProjectRebuild); + runBuild(context, forceCleanCaches); myProjectDescriptor.dataManager.saveVersion(); } catch (ProjectBuildException e) { final Throwable cause = e.getCause(); - if (cause == null) { - final String msg = e.getMessage(); - if (!StringUtil.isEmpty(msg)) { - myMessageDispatcher.processMessage(new ProgressMessage(msg)); - } + if (cause instanceof PersistentEnumerator.CorruptedException || cause instanceof MappingFailedException || cause instanceof IOException) { + myMessageDispatcher.processMessage(new CompilerMessage( + COMPILE_SERVER_NAME, BuildMessage.Kind.INFO, + "Internal caches are corrupted or have outdated format, forcing project rebuild: " + + e.getMessage()) + ); + throw new RebuildRequestedException(cause); } else { - myMessageDispatcher.processMessage(new CompilerMessage(COMPILE_SERVER_NAME, cause)); + if (cause == null) { + final String msg = e.getMessage(); + if (!StringUtil.isEmpty(msg)) { + myMessageDispatcher.processMessage(new ProgressMessage(msg)); + } + } + else { + myMessageDispatcher.processMessage(new CompilerMessage(COMPILE_SERVER_NAME, cause)); + } } } finally { @@ -152,19 +135,6 @@ public class IncProjectBuilder { } } - private CompileContext createContextForForcedRebuild(CompileScope scope, boolean isMake, boolean isProjectRebuild) throws ProjectBuildException { - final CompileContext context; - if (isMake || isProjectRebuild) { - context = createContext(new AllProjectScope(scope.getProject(), scope.getArtifacts(), true), false, true); - } - else { - //in case of forced compilation keep the scope, but remove all caches - context = createContext(scope, false, false); - cleanOutputRoots(context); - } - return context; - } - private static void flushContext(CompileContext context) { if (context != null) { context.getTimestampStorage().force(); @@ -206,12 +176,12 @@ public class IncProjectBuilder { return myModulesProcessed / myTotalModulesWork; } - private void runBuild(CompileContext context) throws ProjectBuildException { + private void runBuild(CompileContext context, boolean forceCleanCaches) throws ProjectBuildException { context.setDone(0.0f); LOG.info("Building project '" + context.getProject().getProjectName() + "'; isRebuild:" +context.isProjectRebuild() + "; isMake:" + context.isMake()); - if (context.isProjectRebuild()) { + if (context.isProjectRebuild() || forceCleanCaches) { cleanOutputRoots(context); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/RebuildRequestedException.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/RebuildRequestedException.java new file mode 100644 index 000000000000..8b589972430f --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/RebuildRequestedException.java @@ -0,0 +1,17 @@ +package org.jetbrains.jps.incremental; + +/** + * @author Eugene Zhuravlev + * Date: 9/20/11 + */ +public class RebuildRequestedException extends ProjectBuildException{ + + public RebuildRequestedException(Throwable cause) { + super(cause); + } + + @Override + public Throwable fillInStackTrace() { + return this; + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java b/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java index 9e2f3e1be12f..189ba7009f86 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java @@ -130,7 +130,7 @@ class ServerState { public void startBuild(String projectPath, BuildType buildType, Set modules, Collection artifacts, Map builderParams, Collection paths, final MessageHandler msgHandler, CanceledStatus cs) throws Throwable{ - + boolean forceCleanCaches = false; ProjectDescriptor pd; synchronized (myConfigurationLock) { pd = myProjects.get(projectPath); @@ -143,17 +143,21 @@ class ServerState { try { timestamps = new ProjectTimestamps(dataStorageRoot); dataManager = new BuildDataManager(dataStorageRoot, myKeepTempCachesInMemory); + if (dataManager.versionDiffers()) { + forceCleanCaches = true; + msgHandler.processMessage(new CompilerMessage("compile-server", BuildMessage.Kind.INFO, "Dependency data format has changed, project rebuild required")); + } } catch (Exception e) { // second try - e.printStackTrace(System.err); + LOG.info(e); if (timestamps != null) { timestamps.close(); } if (dataManager != null) { dataManager.close(); } - buildType = BuildType.PROJECT_REBUILD; // force project rebuild + forceCleanCaches = true; FileUtil.delete(dataStorageRoot); timestamps = new ProjectTimestamps(dataStorageRoot); dataManager = new BuildDataManager(dataStorageRoot, myKeepTempCachesInMemory); @@ -168,28 +172,44 @@ class ServerState { } try { - final CompileScope compileScope = createCompilationScope(buildType, pd, modules, artifacts, paths); - final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), builderParams, cs); - if (msgHandler != null) { + for (int attempt = 0; attempt < 2; attempt++) { + if (forceCleanCaches && modules.isEmpty() && paths.isEmpty()) { + // if compilation scope is the whole project and cache rebuild is forced, use PROJECT_REBUILD for faster compilation + buildType = BuildType.PROJECT_REBUILD; + } + final CompileScope compileScope = createCompilationScope(buildType, pd, modules, artifacts, paths); + final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), builderParams, cs); builder.addMessageHandler(msgHandler); - } - switch (buildType) { - case PROJECT_REBUILD: - builder.build(compileScope, false, true); - break; + try { + switch (buildType) { + case PROJECT_REBUILD: + builder.build(compileScope, false, true, forceCleanCaches); + break; - case FORCED_COMPILATION: - builder.build(compileScope, false, false); - break; + case FORCED_COMPILATION: + builder.build(compileScope, false, false, forceCleanCaches); + break; - case MAKE: - builder.build(compileScope, true, false); - break; + case MAKE: + builder.build(compileScope, true, false, forceCleanCaches); + break; - case CLEAN: - //todo[nik] - // new ProjectBuilder(new GantBinding(), project).clean(); - break; + case CLEAN: + //todo[nik] + // new ProjectBuilder(new GantBinding(), project).clean(); + break; + } + break; // break attempts loop + } + catch (RebuildRequestedException e) { + if (attempt == 0) { + LOG.info(e); + forceCleanCaches = true; + } + else { + throw e; + } + } } } finally { diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java index 3cc1a7f1dbc0..914eb06882f8 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java @@ -210,7 +210,7 @@ public abstract class IncrementalTestCase extends TestCase { new IncProjectBuilder( projectDescriptor, BuilderRegistry.getInstance(), Collections.emptyMap(), CanceledStatus.NULL ).build( - new AllProjectScope(project, Collections.emptySet(), true), false, true + new AllProjectScope(project, Collections.emptySet(), true), false, true, false ); modify(); @@ -222,7 +222,7 @@ public abstract class IncrementalTestCase extends TestCase { new IncProjectBuilder( projectDescriptor, BuilderRegistry.getInstance(), Collections.emptyMap(), CanceledStatus.NULL ).build( - new AllProjectScope(project, Collections.emptySet(), false), true, false + new AllProjectScope(project, Collections.emptySet(), false), true, false, false ); final String expected = StringUtil.convertLineSeparators(FileUtil.loadFile(new File(getBaseDir() + ".log"))); diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java index 23ff5089af8a..7bf374ff77d5 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java @@ -195,7 +195,12 @@ public abstract class ArtifactBuilderTestCase extends UsefulTestCase { } } }); - builder.build(new AllProjectScope(myDescriptor.project, new HashSet(Arrays.asList(artifacts)), force), !force, false); + try { + builder.build(new AllProjectScope(myDescriptor.project, new HashSet(Arrays.asList(artifacts)), force), !force, false, false); + } + catch (RebuildRequestedException e) { + fail(e.getMessage()); + } if (shouldFail) { assertFalse("Build not failed as expected", errorMessages.isEmpty()); }