diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java index 7b66a2565b31..a46ccbfd26b0 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -426,14 +426,17 @@ public class CompileDriver { moduleNames.add(module.getName()); } } - compileContext.getProgressIndicator().setIndeterminate(true); // todo return JpsServerManager.getInstance().submitCompilationTask(myProject.getLocation(), moduleNames, !isMake, new JpsServerResponseHandlerAdapter() { public void handleCompileMessage(JpsRemoteProto.Message.Response.CompileMessage compilerMessage) { final JpsRemoteProto.Message.Response.CompileMessage.Kind kind = compilerMessage.getKind(); //System.out.println(compilerMessage.getText()); if (kind == JpsRemoteProto.Message.Response.CompileMessage.Kind.PROGRESS) { - compileContext.getProgressIndicator().setText(compilerMessage.getText()); + final ProgressIndicator indicator = compileContext.getProgressIndicator(); + indicator.setText(compilerMessage.getText()); + if (compilerMessage.hasDone()) { + indicator.setFraction(compilerMessage.getDone()); + } } else { final CompilerMessageCategory category = kind == JpsRemoteProto.Message.Response.CompileMessage.Kind.ERROR ? CompilerMessageCategory.ERROR diff --git a/jps/jps-builders/proto/jps_remote_proto.proto b/jps/jps-builders/proto/jps_remote_proto.proto index 16735a0aa570..1b9aa1db5d65 100644 --- a/jps/jps-builders/proto/jps_remote_proto.proto +++ b/jps/jps-builders/proto/jps_remote_proto.proto @@ -119,6 +119,7 @@ message Message { optional uint64 problem_location_offset = 6; optional uint64 line = 7; optional uint64 column = 8; + optional float done = 9; } required Type response_type = 1; diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/JpsRemoteProto.java b/jps/jps-builders/src/org/jetbrains/jps/api/JpsRemoteProto.java index 74fbf4a9ca62..633fe78bc433 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/api/JpsRemoteProto.java +++ b/jps/jps-builders/src/org/jetbrains/jps/api/JpsRemoteProto.java @@ -4346,6 +4346,13 @@ public final class JpsRemoteProto { public boolean hasColumn() { return hasColumn; } public long getColumn() { return column_; } + // optional float done = 9; + public static final int DONE_FIELD_NUMBER = 9; + private boolean hasDone; + private float done_ = 0F; + public boolean hasDone() { return hasDone; } + public float getDone() { return done_; } + private void initFields() { kind_ = org.jetbrains.jps.api.JpsRemoteProto.Message.Response.CompileMessage.Kind.ERROR; } @@ -4381,6 +4388,9 @@ public final class JpsRemoteProto { if (hasColumn()) { output.writeUInt64(8, getColumn()); } + if (hasDone()) { + output.writeFloat(9, getDone()); + } } private int memoizedSerializedSize = -1; @@ -4421,6 +4431,10 @@ public final class JpsRemoteProto { size += com.google.protobuf.CodedOutputStream .computeUInt64Size(8, getColumn()); } + if (hasDone()) { + size += com.google.protobuf.CodedOutputStream + .computeFloatSize(9, getDone()); + } memoizedSerializedSize = size; return size; } @@ -4589,6 +4603,9 @@ public final class JpsRemoteProto { if (other.hasColumn()) { setColumn(other.getColumn()); } + if (other.hasDone()) { + setDone(other.getDone()); + } return this; } @@ -4643,6 +4660,10 @@ public final class JpsRemoteProto { setColumn(input.readUInt64()); break; } + case 77: { + setDone(input.readFloat()); + break; + } } } } @@ -4801,6 +4822,24 @@ public final class JpsRemoteProto { return this; } + // optional float done = 9; + public boolean hasDone() { + return result.hasDone(); + } + public float getDone() { + return result.getDone(); + } + public Builder setDone(float value) { + result.hasDone = true; + result.done_ = value; + return this; + } + public Builder clearDone() { + result.hasDone = false; + result.done_ = 0F; + return this; + } + // @@protoc_insertion_point(builder_scope:org.jetbrains.jpsservice.Message.Response.CompileMessage) } diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/ProtoUtil.java b/jps/jps-builders/src/org/jetbrains/jps/api/ProtoUtil.java index db78983aeaba..b055ee5977a1 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/api/ProtoUtil.java +++ b/jps/jps-builders/src/org/jetbrains/jps/api/ProtoUtil.java @@ -132,11 +132,11 @@ public class ProtoUtil { } public static JpsRemoteProto.Message.Response createCompileInfoMessageResponse(String text, String path) { - return createCompileMessageResponse(BuildMessage.Kind.PROGRESS, text, path, -1L, -1L, -1L, -1, -1); + return createCompileMessageResponse(BuildMessage.Kind.PROGRESS, text, path, -1L, -1L, -1L, -1, -1, -1.0f); } - public static JpsRemoteProto.Message.Response createCompileProgressMessageResponse(String text) { - return createCompileMessageResponse(BuildMessage.Kind.PROGRESS, text, null, -1L, -1L, -1L, -1, -1); + public static JpsRemoteProto.Message.Response createCompileProgressMessageResponse(String text, float done) { + return createCompileMessageResponse(BuildMessage.Kind.PROGRESS, text, null, -1L, -1L, -1L, -1, -1, done); } public static JpsRemoteProto.Message.Response createCompileErrorMessageResponse(String text, String path, @@ -145,14 +145,14 @@ public class ProtoUtil { long offset, long line, long column) { - return createCompileMessageResponse(CompilerMessage.Kind.ERROR, text, path, beginOffset, endOffset, offset, line, column); + return createCompileMessageResponse(CompilerMessage.Kind.ERROR, text, path, beginOffset, endOffset, offset, line, column, -1.0f); } public static JpsRemoteProto.Message.Response createCompileMessageResponse(final BuildMessage.Kind kind, String text, String path, long beginOffset, long endOffset, long offset, long line, - long column) { + long column, float done) { final JpsRemoteProto.Message.Response.CompileMessage.Builder builder = JpsRemoteProto.Message.Response.CompileMessage.newBuilder(); switch (kind) { @@ -189,6 +189,9 @@ public class ProtoUtil { if (column > 0L) { builder.setColumn(column); } + if (done >= 0.0f) { + builder.setDone(done); + } return JpsRemoteProto.Message.Response.newBuilder().setResponseType(JpsRemoteProto.Message.Response.Type.COMPILE_MESSAGE).setCompileMessage(builder.build()).build(); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderRegistry.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderRegistry.java index db955fda8707..7840245b8409 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderRegistry.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderRegistry.java @@ -44,6 +44,14 @@ public class BuilderRegistry { } + public int getTotalBuilderCount() { + int count = 0; + for (BuilderCategory category : BuilderCategory.values()) { + count += getBuilders(category).size(); + } + return count; + } + public List getBeforeTasks(){ return Collections.emptyList(); // todo } @@ -53,7 +61,7 @@ public class BuilderRegistry { } public List getBuilders(BuilderCategory category){ - return myBuilders.get(category); // todo + return Collections.unmodifiableList(myBuilders.get(category)); // todo } public void shutdown() { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java index eee53a444b8e..3e0112da48c0 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.ether.dependencyView.Mappings; import org.jetbrains.jps.*; import org.jetbrains.jps.incremental.messages.BuildMessage; +import org.jetbrains.jps.incremental.messages.ProgressMessage; import org.jetbrains.jps.incremental.storage.BuildDataManager; import org.jetbrains.jps.incremental.storage.SourceToOutputMapping; import org.jetbrains.jps.incremental.storage.TimestampStorage; @@ -33,6 +34,7 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler private volatile boolean myErrorsFound = false; private final long myCompilationStartStamp; private final TimestampStorage myTsStorage; + private float myDone = -1.0f; public CompileContext(String projectName, CompileScope scope, boolean isMake, @@ -158,6 +160,9 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler if (msg.getKind() == BuildMessage.Kind.ERROR) { myErrorsFound = true; } + if (msg instanceof ProgressMessage) { + ((ProgressMessage)msg).setDone(myDone); + } myDelegateMessageHandler.processMessage(msg); } @@ -213,6 +218,15 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler return myRootsIndex.getModuleRoots(module); } + public int getTotalModuleCount() { + return myRootsIndex.getTotalModuleCount(); + } + + public void setDone(float done) { + myDone = done; + processMessage(new ProgressMessage("", done)); + } + private static enum DirtyMarkScope{ PRODUCTION, TESTS, BOTH } 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 5ef10b76b2b8..b94e583a36be 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -36,11 +36,17 @@ public class IncProjectBuilder { } }; + private float myModulesProcessed = 0.0f; + private final float myTotalModulesWork; + private final int myTotalBuilderCount; + public IncProjectBuilder(ProjectDescriptor pd, BuilderRegistry builderRegistry) { myProjectDescriptor = pd; myBuilderRegistry = builderRegistry; myProductionChunks = new ProjectChunks(pd.project, ClasspathKind.PRODUCTION_COMPILE); myTestChunks = new ProjectChunks(pd.project, ClasspathKind.TEST_COMPILE); + myTotalModulesWork = (float) pd.rootsIndex.getTotalModuleCount() * 2; /* multiply by 2 to reflect production and test sources */ + myTotalBuilderCount = builderRegistry.getTotalBuilderCount(); } public void addMessageHandler(MessageHandler handler) { @@ -97,7 +103,14 @@ public class IncProjectBuilder { } } + private float updateFractionBuilderFinished(final float delta) { + myModulesProcessed += delta; + return myModulesProcessed / myTotalModulesWork; + } + private void runBuild(CompileContext context) throws ProjectBuildException { + context.setDone(0.0f); + if (context.isProjectRebuild()) { cleanOutputRoots(context); } @@ -198,6 +211,10 @@ public class IncProjectBuilder { if (scope.isAffected(chunk)) { buildChunk(context, chunk); } + else { + final float fraction = updateFractionBuilderFinished(chunk.getModules().size()); + context.setDone(fraction); + } } } @@ -279,18 +296,34 @@ public class IncProjectBuilder { if (builders.isEmpty()) { return; } + + float stageCount = myTotalBuilderCount; + int stagesPassed = 0; + final int modulesInChunk = chunk.getModules().size(); + boolean nextPassRequired; do { nextPassRequired = false; context.beforeNextCompileRound(chunk); for (Builder builder : builders) { final Builder.ExitCode buildResult = builder.build(context, chunk); + if (buildResult == Builder.ExitCode.ABORT) { throw new ProjectBuildException("Builder " + builder.getDescription() + " requested build stop"); } if (buildResult == Builder.ExitCode.ADDITIONAL_PASS_REQUIRED) { + if (!nextPassRequired) { + // recalculate basis + myModulesProcessed -= (stagesPassed * modulesInChunk) / stageCount; + stageCount += myTotalBuilderCount; + myModulesProcessed += (stagesPassed * modulesInChunk) / stageCount; + } nextPassRequired = true; } + + stagesPassed++; + final float fraction = updateFractionBuilderFinished(modulesInChunk / (stageCount)); + context.setDone(fraction); } } while (nextPassRequired); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleRootsIndex.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleRootsIndex.java index 4d63db7b463b..05cd3ba21499 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleRootsIndex.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleRootsIndex.java @@ -16,9 +16,12 @@ import java.util.*; public class ModuleRootsIndex { private final Map myRootToModuleMap = new HashMap(); private final Map> myModuleToRootsMap = new HashMap>(); + private final int myTotalModuleCount; public ModuleRootsIndex(Project project) { - for (Module module : project.getModules().values()) { + final Collection allModules = project.getModules().values(); + myTotalModuleCount = allModules.size(); + for (Module module : allModules) { List moduleRoots = myModuleToRootsMap.get(module); if (moduleRoots == null) { moduleRoots = new ArrayList(); @@ -39,6 +42,10 @@ public class ModuleRootsIndex { } } + public int getTotalModuleCount() { + return myTotalModuleCount; + } + @NotNull public List getModuleRoots(Module module) { final List descriptors = myModuleToRootsMap.get(module); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/ProgressMessage.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/ProgressMessage.java index fc0d306cc25d..a65e4cd37533 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/ProgressMessage.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/ProgressMessage.java @@ -5,7 +5,22 @@ package org.jetbrains.jps.incremental.messages; * Date: 9/29/11 */ public class ProgressMessage extends BuildMessage { + private volatile float myDone; + public ProgressMessage(String messageText) { + this(messageText, -1.0f); + } + + public ProgressMessage(String messageText, float done) { super(messageText, Kind.PROGRESS); + myDone = done; + } + + public float getDone() { + return myDone; + } + + public void setDone(float done) { + myDone = done; } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java b/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java index 3745ee64de48..f7ae9c123d50 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java @@ -7,6 +7,7 @@ import org.jetbrains.jps.api.*; import org.jetbrains.jps.incremental.MessageHandler; import org.jetbrains.jps.incremental.messages.BuildMessage; import org.jetbrains.jps.incremental.messages.CompilerMessage; +import org.jetbrains.jps.incremental.messages.ProgressMessage; import java.io.ByteArrayOutputStream; import java.io.File; @@ -192,11 +193,15 @@ class ServerMessageHandler extends SimpleChannelHandler { response = ProtoUtil.createCompileMessageResponse( compilerMessage.getKind(), text, compilerMessage.getSourcePath(), compilerMessage.getProblemBeginOffset(), compilerMessage.getProblemEndOffset(), - compilerMessage.getProblemLocationOffset(), compilerMessage.getLine(), compilerMessage.getColumn() - ); + compilerMessage.getProblemLocationOffset(), compilerMessage.getLine(), compilerMessage.getColumn(), + -1.0f); } else { - response = ProtoUtil.createCompileProgressMessageResponse(buildMessage.getMessageText()); + float done = -1.0f; + if (buildMessage instanceof ProgressMessage) { + done = ((ProgressMessage)buildMessage).getDone(); + } + response = ProtoUtil.createCompileProgressMessageResponse(buildMessage.getMessageText(), done); } Channels.write(myChannelContext.getChannel(), ProtoUtil.toMessage(mySessionId, response)); }