fsState management inside IDEA, initial

This commit is contained in:
Eugene Zhuravlev
2012-04-26 16:45:53 +02:00
parent 2004512c1a
commit 03e9157b77
29 changed files with 1861 additions and 1069 deletions
@@ -29,7 +29,7 @@ import com.intellij.compiler.make.ChangedConstantsDependencyProcessor;
import com.intellij.compiler.make.DependencyCache;
import com.intellij.compiler.progress.CompilerTask;
import com.intellij.compiler.server.BuildManager;
import com.intellij.compiler.server.BuildMessageHandler;
import com.intellij.compiler.server.DefaultMessageHandler;
import com.intellij.diagnostic.IdeErrorsDialog;
import com.intellij.diagnostic.PluginException;
import com.intellij.openapi.application.ApplicationManager;
@@ -549,7 +549,7 @@ public class CompileDriver {
else {
final BuildManager buildManager = BuildManager.getInstance();
buildManager.cancelAutoMakeTasks(myProject);
return buildManager.scheduleBuild(myProject, compileContext.isRebuild(), compileContext.isMake(), moduleNames, artifactNames, paths, builderParams, new BuildMessageHandler() {
return buildManager.scheduleBuild(myProject, compileContext.isRebuild(), compileContext.isMake(), moduleNames, artifactNames, paths, builderParams, new DefaultMessageHandler() {
@Override
public void sessionTerminated() {
final ExitStatus status = COMPILE_SERVER_BUILD_STATUS.get(compileContext);
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.daemon.impl.actions.SuppressFix;
import com.intellij.codeInsight.daemon.impl.actions.SuppressForClassFix;
import com.intellij.compiler.*;
import com.intellij.compiler.options.CompilerConfigurable;
import com.intellij.compiler.server.BuildManager;
import com.intellij.ide.errorTreeView.*;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.openapi.actionSystem.*;
@@ -110,6 +111,7 @@ public class CompilerErrorTreeView extends NewErrorTreeViewPanel {
if (!project.isDisposed()) {
project.save();
CompileServerManager.getInstance().sendReloadRequest(project);
BuildManager.getInstance().clearState(project);
}
}
});
@@ -21,6 +21,7 @@ import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerIOUtil;
import com.intellij.compiler.CompilerWorkspaceConfiguration;
import com.intellij.compiler.make.MakeUtil;
import com.intellij.compiler.server.BuildManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
@@ -1426,7 +1427,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
toMark = Collections.singleton(root);
}
if (!toMark.isEmpty()) {
CompileServerManager.getInstance().notifyFilesDeleted(toMark);
notifyFilesDeleted(toMark);
}
}
markDirtyIfSource(eventFile, false);
@@ -1544,7 +1545,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
});
if (!pathsToMark.isEmpty()) {
CompileServerManager.getInstance().notifyFilesDeleted(pathsToMark);
notifyFilesDeleted(pathsToMark);
}
}
@@ -1583,10 +1584,10 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
}
});
if (fromMove) {
CompileServerManager.getInstance().notifyFilesDeleted(pathsToMark);
notifyFilesDeleted(pathsToMark);
}
else {
CompileServerManager.getInstance().notifyFilesChanged(pathsToMark);
notifyFilesChanged(pathsToMark);
}
}
@@ -1637,11 +1638,21 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
}
});
if (notifyServer) {
CompileServerManager.getInstance().notifyFilesChanged(pathsToMark);
notifyFilesChanged(pathsToMark);
}
}
}
private static void notifyFilesChanged(Collection<String> paths) {
CompileServerManager.getInstance().notifyFilesChanged(paths);
BuildManager.getInstance().notifyFilesChanged(paths);
}
private static void notifyFilesDeleted(Collection<String> paths) {
CompileServerManager.getInstance().notifyFilesDeleted(paths);
BuildManager.getInstance().notifyFilesDeleted(paths);
}
private boolean belongsToIntermediateSources(VirtualFile file, Project project) {
return FileUtil.isAncestor(myGeneratedDataPaths.get(project), new File(file.getPath()), true);
}
@@ -17,6 +17,7 @@ package com.intellij.compiler.options;
import com.intellij.compiler.CompileServerManager;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.server.BuildManager;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
@@ -253,6 +254,7 @@ public class AnnotationProcessorsConfigurable implements SearchableConfigurable,
SwingUtilities.invokeLater(new Runnable() {
public void run() {
CompileServerManager.getInstance().sendReloadRequest(myProject);
BuildManager.getInstance().clearState(myProject);
}
});
}
@@ -20,6 +20,7 @@ import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerConfigurationImpl;
import com.intellij.compiler.CompilerSettingsFactory;
import com.intellij.compiler.impl.rmiCompiler.RmicConfiguration;
import com.intellij.compiler.server.BuildManager;
import com.intellij.openapi.compiler.CompilerBundle;
import com.intellij.openapi.compiler.options.ExcludedEntriesConfigurable;
import com.intellij.openapi.diagnostic.Logger;
@@ -181,6 +182,7 @@ public class CompilerConfigurable implements SearchableConfigurable.Parent, Conf
SwingUtilities.invokeLater(new Runnable() {
public void run() {
CompileServerManager.getInstance().sendReloadRequest(project);
BuildManager.getInstance().clearState(project);
}
});
}
@@ -17,6 +17,7 @@ package com.intellij.compiler.options;
import com.intellij.compiler.*;
import com.intellij.compiler.impl.TranslatingCompilerFilesMonitor;
import com.intellij.compiler.server.BuildManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompilerBundle;
import com.intellij.openapi.options.Configurable;
@@ -124,6 +125,7 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura
SwingUtilities.invokeLater(new Runnable() {
public void run() {
CompileServerManager.getInstance().sendReloadRequest(myProject);
BuildManager.getInstance().clearState(myProject);
}
});
}
@@ -19,6 +19,7 @@ import com.intellij.compiler.CompileServerManager;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerConfigurationImpl;
import com.intellij.compiler.impl.javaCompiler.BackendCompiler;
import com.intellij.compiler.server.BuildManager;
import com.intellij.ide.ui.ListCellRendererWrapper;
import com.intellij.openapi.compiler.CompilerBundle;
import com.intellij.openapi.options.Configurable;
@@ -128,6 +129,7 @@ public class JavaCompilersTab implements SearchableConfigurable, Configurable.No
SwingUtilities.invokeLater(new Runnable() {
public void run() {
CompileServerManager.getInstance().sendReloadRequest(myProject);
BuildManager.getInstance().clearState(myProject);
}
});
}
@@ -0,0 +1,132 @@
/*
* 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.compiler.server;
import com.intellij.notification.Notification;
import com.intellij.openapi.compiler.CompilationStatusListener;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.compiler.CompilerTopics;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.problems.Problem;
import com.intellij.problems.WolfTheProblemSolver;
import org.jetbrains.jps.api.CmdlineRemoteProto;
import java.util.Collections;
/**
* @author Eugene Zhuravlev
* Date: 4/25/12
*/
class AutoMakeMessageHandler extends DefaultMessageHandler {
private CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status myBuildStatus;
private final Project myProject;
private final WolfTheProblemSolver myWolf;
public AutoMakeMessageHandler(Project project) {
myProject = project;
myBuildStatus = CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.SUCCESS;
myWolf = WolfTheProblemSolver.getInstance(project);
}
@Override
protected void handleBuildEvent(CmdlineRemoteProto.Message.BuilderMessage.BuildEvent event) {
if (myProject.isDisposed()) {
return;
}
switch (event.getEventType()) {
case BUILD_COMPLETED:
if (event.hasCompletionStatus()) {
myBuildStatus = event.getCompletionStatus();
}
return;
case FILES_GENERATED:
final CompilationStatusListener publisher = myProject.getMessageBus().syncPublisher(CompilerTopics.COMPILATION_STATUS);
for (CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.GeneratedFile generatedFile : event.getGeneratedFilesList()) {
final String root = FileUtil.toSystemIndependentName(generatedFile.getOutputRoot());
final String relativePath = FileUtil.toSystemIndependentName(generatedFile.getRelativePath());
publisher.fileGenerated(root, relativePath);
}
return;
default:
return;
}
}
@Override
protected void handleCompileMessage(CmdlineRemoteProto.Message.BuilderMessage.CompileMessage message) {
if (myProject.isDisposed()) {
return;
}
final CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind kind = message.getKind();
if (kind == CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind.ERROR) {
informWolf(myProject, message);
}
}
@Override
public void handleFailure(CmdlineRemoteProto.Message.Failure failure) {
CompilerManager.NOTIFICATION_GROUP.createNotification("Auto make failure: " + failure.getDescription(), MessageType.INFO);
}
@Override
public void sessionTerminated() {
String statusMessage = null/*"Auto make completed"*/;
switch (myBuildStatus) {
case SUCCESS:
//statusMessage = "Auto make completed successfully";
break;
case UP_TO_DATE:
//statusMessage = "All files are up-to-date";
break;
case ERRORS:
statusMessage = "Auto make completed with errors";
break;
case CANCELED:
//statusMessage = "Auto make has been canceled";
break;
}
if (statusMessage != null) {
final Notification notification = CompilerManager.NOTIFICATION_GROUP.createNotification(statusMessage, MessageType.INFO);
if (!myProject.isDisposed()) {
notification.notify(myProject);
}
}
}
private void informWolf(Project project, CmdlineRemoteProto.Message.BuilderMessage.CompileMessage message) {
final String srcPath = message.getSourceFilePath();
if (srcPath != null && !project.isDisposed()) {
final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(srcPath);
if (vFile != null) {
final int line = (int)message.getLine();
final int column = (int)message.getColumn();
if (line > 0 && column > 0) {
final Problem problem = myWolf.convertToProblem(vFile, line, column, new String[]{message.getText()});
myWolf.weHaveGotProblems(vFile, Collections.singletonList(problem));
}
else {
myWolf.queue(vFile);
}
}
}
}
}
@@ -25,29 +25,24 @@ import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.notification.Notification;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathMacros;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.compiler.CompilationStatusListener;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.compiler.CompilerTopics;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerAdapter;
import com.intellij.openapi.projectRoots.*;
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.roots.ModuleRootListener;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.ShutDownTracker;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
@@ -56,10 +51,7 @@ import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.encoding.EncodingManager;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.problems.Problem;
import com.intellij.problems.WolfTheProblemSolver;
import com.intellij.util.Alarm;
import com.intellij.util.containers.ConcurrentHashSet;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.net.NetUtils;
import org.jboss.netty.bootstrap.ServerBootstrap;
@@ -77,6 +69,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.api.*;
import org.jetbrains.jps.cmdline.BuildMain;
import org.jetbrains.jps.incremental.fs.FSState;
import org.jetbrains.jps.incremental.fs.RootDescriptor;
import org.jetbrains.jps.server.ClasspathBootstrap;
import org.jetbrains.jps.server.Server;
@@ -87,7 +81,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -101,9 +94,11 @@ public class BuildManager implements ApplicationComponent{
private static final String SYSTEM_ROOT = "compile-server";
private static final String LOGGER_CONFIG = "log.xml";
private static final String DEFAULT_LOGGER_CONFIG = "defaultLogConfig.xml";
private static final int MAKE_TRIGGER_DELAY = 5 * 1000 /*5 seconds*/;
private final File mySystemDirectory;
private final ProjectManager myProjectManager;
private static final int MAKE_TRIGGER_DELAY = 5 * 1000 /*5 seconds*/;
private final Map<RequestFuture, Project> myAutomakeFutures = new HashMap<RequestFuture, Project>();
private final CompileServerClasspathManager myClasspathManager = new CompileServerClasspathManager();
private final Executor myPooledThreadExecutor = new Executor() {
@@ -112,9 +107,9 @@ public class BuildManager implements ApplicationComponent{
ApplicationManager.getApplication().executeOnPooledThread(command);
}
};
private final Map<String, SequentialTaskExecutor> myProjectToExecutorMap = Collections.synchronizedMap(new HashMap<String, SequentialTaskExecutor>());
private final Map<String, ProjectData> myProjectDataMap = Collections.synchronizedMap(new HashMap<String, ProjectData>());
private final ChannelGroup myAllOpenChannels = new DefaultChannelGroup("compile-manager");
private final ChannelGroup myAllOpenChannels = new DefaultChannelGroup("build-manager");
private final BuildMessageDispatcher myMessageDispatcher = new BuildMessageDispatcher();
private int myListenPort = -1;
private volatile CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings myGlobals;
@@ -202,12 +197,89 @@ public class BuildManager implements ApplicationComponent{
return ApplicationManager.getApplication().getComponent(BuildManager.class);
}
public void notifyFilesChanged(Collection<String> paths) {
// todo: update state
public void notifyFilesChanged(final Collection<String> paths) {
// todo: temporarily commented
//doNotify(paths, false);
}
public void notifyFilesDeleted(Collection<String> paths) {
// todo: update state
// todo: temporarily commented
//doNotify(paths, true);
}
private void doNotify(final Collection<String> paths, final boolean notifyDeletion) {
final Project[] openProjects = myProjectManager.getOpenProjects();
myPooledThreadExecutor.execute(new Runnable() {
@Override
public void run() {
List<Pair<ProjectFileIndex, ProjectData>> activeProjects = new ArrayList<Pair<ProjectFileIndex, ProjectData>>();
for (Project project : openProjects) {
if (project.isDisposed() || project.isDefault()) {
continue;
}
final String projectPath = getProjectPath(project);
final ProjectData data = myProjectDataMap.get(projectPath);
if (data != null) {
activeProjects.add(Pair.create(ProjectRootManager.getInstance(project).getFileIndex(), data));
}
}
final LocalFileSystem lfs = LocalFileSystem.getInstance();
for (final Pair<ProjectFileIndex, ProjectData> pair : activeProjects) {
final ProjectFileIndex fileIndex = pair.first;
final FSState fsState = pair.second.fsState;
pair.second.requestQueue.submit(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
for (String filePath : paths) {
// todo: estimate performance, probably add a way to obtain all data from file index in a single call
final VirtualFile vFile = lfs.findFileByPath(filePath);
if (vFile == null) {
continue;
}
final Module module = fileIndex.getModuleForFile(vFile);
if (module == null) {
continue;
}
final String moduleName = module.getName();
if (!fsState.isInitialized(moduleName)) { // todo: proper sync!
continue;
}
final VirtualFile srcRoot = fileIndex.getSourceRootForFile(vFile);
if (srcRoot == null) {
return;
}
final boolean inTestSources = fileIndex.isInTestSourceContent(vFile);
if (!inTestSources && !fileIndex.isInSourceContent(vFile)) {
continue;
}
try {
final File file = new File(vFile.getPath());
if (notifyDeletion) {
fsState.registerDeleted(moduleName, file, inTestSources, null);
}
else {
fsState.markDirty(file, new RootDescriptor(moduleName, new File(srcRoot.getPath()), inTestSources, false), null);
}
}
catch (IOException e) {
LOG.error(e);
}
}
}
});
}
});
}
}
});
}
public void clearState(Project project) {
final String projectPath = getProjectPath(project);
myProjectDataMap.remove(projectPath);
}
@Nullable
@@ -274,7 +346,6 @@ public class BuildManager implements ApplicationComponent{
}
}
// todo: avoid FS scan on every start
@Nullable
@@ -284,7 +355,7 @@ public class BuildManager implements ApplicationComponent{
final Collection<String> modules,
final Collection<String> artifacts,
final Collection<String> paths,
final Map<String, String> userData, final BuildMessageHandler handler) {
final Map<String, String> userData, DefaultMessageHandler handler) {
final String projectPath = getProjectPath(project);
final UUID sessionId = UUID.randomUUID();
@@ -294,13 +365,27 @@ public class BuildManager implements ApplicationComponent{
globals = buildGlobalSettings();
myGlobals = globals;
}
final SequentialTaskExecutor sequential;
final FSState fsState;
synchronized (myProjectDataMap) {
ProjectData data = myProjectDataMap.get(projectPath);
if (data == null) {
data = new ProjectData(new SequentialTaskExecutor(myPooledThreadExecutor), new FSState());
myProjectDataMap.put(projectPath, data);
}
sequential = data.requestQueue;
fsState = data.fsState;
handler = new FSStateMessageHandler(data.fsState, handler);
}
if (isRebuild) {
params = CmdlineProtoUtil.createRebuildRequest(projectPath, userData, globals);
params = CmdlineProtoUtil.createRebuildRequest(projectPath, userData, globals, fsState);
}
else {
params = isMake ?
CmdlineProtoUtil.createMakeRequest(projectPath, modules, artifacts, userData, globals) :
CmdlineProtoUtil.createForceCompileRequest(projectPath, modules, artifacts, paths, userData, globals);
CmdlineProtoUtil.createMakeRequest(projectPath, modules, artifacts, userData, globals, fsState) :
CmdlineProtoUtil.createForceCompileRequest(projectPath, modules, artifacts, paths, userData, globals, fsState);
}
myMessageDispatcher.registerBuildMessageHandler(sessionId, handler, params);
@@ -318,22 +403,13 @@ public class BuildManager implements ApplicationComponent{
}
}
final RequestFuture<BuildMessageHandler> future = new RequestFuture<BuildMessageHandler>(handler, sessionId, new RequestFuture.CancelAction<com.intellij.compiler.server.BuildMessageHandler>() {
final RequestFuture<BuilderMessageHandler> future = new RequestFuture<BuilderMessageHandler>(handler, sessionId, new RequestFuture.CancelAction<BuilderMessageHandler>() {
@Override
public void cancel(RequestFuture<BuildMessageHandler> future) throws Exception {
public void cancel(RequestFuture<BuilderMessageHandler> future) throws Exception {
myMessageDispatcher.cancelSession(future.getRequestID());
}
});
SequentialTaskExecutor sequential;
synchronized (myProjectToExecutorMap) {
sequential = myProjectToExecutorMap.get(projectPath);
if (sequential == null) {
sequential = new SequentialTaskExecutor(myPooledThreadExecutor);
myProjectToExecutorMap.put(projectPath, sequential);
}
}
sequential.submit(new Runnable() {
@Override
public void run() {
@@ -352,7 +428,7 @@ public class BuildManager implements ApplicationComponent{
processHandler.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(ProcessEvent event) {
final BuildMessageHandler handler = myMessageDispatcher.unregisterBuildMessageHandler(sessionId);
final BuilderMessageHandler handler = myMessageDispatcher.unregisterBuildMessageHandler(sessionId);
if (handler != null) {
handler.sessionTerminated();
}
@@ -372,8 +448,8 @@ public class BuildManager implements ApplicationComponent{
}
catch (ExecutionException e) {
myMessageDispatcher.unregisterBuildMessageHandler(sessionId);
handler.handleFailure(CmdlineProtoUtil.createFailure(e.getMessage(), e));
handler.sessionTerminated();
future.getMessageHandler().handleFailure(CmdlineProtoUtil.createFailure(e.getMessage(), e));
future.getMessageHandler().sessionTerminated();
}
finally {
future.setDone();
@@ -684,103 +760,6 @@ public class BuildManager implements ApplicationComponent{
return builder.toString();
}
private static class AutoMakeMessageHandler extends BuildMessageHandler {
private CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status myBuildStatus;
private final Project myProject;
private final WolfTheProblemSolver myWolf;
public AutoMakeMessageHandler(Project project) {
myProject = project;
myBuildStatus = CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.SUCCESS;
myWolf = WolfTheProblemSolver.getInstance(project);
}
@Override
protected void handleBuildEvent(CmdlineRemoteProto.Message.BuilderMessage.BuildEvent event) {
if (myProject.isDisposed()) {
return;
}
switch (event.getEventType()) {
case BUILD_COMPLETED:
if (event.hasCompletionStatus()) {
myBuildStatus = event.getCompletionStatus();
}
return;
case FILES_GENERATED:
final CompilationStatusListener publisher = myProject.getMessageBus().syncPublisher(CompilerTopics.COMPILATION_STATUS);
for (CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.GeneratedFile generatedFile : event.getGeneratedFilesList()) {
final String root = FileUtil.toSystemIndependentName(generatedFile.getOutputRoot());
final String relativePath = FileUtil.toSystemIndependentName(generatedFile.getRelativePath());
publisher.fileGenerated(root, relativePath);
}
return;
default:
return;
}
}
@Override
protected void handleCompileMessage(CmdlineRemoteProto.Message.BuilderMessage.CompileMessage message) {
if (myProject.isDisposed()) {
return;
}
final CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind kind = message.getKind();
if (kind == CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind.ERROR) {
informWolf(myProject, message);
}
}
@Override
public void handleFailure(CmdlineRemoteProto.Message.Failure failure) {
CompilerManager.NOTIFICATION_GROUP.createNotification("Auto make failure: " + failure.getDescription(), MessageType.INFO);
}
@Override
public void sessionTerminated() {
String statusMessage = null/*"Auto make completed"*/;
switch (myBuildStatus) {
case SUCCESS:
//statusMessage = "Auto make completed successfully";
break;
case UP_TO_DATE:
//statusMessage = "All files are up-to-date";
break;
case ERRORS:
statusMessage = "Auto make completed with errors";
break;
case CANCELED:
//statusMessage = "Auto make has been canceled";
break;
}
if (statusMessage != null) {
final Notification notification = CompilerManager.NOTIFICATION_GROUP.createNotification(statusMessage, MessageType.INFO);
if (!myProject.isDisposed()) {
notification.notify(myProject);
}
}
}
private void informWolf(Project project, CmdlineRemoteProto.Message.BuilderMessage.CompileMessage message) {
final String srcPath = message.getSourceFilePath();
if (srcPath != null && !project.isDisposed()) {
final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(srcPath);
if (vFile != null) {
final int line = (int)message.getLine();
final int column = (int)message.getColumn();
if (line > 0 && column > 0) {
final Problem problem = myWolf.convertToProblem(vFile, line, column, new String[]{message.getText()});
myWolf.weHaveGotProblems(vFile, Collections.singletonList(problem));
}
else {
myWolf.queue(vFile);
}
}
}
}
}
private class ProjectWatcher extends ProjectManagerAdapter {
private final Map<Project, MessageBusConnection> myConnections = new HashMap<Project, MessageBusConnection>();
@@ -806,7 +785,7 @@ public class BuildManager implements ApplicationComponent{
@Override
public void projectClosed(Project project) {
myProjectToExecutorMap.remove(getProjectPath(project));
clearState(project);
final MessageBusConnection conn = myConnections.remove(project);
if (conn != null) {
conn.disconnect();
@@ -814,146 +793,13 @@ public class BuildManager implements ApplicationComponent{
}
}
private static class BuildMessageDispatcher extends SimpleChannelHandler {
private final Map<UUID, SessionData> myMessageHandlers = new ConcurrentHashMap<UUID, SessionData>();
private final Set<UUID> myCanceledSessions = new ConcurrentHashSet<UUID>();
private static class ProjectData {
final SequentialTaskExecutor requestQueue;
final FSState fsState;
public void registerBuildMessageHandler(UUID sessionId,
BuildMessageHandler handler,
CmdlineRemoteProto.Message.ControllerMessage params) {
myMessageHandlers.put(sessionId, new SessionData(sessionId, handler, params));
}
@Nullable
public BuildMessageHandler unregisterBuildMessageHandler(UUID sessionId) {
myCanceledSessions.remove(sessionId);
final SessionData data = myMessageHandlers.remove(sessionId);
return data != null? data.handler : null;
}
public void cancelSession(UUID sessionId) {
if (myCanceledSessions.add(sessionId)) {
final SessionData data = myMessageHandlers.get(sessionId);
if (data != null) {
final Channel channel = data.channel;
if (channel != null) {
Channels.write(channel, CmdlineProtoUtil.toMessage(sessionId, CmdlineProtoUtil.createCancelCommand()));
}
}
}
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
final CmdlineRemoteProto.Message message = (CmdlineRemoteProto.Message)e.getMessage();
SessionData sessionData = (SessionData)ctx.getAttachment();
UUID sessionId;
if (sessionData == null) {
// this is the first message for this session, so fill session data with missing info
final CmdlineRemoteProto.Message.UUID id = message.getSessionId();
sessionId = new UUID(id.getMostSigBits(), id.getLeastSigBits());
sessionData = myMessageHandlers.get(sessionId);
if (sessionData != null) {
sessionData.channel = ctx.getChannel();
ctx.setAttachment(sessionData);
}
if (myCanceledSessions.contains(sessionId)) {
Channels.write(ctx.getChannel(), CmdlineProtoUtil.toMessage(sessionId, CmdlineProtoUtil.createCancelCommand()));
}
}
else {
sessionId = sessionData.sessionId;
}
final BuildMessageHandler handler = sessionData != null? sessionData.handler : null;
if (handler == null) {
// todo
LOG.info("No message handler registered for session " + sessionId);
return;
}
final CmdlineRemoteProto.Message.Type messageType = message.getType();
switch (messageType) {
case FAILURE:
handler.handleFailure(message.getFailure());
break;
case BUILDER_MESSAGE:
final CmdlineRemoteProto.Message.BuilderMessage builderMessage = message.getBuilderMessage();
final CmdlineRemoteProto.Message.BuilderMessage.Type responseType = builderMessage.getType();
if (responseType == CmdlineRemoteProto.Message.BuilderMessage.Type.PARAM_REQUEST) {
final CmdlineRemoteProto.Message.ControllerMessage params = sessionData.params;
if (params != null) {
sessionData.params = null;
Channels.write(ctx.getChannel(), CmdlineProtoUtil.toMessage(sessionId, params));
}
else {
cancelSession(sessionId);
}
}
else {
handler.handleBuildMessage(builderMessage);
}
break;
default:
LOG.info("Unsupported message type " + messageType);
break;
}
}
@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
try {
super.channelClosed(ctx, e);
}
finally {
final SessionData sessionData = (SessionData)ctx.getAttachment();
if (sessionData != null) {
final BuildMessageHandler handler = unregisterBuildMessageHandler(sessionData.sessionId);
if (handler != null) {
// notify the handler only if it has not been notified yet
handler.sessionTerminated();
}
}
}
}
@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
try {
super.channelDisconnected(ctx, e);
}
finally {
final SessionData sessionData = (SessionData)ctx.getAttachment();
if (sessionData != null) { // this is the context corresponding to some session
final Channel channel = e.getChannel();
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
channel.close();
}
});
}
}
}
}
private static final class SessionData {
final UUID sessionId;
final BuildMessageHandler handler;
volatile CmdlineRemoteProto.Message.ControllerMessage params;
volatile Channel channel;
private SessionData(UUID sessionId, BuildMessageHandler handler, CmdlineRemoteProto.Message.ControllerMessage params) {
this.sessionId = sessionId;
this.handler = handler;
this.params = params;
private ProjectData(SequentialTaskExecutor requestQueue, FSState fsState) {
this.requestQueue = requestQueue;
this.fsState = fsState;
}
}
@@ -0,0 +1,176 @@
/*
* 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.compiler.server;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.containers.ConcurrentHashSet;
import org.jboss.netty.channel.*;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.api.CmdlineProtoUtil;
import org.jetbrains.jps.api.CmdlineRemoteProto;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Eugene Zhuravlev
* Date: 4/25/12
*/
class BuildMessageDispatcher extends SimpleChannelHandler {
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.server.BuildMessageDispatcher");
private final Map<UUID, SessionData> myMessageHandlers = new ConcurrentHashMap<UUID, SessionData>();
private final Set<UUID> myCanceledSessions = new ConcurrentHashSet<UUID>();
public void registerBuildMessageHandler(UUID sessionId,
BuilderMessageHandler handler,
CmdlineRemoteProto.Message.ControllerMessage params) {
myMessageHandlers.put(sessionId, new SessionData(sessionId, handler, params));
}
@Nullable
public BuilderMessageHandler unregisterBuildMessageHandler(UUID sessionId) {
myCanceledSessions.remove(sessionId);
final SessionData data = myMessageHandlers.remove(sessionId);
return data != null? data.handler : null;
}
public void cancelSession(UUID sessionId) {
if (myCanceledSessions.add(sessionId)) {
final SessionData data = myMessageHandlers.get(sessionId);
if (data != null) {
final Channel channel = data.channel;
if (channel != null) {
Channels.write(channel, CmdlineProtoUtil.toMessage(sessionId, CmdlineProtoUtil.createCancelCommand()));
}
}
}
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
final CmdlineRemoteProto.Message message = (CmdlineRemoteProto.Message)e.getMessage();
SessionData sessionData = (SessionData)ctx.getAttachment();
UUID sessionId;
if (sessionData == null) {
// this is the first message for this session, so fill session data with missing info
final CmdlineRemoteProto.Message.UUID id = message.getSessionId();
sessionId = new UUID(id.getMostSigBits(), id.getLeastSigBits());
sessionData = myMessageHandlers.get(sessionId);
if (sessionData != null) {
sessionData.channel = ctx.getChannel();
ctx.setAttachment(sessionData);
}
if (myCanceledSessions.contains(sessionId)) {
Channels.write(ctx.getChannel(), CmdlineProtoUtil.toMessage(sessionId, CmdlineProtoUtil.createCancelCommand()));
}
}
else {
sessionId = sessionData.sessionId;
}
final BuilderMessageHandler handler = sessionData != null? sessionData.handler : null;
if (handler == null) {
// todo
LOG.info("No message handler registered for session " + sessionId);
return;
}
final CmdlineRemoteProto.Message.Type messageType = message.getType();
switch (messageType) {
case FAILURE:
handler.handleFailure(message.getFailure());
break;
case BUILDER_MESSAGE:
final CmdlineRemoteProto.Message.BuilderMessage builderMessage = message.getBuilderMessage();
final CmdlineRemoteProto.Message.BuilderMessage.Type msgType = builderMessage.getType();
if (msgType == CmdlineRemoteProto.Message.BuilderMessage.Type.PARAM_REQUEST) {
final CmdlineRemoteProto.Message.ControllerMessage params = sessionData.params;
if (params != null) {
sessionData.params = null;
Channels.write(ctx.getChannel(), CmdlineProtoUtil.toMessage(sessionId, params));
}
else {
cancelSession(sessionId);
}
}
else {
handler.handleBuildMessage(builderMessage);
}
break;
default:
LOG.info("Unsupported message type " + messageType);
break;
}
}
@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
try {
super.channelClosed(ctx, e);
}
finally {
final SessionData sessionData = (SessionData)ctx.getAttachment();
if (sessionData != null) {
final BuilderMessageHandler handler = unregisterBuildMessageHandler(sessionData.sessionId);
if (handler != null) {
// notify the handler only if it has not been notified yet
handler.sessionTerminated();
}
}
}
}
@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
try {
super.channelDisconnected(ctx, e);
}
finally {
final SessionData sessionData = (SessionData)ctx.getAttachment();
if (sessionData != null) { // this is the context corresponding to some session
final Channel channel = e.getChannel();
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
channel.close();
}
});
}
}
}
private static final class SessionData {
final UUID sessionId;
final BuilderMessageHandler handler;
volatile CmdlineRemoteProto.Message.ControllerMessage params;
volatile Channel channel;
private SessionData(UUID sessionId, BuilderMessageHandler handler, CmdlineRemoteProto.Message.ControllerMessage params) {
this.sessionId = sessionId;
this.handler = handler;
this.params = params;
}
}
}
@@ -0,0 +1,30 @@
/*
* 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.compiler.server;
import org.jetbrains.jps.api.CmdlineRemoteProto;
/**
* @author Eugene Zhuravlev
* Date: 4/25/12
*/
public interface BuilderMessageHandler {
void handleBuildMessage(CmdlineRemoteProto.Message.BuilderMessage msg);
void handleFailure(CmdlineRemoteProto.Message.Failure failure);
void sessionTerminated();
}
@@ -21,12 +21,8 @@ import org.jetbrains.jps.api.CmdlineRemoteProto;
* @author Eugene Zhuravlev
* Date: 4/18/12
*/
public abstract class BuildMessageHandler {
public abstract void sessionTerminated();
public abstract void handleFailure(CmdlineRemoteProto.Message.Failure failure);
public abstract class DefaultMessageHandler implements BuilderMessageHandler {
@Override
public final void handleBuildMessage(CmdlineRemoteProto.Message.BuilderMessage msg) {
switch (msg.getType()) {
case BUILD_EVENT:
@@ -35,9 +31,15 @@ public abstract class BuildMessageHandler {
case COMPILE_MESSAGE:
handleCompileMessage(msg.getCompileMessage());
break;
case FS_STATE:
handleFSStateMessage(msg.getFsstateMessage());
break;
}
}
protected void handleFSStateMessage(CmdlineRemoteProto.Message.FSStateMessage message) {
}
protected abstract void handleCompileMessage(CmdlineRemoteProto.Message.BuilderMessage.CompileMessage message);
protected abstract void handleBuildEvent(CmdlineRemoteProto.Message.BuilderMessage.BuildEvent event);
@@ -0,0 +1,83 @@
/*
* 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.compiler.server;
import org.jetbrains.jps.api.CmdlineRemoteProto;
import org.jetbrains.jps.incremental.fs.FSState;
import java.io.File;
import java.util.*;
/**
* @author Eugene Zhuravlev
* Date: 4/18/12
*/
public class FSStateMessageHandler extends DefaultMessageHandler {
private final FSState myFsState;
private final DefaultMessageHandler myDelegate;
protected FSStateMessageHandler(FSState fsState, DefaultMessageHandler delegate) {
myFsState = fsState;
myDelegate = delegate;
}
@Override
public void handleFailure(CmdlineRemoteProto.Message.Failure failure) {
myDelegate.handleFailure(failure);
}
@Override
public void sessionTerminated() {
myDelegate.sessionTerminated();
}
protected void handleFSStateMessage(CmdlineRemoteProto.Message.FSStateMessage message) {
try {
myDelegate.handleFSStateMessage(message);
}
finally {
final String moduleName = message.getModuleName();
final List<String> deleteProduction = message.getDeletedProductionList();
final List<String> deletedTests = message.getDeletedTestsList();
final Map<File,Set<File>> recompileProduction = new HashMap<File, Set<File>>();
final Map<File, Set<File>> recompileTests = new HashMap<File, Set<File>>();
for (CmdlineRemoteProto.Message.FSStateMessage.RootDelta delta : message.getRecompileDeltaList()) {
final File root = new File(delta.getRoot());
final Map<File, Set<File>> map = delta.getTestSources()? recompileTests : recompileProduction;
Set<File> files = map.get(root);
if (files == null) {
files = new HashSet<File>();
map.put(root, files);
}
for (String path : delta.getPathList()) {
files.add(new File(path));
}
}
myFsState.init(moduleName, deleteProduction, deletedTests, recompileProduction, recompileTests);
}
}
protected void handleCompileMessage(CmdlineRemoteProto.Message.BuilderMessage.CompileMessage message) {
myDelegate.handleCompileMessage(message);
}
protected void handleBuildEvent(CmdlineRemoteProto.Message.BuilderMessage.BuildEvent event) {
myDelegate.handleBuildEvent(event);
}
}
@@ -16,6 +16,7 @@
package com.intellij.packaging.impl.artifacts;
import com.intellij.compiler.CompileServerManager;
import com.intellij.compiler.server.BuildManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.WriteAction;
@@ -371,6 +372,7 @@ public class ArtifactManagerImpl extends ArtifactManager implements ProjectCompo
updateWatchedRoots();
if (hasChanges) {
CompileServerManager.getInstance().sendReloadRequest(myProject);
BuildManager.getInstance().clearState(myProject);
}
}
@@ -15,9 +15,17 @@ message Message {
required string value = 2;
}
message PathStampPair {
required string path = 1;
required uint64 stamp = 2;
message FSStateMessage {
message RootDelta {
required bool test_sources = 1;
required string root = 2;
repeated string path = 3;
}
required string module_name = 1;
repeated RootDelta recompile_delta = 2;
repeated string deleted_production = 3;
repeated string deleted_tests = 4;
}
enum Type {
@@ -70,6 +78,7 @@ message Message {
repeated string file_path = 5;
repeated string artifact_name = 6;
repeated KeyValuePair builder_parameter = 7;
repeated FSStateMessage fs_state = 8;
}
required Type type = 1;
@@ -81,8 +90,8 @@ message Message {
PARAM_REQUEST = 1;
BUILD_EVENT = 2;
COMPILE_MESSAGE = 3;
TIMESTAMPS_EVENT = 4;
CLEAN_TIMESTAMPS = 5;
FS_STATE = 4;
FS_EVENT = 5;
}
message BuildEvent {
@@ -127,15 +136,10 @@ message Message {
optional float done = 9;
}
message TimestampsMessage {
repeated PathStampPair to_update = 1;
repeated string to_remove = 2;
}
required Type type = 1;
optional BuildEvent build_event = 2;
optional CompileMessage compile_message = 3;
optional TimestampsMessage timestamps_message = 4;
optional FSStateMessage fsstate_message = 4;
}
required UUID session_id = 1;
@@ -3,15 +3,13 @@ package org.jetbrains.jps.api;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.incremental.fs.FSState;
import org.jetbrains.jps.incremental.messages.BuildMessage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintStream;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.UUID;
import java.util.*;
/**
* @author Eugene Zhuravlev
@@ -19,14 +17,21 @@ import java.util.UUID;
*/
public class CmdlineProtoUtil {
public static CmdlineRemoteProto.Message.BuilderMessage createFSStateBuilderMessage(String moduleName, FSState fsState) {
final CmdlineRemoteProto.Message.FSStateMessage fsStateMessage = createFSStateMessage(moduleName, fsState);
return CmdlineRemoteProto.Message.BuilderMessage.newBuilder().setType(CmdlineRemoteProto.Message.BuilderMessage.Type.FS_STATE).setFsstateMessage(
fsStateMessage).build();
}
public static CmdlineRemoteProto.Message.ControllerMessage createMakeRequest(String project,
Collection<String> modules,
Collection<String> artifacts,
final Map<String, String> userData,
final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals) {
final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals,
final FSState fsState) {
return createBuildParametersMessage(CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.Type.MAKE, project, modules, artifacts,
userData, Collections.<String>emptyList(),
globals);
globals, fsState);
}
public static CmdlineRemoteProto.Message.ControllerMessage createForceCompileRequest(String project,
@@ -34,29 +39,31 @@ public class CmdlineProtoUtil {
Collection<String> artifacts,
Collection<String> paths,
final Map<String, String> userData,
final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals) {
final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals,
final FSState fsState) {
return createBuildParametersMessage(CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.Type.FORCED_COMPILATION, project, modules,
artifacts,
userData, paths, globals);
userData, paths, globals, fsState);
}
public static CmdlineRemoteProto.Message.ControllerMessage createRebuildRequest(String project,
final Map<String, String> userData,
final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals) {
final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals,
final FSState fsState) {
return createBuildParametersMessage(CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.Type.REBUILD, project,
Collections.<String>emptyList(),
Collections.<String>emptyList(), userData, Collections.<String>emptyList(),
globals);
globals, fsState);
}
public static CmdlineRemoteProto.Message.ControllerMessage createCleanRequest(String project,
Collection<String> modules,
Collection<String> artifacts,
final Map<String, String> userData,
final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals) {
final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals,
final FSState fsState) {
return createBuildParametersMessage(
CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.Type.CLEAN, project, modules, artifacts, userData, Collections.<String>emptyList(),
globals
CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.Type.CLEAN, project, modules, artifacts, userData, Collections.<String>emptyList(), globals, fsState
);
}
@@ -66,7 +73,8 @@ public class CmdlineProtoUtil {
Collection<String> artifacts,
Map<String, String> userData,
Collection<String> paths,
final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals) {
final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals,
FSState fsState) {
final CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.Builder
builder = CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.newBuilder();
builder.setGlobalSettings(globals);
@@ -90,6 +98,11 @@ public class CmdlineProtoUtil {
if (!paths.isEmpty()) {
builder.addAllFilePath(paths);
}
for (String moduleName : fsState.getInitializedModules()) {
builder.addFsState(createFSStateMessage(moduleName, fsState));
}
return CmdlineRemoteProto.Message.ControllerMessage.newBuilder().setType(CmdlineRemoteProto.Message.ControllerMessage.Type.BUILD_PARAMETERS).setParamsMessage(builder.build()).build();
}
@@ -213,22 +226,26 @@ public class CmdlineProtoUtil {
return uuidBuilder.setMostSigBits(sessionId.getMostSignificantBits()).setLeastSigBits(sessionId.getLeastSignificantBits()).build();
}
public static CmdlineRemoteProto.Message.BuilderMessage createTimestampsMessage(Collection<Pair<File, Long>> toUpdate, Collection<File> toRemove) {
final CmdlineRemoteProto.Message.BuilderMessage.TimestampsMessage.Builder tsBuilder =
CmdlineRemoteProto.Message.BuilderMessage.TimestampsMessage.newBuilder();
for (Pair<File, Long> p : toUpdate) {
final File file = p.first;
final Long timestamp = p.second;
final CmdlineRemoteProto.Message.PathStampPair pair = CmdlineRemoteProto.Message.PathStampPair.newBuilder().setPath(
FileUtil.toSystemIndependentName(file.getPath())).setStamp(timestamp).build();
tsBuilder.addToUpdate(pair);
}
for (File file : toRemove) {
tsBuilder.addToRemove(FileUtil.toSystemIndependentName(file.getPath()));
}
return CmdlineRemoteProto.Message.BuilderMessage.newBuilder().setType(CmdlineRemoteProto.Message.BuilderMessage.Type.TIMESTAMPS_EVENT).setTimestampsMessage(tsBuilder.build()).build();
private static CmdlineRemoteProto.Message.FSStateMessage createFSStateMessage(String moduleName, FSState fsState) {
final CmdlineRemoteProto.Message.FSStateMessage.Builder stateBuilder = CmdlineRemoteProto.Message.FSStateMessage.newBuilder();
stateBuilder.setModuleName(moduleName);
stateBuilder.addAllDeletedProduction(fsState.getDeletedPaths(moduleName, false));
stateBuilder.addAllDeletedTests(fsState.getDeletedPaths(moduleName, true));
fillRecompilePaths(moduleName, fsState, false, stateBuilder);
fillRecompilePaths(moduleName, fsState, true, stateBuilder);
return stateBuilder.build();
}
private static void fillRecompilePaths(String moduleName, FSState fsState, final boolean forTests, CmdlineRemoteProto.Message.FSStateMessage.Builder stateBuilder) {
for (Map.Entry<File, Set<File>> entry : fsState.getSourcesToRecompile(moduleName, forTests).entrySet()) {
final CmdlineRemoteProto.Message.FSStateMessage.RootDelta.Builder deltaBuilder = CmdlineRemoteProto.Message.FSStateMessage.RootDelta.newBuilder();
deltaBuilder.setTestSources(forTests);
deltaBuilder.setRoot(FileUtil.toSystemIndependentName(entry.getKey().getPath()));
for (File file : entry.getValue()) {
deltaBuilder.addPath(FileUtil.toSystemIndependentName(file.getPath()));
}
stateBuilder.addRecompileDelta(deltaBuilder.build());
}
}
}
File diff suppressed because it is too large Load Diff
@@ -110,7 +110,7 @@ public class RequestFuture<T> implements Future {
return null;
}
public T getResponseHandler() {
public T getMessageHandler() {
return myHandler;
}
}
@@ -33,7 +33,7 @@ final class ProtobufClientMessageHandler<T extends ProtobufResponseHandler> exte
public final void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
final UUID messageUUID = myUuidGetter.getSessionUUID(e);
final RequestFuture<T> future = myHandlers.get(messageUUID);
final T handler = future != null ? future.getResponseHandler() : null;
final T handler = future != null ? future.getMessageHandler() : null;
if (handler == null) {
terminateSession(messageUUID);
}
@@ -57,7 +57,7 @@ final class ProtobufClientMessageHandler<T extends ProtobufResponseHandler> exte
private void terminateSession(UUID sessionId) {
final RequestFuture<T> future = removeFuture(sessionId);
if (future != null) {
final T handler = future.getResponseHandler();
final T handler = future.getMessageHandler();
try {
if (handler != null) {
try {
@@ -25,7 +25,6 @@ import org.jetbrains.jps.incremental.fs.BuildFSState;
import org.jetbrains.jps.incremental.fs.RootDescriptor;
import org.jetbrains.jps.incremental.messages.*;
import org.jetbrains.jps.incremental.storage.BuildDataManager;
import org.jetbrains.jps.incremental.storage.NetworkStamps;
import org.jetbrains.jps.incremental.storage.ProjectTimestamps;
import org.jetbrains.jps.incremental.storage.Timestamps;
import org.jetbrains.jps.server.ProjectDescriptor;
@@ -57,6 +56,7 @@ final class BuildSession implements Runnable, CanceledStatus {
private final List<String> myFilePaths;
private final Map<String, String> myBuilderParams;
private String myProjectPath;
private List<CmdlineRemoteProto.Message.FSStateMessage> myModuleFSStates;
// todo pass FSState in order not to scan FS from scratch
@@ -91,6 +91,7 @@ final class BuildSession implements Runnable, CanceledStatus {
for (CmdlineRemoteProto.Message.KeyValuePair pair : params.getBuilderParameterList()) {
myBuilderParams.put(pair.getKey(), pair.getValue());
}
myModuleFSStates = params.getFsStateList();
}
public void run() {
@@ -150,12 +151,30 @@ final class BuildSession implements Runnable, CanceledStatus {
ProjectDescriptor pd;
final Project project = loadProject(projectPath);
final BuildFSState fsState = new BuildFSState(false);
for (CmdlineRemoteProto.Message.FSStateMessage state : myModuleFSStates) {
final Map<File, Set<File>> recompileProduction = new HashMap<File, Set<File>>();
final Map<File, Set<File>> recompileTests = new HashMap<File, Set<File>>();
for (CmdlineRemoteProto.Message.FSStateMessage.RootDelta delta : state.getRecompileDeltaList()) {
final Map<File, Set<File>> map = delta.getTestSources()? recompileTests : recompileProduction;
final File root = new File(delta.getRoot());
Set<File> files = map.get(root);
if (files == null) {
files = new HashSet<File>();
map.put(root, files);
}
for (String path : delta.getPathList()) {
files.add(new File(path));
}
}
fsState.init(state.getModuleName(), state.getDeletedProductionList(), state.getDeletedTestsList(), recompileProduction, recompileTests);
}
ProjectTimestamps projectTimestamps = null;
BuildDataManager dataManager = null;
final File dataStorageRoot = Utils.getDataStorageRoot(project);
try {
// todo: create optionally
//projectTimestamps = new ProjectTimestamps(dataStorageRoot);
projectTimestamps = new ProjectTimestamps(dataStorageRoot);
dataManager = new BuildDataManager(dataStorageRoot, true);
if (dataManager.versionDiffers()) {
forceCleanCaches = true;
@@ -189,7 +208,7 @@ final class BuildSession implements Runnable, CanceledStatus {
buildType = BuildType.PROJECT_REBUILD;
}
final Timestamps timestamps = projectTimestamps != null? projectTimestamps.getStorage() : new NetworkStamps(mySessionId, myChannel);
final Timestamps timestamps = pd.timestamps.getStorage();
final CompileScope compileScope = createCompilationScope(buildType, pd, timestamps, modules, artifacts, paths);
final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), timestamps, builderParams, cs);
@@ -216,7 +235,6 @@ final class BuildSession implements Runnable, CanceledStatus {
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;
@@ -226,6 +244,13 @@ final class BuildSession implements Runnable, CanceledStatus {
}
}
}
// save initialized FS state for future use
for (Module module : pd.project.getModules().values()) {
if (fsState.isInitialized(module.getName())) {
Channels.write(myChannel, CmdlineProtoUtil.toMessage(mySessionId, CmdlineProtoUtil.createFSStateBuilderMessage(module.getName(),
fsState)));
}
}
}
finally {
pd.release();
@@ -249,7 +249,7 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler
myNonIncrementalModules.remove(new Pair<Module, DirtyMarkScope>(module, dirtyScope));
}
if (isProjectRebuild()) {
myProjectDescriptor.fsState.markInitialScanPerformed(module, compilingTests);
myProjectDescriptor.fsState.markInitialScanPerformed(module.getName(), compilingTests);
}
final List<RootDescriptor> roots = myProjectDescriptor.rootsIndex.getModuleRoots(module);
for (RootDescriptor descriptor : roots) {
@@ -303,7 +303,7 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler
}
else {
if (isMake()) {
if (myProjectDescriptor.fsState.markInitialScanPerformed(module, isCompilingTests())) {
if (myProjectDescriptor.fsState.markInitialScanPerformed(module.getName(), isCompilingTests())) {
initModuleFSState(module);
}
}
@@ -12,7 +12,6 @@ import org.jetbrains.jps.incremental.storage.Timestamps;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -22,8 +21,6 @@ import java.util.Set;
* Date: 12/16/11
*/
public class BuildFSState extends FSState {
private final Set<Module> myInitialTestsScanPerformed = Collections.synchronizedSet(new HashSet<Module>());
private final Set<Module> myInitialProductionScanPerformed = Collections.synchronizedSet(new HashSet<Module>());
private final Set<String> myContextModules = new HashSet<String>();
private volatile FilesDelta myCurrentRoundDelta;
@@ -37,12 +34,14 @@ public class BuildFSState extends FSState {
myAlwaysScanFS = alwaysScanFS;
}
public boolean markInitialScanPerformed(Module module, boolean forTests) {
if (myAlwaysScanFS) {
return true;
}
final Set<Module> map = forTests ? myInitialTestsScanPerformed : myInitialProductionScanPerformed;
return map.add(module);
@Override
public boolean isInitialized(String moduleName) {
return myAlwaysScanFS || super.isInitialized(moduleName);
}
@Override
public boolean markInitialScanPerformed(String moduleName, boolean forTests) {
return myAlwaysScanFS || super.markInitialScanPerformed(moduleName, forTests);
}
@Override
@@ -14,11 +14,25 @@ import java.util.*;
*/
public class FSState {
private final Map<String, FilesDelta> myDeltas = Collections.synchronizedMap(new HashMap<String, FilesDelta>());
protected final Set<String> myInitialTestsScanPerformed = Collections.synchronizedSet(new HashSet<String>());
protected final Set<String> myInitialProductionScanPerformed = Collections.synchronizedSet(new HashSet<String>());
public void clearAll() {
myDeltas.clear();
}
public Set<String> getInitializedModules() {
final HashSet<String> result = new HashSet<String>(myInitialProductionScanPerformed);
result.retainAll(myInitialTestsScanPerformed);
return result;
}
public void init(String moduleName, final Collection<String> deleteProduction, final Collection<String> deletedTests, final Map<File, Set<File>> recompileProduction, final Map<File, Set<File>> recompileTests) {
getDelta(moduleName).init(deleteProduction, deletedTests, recompileProduction, recompileTests);
myInitialTestsScanPerformed.add(moduleName);
myInitialProductionScanPerformed.add(moduleName);
}
public final void clearRecompile(final RootDescriptor rd) {
getDelta(rd.module).clearRecompile(rd.root, rd.isTestRoot);
}
@@ -77,4 +91,12 @@ public class FSState {
return delta;
}
}
public boolean isInitialized(String moduleName) {
return myInitialTestsScanPerformed.contains(moduleName) && myInitialProductionScanPerformed.contains(moduleName);
}
public boolean markInitialScanPerformed(final String moduleName, boolean forTests) {
return (forTests ? myInitialTestsScanPerformed : myInitialProductionScanPerformed).add(moduleName);
}
}
@@ -13,6 +13,18 @@ final class FilesDelta {
private final Map<File, Set<File>> mySourcesToRecompile = Collections.synchronizedMap(new HashMap<File, Set<File>>()); // srcRoot -> set of sources
private final Map<File, Set<File>> myTestsToRecompile = Collections.synchronizedMap(new HashMap<File, Set<File>>()); // srcRoot -> set of sources
public void init(Collection<String> deletedProduction, Collection<String> deletedTests, Map<File, Set<File>> recompileProduction, Map<File, Set<File>> recompileTests) {
myDeletedProduction.clear();
myDeletedProduction.addAll(deletedProduction);
myDeletedTests.clear();
myDeletedTests.addAll(deletedTests);
mySourcesToRecompile.clear();
mySourcesToRecompile.putAll(recompileProduction);
myTestsToRecompile.clear();
myTestsToRecompile.putAll(recompileTests);
}
public boolean markRecompile(File root, boolean isTestRoot, File file) {
final boolean added = _addToRecompiled(root, isTestRoot, file);
if (added) {
@@ -402,7 +402,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
future.cancel(false);
}
}
rc = future.getResponseHandler().isTerminatedSuccessfully();
rc = future.getMessageHandler().isTerminatedSuccessfully();
}
return rc;
}
@@ -1,61 +0,0 @@
package org.jetbrains.jps.incremental.storage;
import com.intellij.openapi.util.Pair;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.Channels;
import org.jetbrains.jps.api.CmdlineProtoUtil;
import org.jetbrains.jps.api.CmdlineRemoteProto;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.UUID;
/**
* @author Eugene Zhuravlev
* Date: 4/24/12
*/
public class NetworkStamps implements Timestamps{
private final UUID mySessionId;
private final Channel myChannel;
public NetworkStamps(UUID sessionId, Channel channel) {
mySessionId = sessionId;
myChannel = channel;
}
@Override
public void force() {
// empty
}
// todo: add alarm to send events in bulk messages?
@Override
public void saveStamp(File file, long timestamp) throws IOException {
final CmdlineRemoteProto.Message.BuilderMessage builderMessage = CmdlineProtoUtil.createTimestampsMessage(
Collections.singleton(new Pair<File, Long>(file, timestamp)), Collections.<File>emptyList()
);
Channels.write(myChannel, CmdlineProtoUtil.toMessage(mySessionId, builderMessage));
}
@Override
public void removeStamp(File file) throws IOException {
final CmdlineRemoteProto.Message.BuilderMessage builderMessage = CmdlineProtoUtil.createTimestampsMessage(
Collections.<Pair<File, Long>>emptyList(), Collections.singleton(file)
);
Channels.write(myChannel, CmdlineProtoUtil.toMessage(mySessionId, builderMessage));
}
@Override
public void clean() throws IOException {
Channels.write(myChannel, CmdlineProtoUtil.toMessage(mySessionId,
CmdlineRemoteProto.Message.BuilderMessage.newBuilder().setType(CmdlineRemoteProto.Message.BuilderMessage.Type.CLEAN_TIMESTAMPS).build()
));
}
@Override
public long getStamp(File file) throws IOException {
throw new IOException("operation getStamp() is not supported");
}
}
@@ -1,6 +1,5 @@
package org.jetbrains.jps.server;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.JavaSdk;
import org.jetbrains.jps.Module;
import org.jetbrains.jps.Project;
@@ -22,7 +21,6 @@ import java.util.Set;
public final class ProjectDescriptor {
public final Project project;
public final BuildFSState fsState;
@Nullable
public final ProjectTimestamps timestamps;
public final BuildDataManager dataManager;
private final BuildLoggingManager myLoggingManager;
@@ -32,7 +30,7 @@ public final class ProjectDescriptor {
public ProjectDescriptor(Project project,
BuildFSState fsState,
@Nullable ProjectTimestamps timestamps,
ProjectTimestamps timestamps,
BuildDataManager dataManager,
BuildLoggingManager loggingManager) {
this.project = project;
@@ -73,9 +71,7 @@ public final class ProjectDescriptor {
}
if (shouldClose) {
try {
if (timestamps != null) {
timestamps.close();
}
timestamps.close();
}
finally {
try {
@@ -172,7 +172,6 @@ class ServerState {
}
final ProjectDescriptor finalPd = pd;
assert pd.timestamps != null;
try {
for (int attempt = 0; attempt < 2; attempt++) {
if (forceCleanCaches && modules.isEmpty() && paths.isEmpty()) {
@@ -64,6 +64,10 @@ public class MemberChangeTest extends IncrementalTestCase {
doTest();
}
public void testAddMethodWithCovariantReturnType() throws Exception {
doTest();
}
public void testAddMoreAccessibleMethodToBase() throws Exception {
doTest();
}