event-based hotswap for compile server

This commit is contained in:
Eugene Zhuravlev
2012-01-17 20:26:24 +01:00
parent 5c3df137e8
commit 65376ac093
16 changed files with 605 additions and 43 deletions
@@ -88,6 +88,7 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.containers.OrderedSet;
import com.intellij.util.messages.MessageBus;
import gnu.trove.TIntHashSet;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NonNls;
@@ -425,6 +426,7 @@ public class CompileDriver {
}
}
final JpsServerManager jpsServerManager = JpsServerManager.getInstance();
final MessageBus messageBus = myProject.getMessageBus();
return jpsServerManager.submitCompilationTask(myProject.getLocation(), compileContext.isRebuild(), compileContext.isMake(), moduleNames, paths, new JpsServerResponseHandlerAdapter() {
public void handleCompileMessage(JpsRemoteProto.Message.Response.CompileMessage compilerMessage) {
@@ -467,6 +469,15 @@ public class CompileDriver {
case BUILD_STARTED:
compileContext.getProgressIndicator().setText("Compilation started");
break;
case FILES_GENERATED:
final List<JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile> generated = event.getGeneratedFilesList();
final CompilationStatusListener publisher = messageBus.syncPublisher(CompilerTopics.COMPILATION_STATUS);
for (JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile generatedFile : generated) {
final String root = FileUtil.toSystemIndependentName(generatedFile.getOutputRoot());
final String relativePath = FileUtil.toSystemIndependentName(generatedFile.getRelativePath());
publisher.fileGenerated(root, relativePath);
}
break;
case BUILD_COMPLETED:
ExitStatus status = ExitStatus.SUCCESS;
if (event.hasCompletionStatus()) {
@@ -584,7 +584,7 @@ public class CompilerTask extends Task.Backgroundable {
myUserAcceptedCancel = true;
final MessageBusConnection connection = project.getMessageBus().connect();
connection.subscribe(CompilerTopics.COMPILATION_STATUS, new CompilationStatusListener() {
connection.subscribe(CompilerTopics.COMPILATION_STATUS, new CompilationStatusAdapter() {
public void compilationFinished(boolean aborted, int errors, int warnings, final CompileContext compileContext) {
connection.disconnect();
ProjectUtil.closeAndDispose(project);
@@ -0,0 +1,24 @@
/*
* 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 com.intellij.openapi.compiler;
public class CompilationStatusAdapter implements CompilationStatusListener {
public void compilationFinished(boolean aborted, int errors, int warnings, final CompileContext compileContext) {
}
public void fileGenerated(String outputRoot, String relativePath) {
}
}
@@ -32,4 +32,6 @@ public interface CompilationStatusListener extends EventListener {
* @param compileContext context for the finished compilation
*/
void compilationFinished(boolean aborted, int errors, int warnings, final CompileContext compileContext);
void fileGenerated(String outputRoot, String relativePath);
}
@@ -23,6 +23,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.OrderEnumerator;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
@@ -67,7 +68,7 @@ public class HotSwapManager extends AbstractProjectComponent {
myTimeStamps.put(session, Long.valueOf(tStamp));
}
public Map<String, HotSwapFile> getModifiedClasses(final DebuggerSession session, final HotSwapProgress progress) {
public Map<String, HotSwapFile> scanForModifiedClasses(final DebuggerSession session, final HotSwapProgress progress) {
DebuggerManagerThreadImpl.assertIsManagerThread();
final List<File> outputRoots = new ArrayList<File>();
@@ -125,7 +126,39 @@ public class HotSwapManager extends AbstractProjectComponent {
setTimeStamp(session, newSwapTime);
}
public static Map<DebuggerSession, Map<String, HotSwapFile>> getModifiedClasses(final List<DebuggerSession> sessions, final HotSwapProgress swapProgress) {
public static Map<DebuggerSession, Map<String, HotSwapFile>> findModifiedClasses(List<DebuggerSession> sessions, Map<String, List<String>> generatedPaths) {
final Map<DebuggerSession, Map<String, HotSwapFile>> result = new java.util.HashMap<DebuggerSession, Map<String, HotSwapFile>>();
List<Pair<DebuggerSession, Long>> sessionWithStamps = new ArrayList<Pair<DebuggerSession, Long>>();
for (DebuggerSession session : sessions) {
sessionWithStamps.add(new Pair<DebuggerSession, Long>(session, getInstance(session.getProject()).getTimeStamp(session)));
}
for (Map.Entry<String, List<String>> entry : generatedPaths.entrySet()) {
final File root = new File(entry.getKey());
for (String relativePath : entry.getValue()) {
if (SystemInfo.isFileSystemCaseSensitive? StringUtil.endsWith(relativePath, CLASS_EXTENSION) : StringUtil.endsWithIgnoreCase(relativePath, CLASS_EXTENSION)) {
final String qualifiedName = relativePath.substring(0, relativePath.length() - CLASS_EXTENSION.length()).replace('/', '.');
final HotSwapFile hotswapFile = new HotSwapFile(new File(root, relativePath));
final long fileStamp = hotswapFile.file.lastModified();
for (Pair<DebuggerSession, Long> pair : sessionWithStamps) {
final DebuggerSession session = pair.first;
if (fileStamp > pair.second) {
Map<String, HotSwapFile> container = result.get(session);
if (container == null) {
container = new java.util.HashMap<String, HotSwapFile>();
result.put(session, container);
}
container.put(qualifiedName, hotswapFile);
}
}
}
}
}
return result;
}
public static Map<DebuggerSession, Map<String, HotSwapFile>> scanForModifiedClasses(final List<DebuggerSession> sessions, final HotSwapProgress swapProgress) {
final Map<DebuggerSession, Map<String, HotSwapFile>> modifiedClasses = new HashMap<DebuggerSession, Map<String, HotSwapFile>>();
final MultiProcessCommand scanClassesCommand = new MultiProcessCommand();
@@ -141,7 +174,7 @@ public class HotSwapManager extends AbstractProjectComponent {
scanClassesCommand.addCommand(debuggerSession.getProcess(), new DebuggerCommandImpl() {
protected void action() throws Exception {
swapProgress.setDebuggerSession(debuggerSession);
final Map<String, HotSwapFile> sessionClasses = getInstance(swapProgress.getProject()).getModifiedClasses(debuggerSession, swapProgress);
final Map<String, HotSwapFile> sessionClasses = getInstance(swapProgress.getProject()).scanForModifiedClasses(debuggerSession, swapProgress);
if (!sessionClasses.isEmpty()) {
modifiedClasses.put(debuggerSession, sessionClasses);
}
@@ -41,12 +41,11 @@ import com.intellij.util.PairFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.messages.MessageBus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
/**
* User: lex
@@ -62,7 +61,21 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent{
public HotSwapUIImpl(final Project project, MessageBus bus) {
myProject = project;
bus.connect().subscribe(CompilerTopics.COMPILATION_STATUS, new CompilationStatusListener() {
private final AtomicReference<Map<String, List<String>>> myGeneratedPaths = new AtomicReference<Map<String, List<String>>>(new HashMap<String, List<String>>());
public void fileGenerated(String outputRoot, String relativePath) {
final Map<String, List<String>> map = myGeneratedPaths.get();
List<String> paths = map.get(outputRoot);
if (paths == null) {
paths = new ArrayList<String>();
map.put(outputRoot, paths);
}
paths.add(relativePath);
}
public void compilationFinished(boolean aborted, int errors, int warnings, CompileContext compileContext) {
final Map<String, List<String>> generated = myGeneratedPaths.getAndSet(new HashMap<String, List<String>>());
if (myProject.isDisposed()) {
return;
}
@@ -82,7 +95,7 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent{
}
}
if (!sessions.isEmpty()) {
hotSwapSessions(sessions);
hotSwapSessions(sessions, generated);
}
}
myPerformHotswapAfterThisCompilation = true;
@@ -129,7 +142,7 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent{
return false;
}
private void hotSwapSessions(final List<DebuggerSession> sessions) {
private void hotSwapSessions(final List<DebuggerSession> sessions, @Nullable final Map<String, List<String>> generatedPaths) {
final boolean shouldAskBeforeHotswap = myAskBeforeHotswap;
myAskBeforeHotswap = true;
@@ -148,7 +161,7 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent{
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
final Map<DebuggerSession, Map<String, HotSwapFile>> modifiedClasses = getModifiedClasses(findClassesProgress, sessions);
final Map<DebuggerSession, Map<String, HotSwapFile>> modifiedClasses = generatedPaths == null? scanForModifiedClassesWithProgress(sessions, findClassesProgress) : HotSwapManager.findModifiedClasses(sessions, generatedPaths);
final Application application = ApplicationManager.getApplication();
if (modifiedClasses.isEmpty()) {
@@ -179,7 +192,7 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent{
@Override
public Integer fun(Integer exitCode, JCheckBox cb) {
settings.HOTSWAP_HANG_WARNING_ENABLED = !cb.isSelected();
return exitCode == DialogWrapper.OK_EXIT_CODE? exitCode : DialogWrapper.CANCEL_EXIT_CODE;
return exitCode == DialogWrapper.OK_EXIT_CODE ? exitCode : DialogWrapper.CANCEL_EXIT_CODE;
}
}
);
@@ -203,6 +216,21 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent{
});
}
private static Map<DebuggerSession, Map<String, HotSwapFile>> scanForModifiedClassesWithProgress(final List<DebuggerSession> sessions, final HotSwapProgressImpl progress) {
final Ref<Map<DebuggerSession, Map<String, HotSwapFile>>> result = Ref.create(null);
ProgressManager.getInstance().runProcess(new Runnable() {
public void run() {
try {
result.set(HotSwapManager.scanForModifiedClasses(sessions, progress));
}
finally {
progress.finished();
}
}
}, progress.getProgressIndicator());
return result.get();
}
private static void reloadModifiedClasses(final Map<DebuggerSession, Map<String, HotSwapFile>> modifiedClasses, final HotSwapProgressImpl progress) {
ProgressManager.getInstance().runProcess(new Runnable() {
public void run() {
@@ -212,18 +240,6 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent{
}, progress.getProgressIndicator());
}
private static Map<DebuggerSession, Map<String, HotSwapFile>> getModifiedClasses(final HotSwapProgressImpl swapProgress, final List<DebuggerSession> sessions) {
final Ref<Map<DebuggerSession, Map<String, HotSwapFile>>> modifiedClasses = Ref.create(null);
ProgressManager.getInstance().runProcess(new Runnable() {
public void run() {
modifiedClasses.set(HotSwapManager.getModifiedClasses(sessions, swapProgress));
swapProgress.finished();
}
}, swapProgress.getProgressIndicator());
return modifiedClasses.get();
}
public void reloadChangedClasses(final DebuggerSession session, boolean compileBeforeHotswap) {
dontAskHotswapAfterThisCompilation();
if (compileBeforeHotswap) {
@@ -233,7 +249,7 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent{
if(session.isAttached()) {
final List<DebuggerSession> sessions = new ArrayList<DebuggerSession>(1);
sessions.add(session);
hotSwapSessions(sessions);
hotSwapSessions(sessions, null);
}
}
}
@@ -104,16 +104,25 @@ message Message {
BUILD_STARTED = 1;
BUILD_COMPLETED = 2;
COMMAND_COMPLETED = 3;
FILES_GENERATED = 4;
}
enum Status {
CANCELED = 1;
ERRORS = 2;
SUCCESS = 3;
UP_TO_DATE = 4;
}
message GeneratedFile {
required string output_root = 1;
required string relative_path = 2;
}
required Type event_type = 1;
optional string description = 2;
optional Status completion_status = 3;
repeated GeneratedFile generated_files = 4;
}
message CompileMessage {
@@ -4330,6 +4330,7 @@ public final class JpsRemoteProto {
BUILD_STARTED(0, 1),
BUILD_COMPLETED(1, 2),
COMMAND_COMPLETED(2, 3),
FILES_GENERATED(3, 4),
;
@@ -4340,6 +4341,7 @@ public final class JpsRemoteProto {
case 1: return BUILD_STARTED;
case 2: return BUILD_COMPLETED;
case 3: return COMMAND_COMPLETED;
case 4: return FILES_GENERATED;
default: return null;
}
}
@@ -4409,6 +4411,305 @@ public final class JpsRemoteProto {
// @@protoc_insertion_point(enum_scope:org.jetbrains.jpsservice.Message.Response.BuildEvent.Status)
}
public static final class GeneratedFile extends
com.google.protobuf.GeneratedMessageLite {
// Use GeneratedFile.newBuilder() to construct.
private GeneratedFile() {
initFields();
}
private GeneratedFile(boolean noInit) {}
private static final GeneratedFile defaultInstance;
public static GeneratedFile getDefaultInstance() {
return defaultInstance;
}
public GeneratedFile getDefaultInstanceForType() {
return defaultInstance;
}
// required string output_root = 1;
public static final int OUTPUT_ROOT_FIELD_NUMBER = 1;
private boolean hasOutputRoot;
private java.lang.String outputRoot_ = "";
public boolean hasOutputRoot() { return hasOutputRoot; }
public java.lang.String getOutputRoot() { return outputRoot_; }
// required string relative_path = 2;
public static final int RELATIVE_PATH_FIELD_NUMBER = 2;
private boolean hasRelativePath;
private java.lang.String relativePath_ = "";
public boolean hasRelativePath() { return hasRelativePath; }
public java.lang.String getRelativePath() { return relativePath_; }
private void initFields() {
}
public final boolean isInitialized() {
if (!hasOutputRoot) return false;
if (!hasRelativePath) return false;
return true;
}
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
getSerializedSize();
if (hasOutputRoot()) {
output.writeString(1, getOutputRoot());
}
if (hasRelativePath()) {
output.writeString(2, getRelativePath());
}
}
private int memoizedSerializedSize = -1;
public int getSerializedSize() {
int size = memoizedSerializedSize;
if (size != -1) return size;
size = 0;
if (hasOutputRoot()) {
size += com.google.protobuf.CodedOutputStream
.computeStringSize(1, getOutputRoot());
}
if (hasRelativePath()) {
size += com.google.protobuf.CodedOutputStream
.computeStringSize(2, getRelativePath());
}
memoizedSerializedSize = size;
return size;
}
public static org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).buildParsed();
}
public static org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data, extensionRegistry)
.buildParsed();
}
public static org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).buildParsed();
}
public static org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data, extensionRegistry)
.buildParsed();
}
public static org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile parseFrom(java.io.InputStream input)
throws java.io.IOException {
return newBuilder().mergeFrom(input).buildParsed();
}
public static org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return newBuilder().mergeFrom(input, extensionRegistry)
.buildParsed();
}
public static org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
Builder builder = newBuilder();
if (builder.mergeDelimitedFrom(input)) {
return builder.buildParsed();
} else {
return null;
}
}
public static org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
Builder builder = newBuilder();
if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
return builder.buildParsed();
} else {
return null;
}
}
public static org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return newBuilder().mergeFrom(input).buildParsed();
}
public static org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return newBuilder().mergeFrom(input, extensionRegistry)
.buildParsed();
}
public static Builder newBuilder() { return Builder.create(); }
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder(org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile prototype) {
return newBuilder().mergeFrom(prototype);
}
public Builder toBuilder() { return newBuilder(this); }
public static final class Builder extends
com.google.protobuf.GeneratedMessageLite.Builder<
org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile, Builder> {
private org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile result;
// Construct using org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile.newBuilder()
private Builder() {}
private static Builder create() {
Builder builder = new Builder();
builder.result = new org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile();
return builder;
}
protected org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile internalGetResult() {
return result;
}
public Builder clear() {
if (result == null) {
throw new IllegalStateException(
"Cannot call clear() after build().");
}
result = new org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile();
return this;
}
public Builder clone() {
return create().mergeFrom(result);
}
public org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile getDefaultInstanceForType() {
return org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile.getDefaultInstance();
}
public boolean isInitialized() {
return result.isInitialized();
}
public org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile build() {
if (result != null && !isInitialized()) {
throw newUninitializedMessageException(result);
}
return buildPartial();
}
private org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile buildParsed()
throws com.google.protobuf.InvalidProtocolBufferException {
if (!isInitialized()) {
throw newUninitializedMessageException(
result).asInvalidProtocolBufferException();
}
return buildPartial();
}
public org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile buildPartial() {
if (result == null) {
throw new IllegalStateException(
"build() has already been called on this Builder.");
}
org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile returnMe = result;
result = null;
return returnMe;
}
public Builder mergeFrom(org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile other) {
if (other == org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile.getDefaultInstance()) return this;
if (other.hasOutputRoot()) {
setOutputRoot(other.getOutputRoot());
}
if (other.hasRelativePath()) {
setRelativePath(other.getRelativePath());
}
return this;
}
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
while (true) {
int tag = input.readTag();
switch (tag) {
case 0:
return this;
default: {
if (!parseUnknownField(input, extensionRegistry, tag)) {
return this;
}
break;
}
case 10: {
setOutputRoot(input.readString());
break;
}
case 18: {
setRelativePath(input.readString());
break;
}
}
}
}
// required string output_root = 1;
public boolean hasOutputRoot() {
return result.hasOutputRoot();
}
public java.lang.String getOutputRoot() {
return result.getOutputRoot();
}
public Builder setOutputRoot(java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
result.hasOutputRoot = true;
result.outputRoot_ = value;
return this;
}
public Builder clearOutputRoot() {
result.hasOutputRoot = false;
result.outputRoot_ = getDefaultInstance().getOutputRoot();
return this;
}
// required string relative_path = 2;
public boolean hasRelativePath() {
return result.hasRelativePath();
}
public java.lang.String getRelativePath() {
return result.getRelativePath();
}
public Builder setRelativePath(java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
result.hasRelativePath = true;
result.relativePath_ = value;
return this;
}
public Builder clearRelativePath() {
result.hasRelativePath = false;
result.relativePath_ = getDefaultInstance().getRelativePath();
return this;
}
// @@protoc_insertion_point(builder_scope:org.jetbrains.jpsservice.Message.Response.BuildEvent.GeneratedFile)
}
static {
defaultInstance = new GeneratedFile(true);
org.jetbrains.jps.api.JpsRemoteProto.internalForceInit();
defaultInstance.initFields();
}
// @@protoc_insertion_point(class_scope:org.jetbrains.jpsservice.Message.Response.BuildEvent.GeneratedFile)
}
// required .org.jetbrains.jpsservice.Message.Response.BuildEvent.Type event_type = 1;
public static final int EVENT_TYPE_FIELD_NUMBER = 1;
private boolean hasEventType;
@@ -4430,12 +4731,27 @@ public final class JpsRemoteProto {
public boolean hasCompletionStatus() { return hasCompletionStatus; }
public org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.Status getCompletionStatus() { return completionStatus_; }
// repeated .org.jetbrains.jpsservice.Message.Response.BuildEvent.GeneratedFile generated_files = 4;
public static final int GENERATED_FILES_FIELD_NUMBER = 4;
private java.util.List<org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile> generatedFiles_ =
java.util.Collections.emptyList();
public java.util.List<org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile> getGeneratedFilesList() {
return generatedFiles_;
}
public int getGeneratedFilesCount() { return generatedFiles_.size(); }
public org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile getGeneratedFiles(int index) {
return generatedFiles_.get(index);
}
private void initFields() {
eventType_ = org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.Type.BUILD_STARTED;
completionStatus_ = org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.Status.CANCELED;
}
public final boolean isInitialized() {
if (!hasEventType) return false;
for (org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile element : getGeneratedFilesList()) {
if (!element.isInitialized()) return false;
}
return true;
}
@@ -4451,6 +4767,9 @@ public final class JpsRemoteProto {
if (hasCompletionStatus()) {
output.writeEnum(3, getCompletionStatus().getNumber());
}
for (org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile element : getGeneratedFilesList()) {
output.writeMessage(4, element);
}
}
private int memoizedSerializedSize = -1;
@@ -4471,6 +4790,10 @@ public final class JpsRemoteProto {
size += com.google.protobuf.CodedOutputStream
.computeEnumSize(3, getCompletionStatus().getNumber());
}
for (org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile element : getGeneratedFilesList()) {
size += com.google.protobuf.CodedOutputStream
.computeMessageSize(4, element);
}
memoizedSerializedSize = size;
return size;
}
@@ -4608,6 +4931,10 @@ public final class JpsRemoteProto {
throw new IllegalStateException(
"build() has already been called on this Builder.");
}
if (result.generatedFiles_ != java.util.Collections.EMPTY_LIST) {
result.generatedFiles_ =
java.util.Collections.unmodifiableList(result.generatedFiles_);
}
org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent returnMe = result;
result = null;
return returnMe;
@@ -4624,6 +4951,12 @@ public final class JpsRemoteProto {
if (other.hasCompletionStatus()) {
setCompletionStatus(other.getCompletionStatus());
}
if (!other.generatedFiles_.isEmpty()) {
if (result.generatedFiles_.isEmpty()) {
result.generatedFiles_ = new java.util.ArrayList<org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile>();
}
result.generatedFiles_.addAll(other.generatedFiles_);
}
return this;
}
@@ -4662,6 +4995,12 @@ public final class JpsRemoteProto {
}
break;
}
case 34: {
org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile.Builder subBuilder = org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile.newBuilder();
input.readMessage(subBuilder, extensionRegistry);
addGeneratedFiles(subBuilder.buildPartial());
break;
}
}
}
}
@@ -4730,6 +5069,57 @@ public final class JpsRemoteProto {
return this;
}
// repeated .org.jetbrains.jpsservice.Message.Response.BuildEvent.GeneratedFile generated_files = 4;
public java.util.List<org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile> getGeneratedFilesList() {
return java.util.Collections.unmodifiableList(result.generatedFiles_);
}
public int getGeneratedFilesCount() {
return result.getGeneratedFilesCount();
}
public org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile getGeneratedFiles(int index) {
return result.getGeneratedFiles(index);
}
public Builder setGeneratedFiles(int index, org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile value) {
if (value == null) {
throw new NullPointerException();
}
result.generatedFiles_.set(index, value);
return this;
}
public Builder setGeneratedFiles(int index, org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile.Builder builderForValue) {
result.generatedFiles_.set(index, builderForValue.build());
return this;
}
public Builder addGeneratedFiles(org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile value) {
if (value == null) {
throw new NullPointerException();
}
if (result.generatedFiles_.isEmpty()) {
result.generatedFiles_ = new java.util.ArrayList<org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile>();
}
result.generatedFiles_.add(value);
return this;
}
public Builder addGeneratedFiles(org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile.Builder builderForValue) {
if (result.generatedFiles_.isEmpty()) {
result.generatedFiles_ = new java.util.ArrayList<org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile>();
}
result.generatedFiles_.add(builderForValue.build());
return this;
}
public Builder addAllGeneratedFiles(
java.lang.Iterable<? extends org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile> values) {
if (result.generatedFiles_.isEmpty()) {
result.generatedFiles_ = new java.util.ArrayList<org.jetbrains.jps.api.JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile>();
}
super.addAll(values, result.generatedFiles_);
return this;
}
public Builder clearGeneratedFiles() {
result.generatedFiles_ = java.util.Collections.emptyList();
return this;
}
// @@protoc_insertion_point(builder_scope:org.jetbrains.jpsservice.Message.Response.BuildEvent)
}
@@ -1,5 +1,6 @@
package org.jetbrains.jps.api;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.incremental.messages.BuildMessage;
@@ -116,18 +117,22 @@ public class ProtoUtil {
}
public static JpsRemoteProto.Message.Response createBuildStartedEvent(@Nullable String description) {
return createBuildEvent(JpsRemoteProto.Message.Response.BuildEvent.Type.BUILD_STARTED, description, null);
return createBuildEvent(JpsRemoteProto.Message.Response.BuildEvent.Type.BUILD_STARTED, description, null, null);
}
public static JpsRemoteProto.Message.Response createBuildCompletedEvent(@Nullable String description, final JpsRemoteProto.Message.Response.BuildEvent.Status status) {
return createBuildEvent(JpsRemoteProto.Message.Response.BuildEvent.Type.BUILD_COMPLETED, description, status);
return createBuildEvent(JpsRemoteProto.Message.Response.BuildEvent.Type.BUILD_COMPLETED, description, status, null);
}
public static JpsRemoteProto.Message.Response createCommandCompletedEvent(@Nullable String description) {
return createBuildEvent(JpsRemoteProto.Message.Response.BuildEvent.Type.COMMAND_COMPLETED, description, null);
return createBuildEvent(JpsRemoteProto.Message.Response.BuildEvent.Type.COMMAND_COMPLETED, description, null, null);
}
public static JpsRemoteProto.Message.Response createBuildEvent(final JpsRemoteProto.Message.Response.BuildEvent.Type type, @Nullable String description, final JpsRemoteProto.Message.Response.BuildEvent.Status status) {
public static JpsRemoteProto.Message.Response createFileGeneratedEvent(final Collection<Pair<String, String>> paths) {
return createBuildEvent(JpsRemoteProto.Message.Response.BuildEvent.Type.FILES_GENERATED, null, null, paths);
}
public static JpsRemoteProto.Message.Response createBuildEvent(final JpsRemoteProto.Message.Response.BuildEvent.Type type, @Nullable String description, final JpsRemoteProto.Message.Response.BuildEvent.Status status, Collection<Pair<String, String>> generatedPaths) {
final JpsRemoteProto.Message.Response.BuildEvent.Builder builder = JpsRemoteProto.Message.Response.BuildEvent.newBuilder().setEventType(type);
if (description != null) {
builder.setDescription(description);
@@ -135,6 +140,13 @@ public class ProtoUtil {
if (status != null) {
builder.setCompletionStatus(status);
}
if (generatedPaths != null) {
for (Pair<String, String> pair : generatedPaths) {
final JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile.Builder fileBuilder = JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile.newBuilder();
final JpsRemoteProto.Message.Response.BuildEvent.GeneratedFile generatedFile = fileBuilder.setOutputRoot(pair.first).setRelativePath(pair.second).build();
builder.addGeneratedFiles(generatedFile);
}
}
return JpsRemoteProto.Message.Response.newBuilder().setResponseType(JpsRemoteProto.Message.Response.Type.BUILD_EVENT).setBuildEvent(builder.build()).build();
}
@@ -14,6 +14,7 @@ import org.jetbrains.jps.incremental.*;
import org.jetbrains.jps.incremental.java.JavaBuilder;
import org.jetbrains.jps.incremental.messages.BuildMessage;
import org.jetbrains.jps.incremental.messages.CompilerMessage;
import org.jetbrains.jps.incremental.messages.FileGeneratedEvent;
import org.jetbrains.jps.incremental.messages.ProgressMessage;
import org.jetbrains.jps.incremental.storage.SourceToOutputMapping;
import org.jetbrains.jps.server.ClasspathBootstrap;
@@ -147,7 +148,9 @@ public class GroovyBuilder extends Builder {
final Mappings delta = context.createDelta();
final List<File> successfullyCompiledFiles = new ArrayList<File>();
if (!successfullyCompiled.isEmpty()) {
final Callbacks.Backend callback = delta.getCallback();
final FileGeneratedEvent generatedEvent = new FileGeneratedEvent();
for (GroovycOSProcessHandler.OutputItem item : successfullyCompiled) {
final String sourcePath = FileUtil.toSystemIndependentName(item.sourcePath);
@@ -159,9 +162,14 @@ public class GroovyBuilder extends Builder {
}
callback.associate(outputPath, Callbacks.getDefaultLookup(sourcePath), new ClassReader(FileUtil.loadFileBytes(new File(outputPath))));
successfullyCompiledFiles.add(new File(sourcePath));
generatedEvent.add(moduleOutputPath, FileUtil.getRelativePath(moduleOutputPath, outputPath, '/'));
}
context.processMessage(generatedEvent);
}
final boolean needSecondPass = updateMappings(context, delta, chunk, toCompile.keySet(), successfullyCompiledFiles);
if (needSecondPass) {
exitCode = ExitCode.ADDITIONAL_PASS_REQUIRED;
@@ -19,6 +19,7 @@ import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.incremental.*;
import org.jetbrains.jps.incremental.messages.BuildMessage;
import org.jetbrains.jps.incremental.messages.CompilerMessage;
import org.jetbrains.jps.incremental.messages.FileGeneratedEvent;
import org.jetbrains.jps.incremental.messages.ProgressMessage;
import org.jetbrains.jps.incremental.storage.BuildDataManager;
import org.jetbrains.jps.incremental.storage.SourceToFormMapping;
@@ -611,12 +612,24 @@ public class JavaBuilder extends Builder{
public void writePendingData() {
try {
for (OutputFileObject file : myFileObjects) {
if (!myFileObjects.isEmpty()) {
final FileGeneratedEvent event = new FileGeneratedEvent();
try {
writeToDisk(file);
for (OutputFileObject fileObject : myFileObjects) {
try {
writeToDisk(fileObject);
final File rootFile = fileObject.getOutputRoot();
if (rootFile != null) {
event.add(rootFile.getPath(), fileObject.getRelativePath());
}
}
catch (IOException e) {
myContext.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, e.getMessage()));
}
}
}
catch (IOException e) {
myContext.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, e.getMessage()));
finally {
myContext.processMessage(event);
}
}
}
@@ -110,7 +110,7 @@ class JavacFileManager extends ForwardingJavaFileManager<StandardJavaFileManager
}
}
final File file = (dir == null? new File(fileName).getAbsoluteFile() : new File(dir, fileName));
return new OutputFileObject(myContext, file, kind, className, src);
return new OutputFileObject(myContext, dir, fileName, file, kind, className, src);
}
private File getSingleOutputDirectory(final Location loc, final JavaFileObject sourceFile) {
@@ -3,7 +3,8 @@ package org.jetbrains.jps.incremental.java;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.incremental.Paths;
import javax.tools.*;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import java.io.*;
import java.util.Arrays;
@@ -14,21 +15,35 @@ import java.util.Arrays;
class OutputFileObject extends SimpleJavaFileObject {
private final JavacFileManager.Context myContext;
@Nullable
private final File myOutputRoot;
private final String myRelativePath;
private final File myFile;
@Nullable
private final String myClassName;
private volatile Content myContent;
private final File mySourceFile;
public OutputFileObject(JavacFileManager.Context context, File file, Kind kind, @Nullable String className, JavaFileObject source) {
public OutputFileObject(JavacFileManager.Context context, @Nullable File outputRoot, String relativePath, File file, Kind kind, @Nullable String className, JavaFileObject source) {
super(Paths.toURI(file.getPath()), kind);
myContext = context;
myOutputRoot = outputRoot;
myRelativePath = relativePath;
myFile = file;
myClassName = className;
mySourceFile = source != null? new File(Paths.toURI(source.toUri().getPath())) : null;
}
@Nullable
public File getOutputRoot() {
return myOutputRoot;
}
public String getRelativePath() {
return myRelativePath;
}
public File getFile() {
return myFile;
}
@@ -0,0 +1,27 @@
package org.jetbrains.jps.incremental.messages;
import com.intellij.openapi.util.Pair;
import java.util.ArrayList;
import java.util.Collection;
/**
* @author Eugene Zhuravlev
* Date: 9/29/11
*/
public class FileGeneratedEvent extends BuildMessage {
private Collection<Pair<String, String>> myPaths = new ArrayList<Pair<String, String>>();
public FileGeneratedEvent() {
super("", Kind.INFO);
}
public void add(String root, String relativePath) {
myPaths.add(new Pair<String, String>(root, relativePath));
}
public Collection<Pair<String, String>> getPaths() {
return myPaths;
}
}
@@ -1,15 +1,13 @@
package org.jetbrains.jps.server;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import org.jboss.netty.channel.*;
import org.jetbrains.annotations.Nullable;
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 org.jetbrains.jps.incremental.messages.UptoDateFilesSavedEvent;
import org.jetbrains.jps.incremental.messages.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -203,7 +201,11 @@ class ServerMessageHandler extends SimpleChannelHandler {
ServerState.getInstance().startBuild(myProjectPath, myModules, myPaths, myParams, new MessageHandler() {
public void processMessage(BuildMessage buildMessage) {
final JpsRemoteProto.Message.Response response;
if (buildMessage instanceof UptoDateFilesSavedEvent) {
if (buildMessage instanceof FileGeneratedEvent) {
final Collection<Pair<String, String>> paths = ((FileGeneratedEvent)buildMessage).getPaths();
response = !paths.isEmpty()? ProtoUtil.createFileGeneratedEvent(paths) : null;
}
else if (buildMessage instanceof UptoDateFilesSavedEvent) {
markedFilesUptodate.set(true);
response = null;
}
@@ -109,7 +109,7 @@ public class AndroidPrecompileTask implements CompileTask {
CompilerManager.getInstance(project).addCompilationStatusListener(new MyCompilationStatusListener(project, addedEntries), project);
}
CompilerManager.getInstance(project).addCompilationStatusListener(new CompilationStatusListener() {
CompilerManager.getInstance(project).addCompilationStatusListener(new CompilationStatusAdapter() {
@Override
public void compilationFinished(boolean aborted, int errors, int warnings, final CompileContext compileContext) {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@@ -199,7 +199,7 @@ public class AndroidPrecompileTask implements CompileTask {
}
}
private static class MyCompilationStatusListener implements CompilationStatusListener {
private static class MyCompilationStatusListener extends CompilationStatusAdapter {
private final Project myProject;
private final Set<ExcludeEntryDescription> myEntriesToRemove;