compiler: add 'Compile affected unloaded modules before commit' option

Now the build process can optionally load unloaded modules and compile them. It's used to check before committing that changes don't break compilation of unloaded modules (IDEA-180275).
This commit is contained in:
nik
2017-10-09 20:27:04 +03:00
parent f6553f228f
commit 72ebbbe011
23 changed files with 353 additions and 36 deletions
@@ -263,6 +263,11 @@ public class CompilerManagerImpl extends CompilerManager {
new CompileDriver(myProject).make(scope, new ListenerNotificator(callback));
}
@Override
public void makeWithModalProgress(@NotNull CompileScope scope, @Nullable CompileStatusNotification callback) {
new CompileDriver(myProject).make(scope, true, new ListenerNotificator(callback));
}
@Override
public void make(@NotNull CompileScope scope, CompilerFilter filter, @Nullable CompileStatusNotification callback) {
final CompileDriver compileDriver = new CompileDriver(myProject);
@@ -66,10 +66,7 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jps.api.CmdlineProtoUtil;
import org.jetbrains.jps.api.CmdlineRemoteProto;
import org.jetbrains.jps.api.GlobalOptions;
import org.jetbrains.jps.api.TaskFuture;
import org.jetbrains.jps.api.*;
import org.jetbrains.jps.model.java.JavaSourceRootType;
import javax.swing.*;
@@ -107,8 +104,12 @@ public class CompileDriver {
}
public void make(CompileScope scope, CompileStatusNotification callback) {
make(scope, false, callback);
}
public void make(CompileScope scope, boolean withModalProgress, CompileStatusNotification callback) {
if (validateCompilerConfiguration(scope)) {
startup(scope, false, false, callback, null);
startup(scope, false, false, withModalProgress, callback, null);
}
else {
callback.finished(true, 0, 0, DummyCompileContext.getInstance());
@@ -195,7 +196,7 @@ public class CompileDriver {
scopes.addAll(explicitScopes);
}
else if (!compileContext.isRebuild() && !CompileScopeUtil.allProjectModulesAffected(compileContext)) {
CompileScopeUtil.addScopesForModules(Arrays.asList(scope.getAffectedModules()), scopes, forceBuild);
CompileScopeUtil.addScopesForModules(Arrays.asList(scope.getAffectedModules()), scope.getAffectedUnloadedModules(), scopes, forceBuild);
}
else {
scopes.addAll(CmdlineProtoUtil.createAllModulesScopes(forceBuild));
@@ -228,7 +229,7 @@ public class CompileDriver {
// need to pass scope's user data to server
final Map<String, String> builderParams;
if (onlyCheckUpToDate) {
builderParams = Collections.emptyMap();
builderParams = new HashMap<>();
}
else {
final Map<Key, Object> exported = scope.exportUserData();
@@ -241,9 +242,12 @@ public class CompileDriver {
}
}
else {
builderParams = Collections.emptyMap();
builderParams = new HashMap<>();
}
}
if (!scope.getAffectedUnloadedModules().isEmpty()) {
builderParams.put(BuildParametersKeys.LOAD_UNLOADED_MODULES, Boolean.TRUE.toString());
}
final MessageBus messageBus = myProject.getMessageBus();
final MultiMap<String, Artifact> outputToArtifact = ArtifactCompilerUtil.containsArtifacts(scopes) ? ArtifactCompilerUtil.createOutputToArtifactMap(myProject) : null;
@@ -372,16 +376,22 @@ public class CompileDriver {
});
}
private void startup(final CompileScope scope, final boolean isRebuild, final boolean forceCompile,
final CompileStatusNotification callback, final CompilerMessage message) {
startup(scope, isRebuild, forceCompile, false, callback, message);
}
private void startup(final CompileScope scope,
final boolean isRebuild,
final boolean forceCompile,
final CompileStatusNotification callback,
boolean withModalProgress, final CompileStatusNotification callback,
final CompilerMessage message) {
ApplicationManager.getApplication().assertIsDispatchThread();
final String contentName = CompilerBundle.message(forceCompile ? "compiler.content.name.compile" : "compiler.content.name.make");
final boolean isUnitTestMode = ApplicationManager.getApplication().isUnitTestMode();
final CompilerTask compileTask = new CompilerTask(myProject, contentName, isUnitTestMode, true, true, isCompilationStartedAutomatically(scope));
final CompilerTask compileTask = new CompilerTask(myProject, contentName, isUnitTestMode, !withModalProgress, true,
isCompilationStartedAutomatically(scope), withModalProgress);
StatusBar.Info.set("", myProject, "Compiler");
// ensure the project model seen by build process is up-to-date
@@ -36,13 +36,19 @@ public class CompileScopeUtil {
scope.putUserData(BASE_SCOPE_FOR_EXTERNAL_BUILD, scopes);
}
public static void addScopesForModules(Collection<Module> modules, List<TargetTypeBuildScope> scopes, boolean forceBuild) {
if (!modules.isEmpty()) {
public static void addScopesForModules(Collection<Module> modules,
Collection<String> unloadedModules,
List<TargetTypeBuildScope> scopes,
boolean forceBuild) {
if (!modules.isEmpty() || !unloadedModules.isEmpty()) {
for (JavaModuleBuildTargetType type : JavaModuleBuildTargetType.ALL_TYPES) {
TargetTypeBuildScope.Builder builder = TargetTypeBuildScope.newBuilder().setTypeId(type.getTypeId()).setForceBuild(forceBuild);
for (Module module : modules) {
builder.addTargetId(module.getName());
}
for (String unloadedModule : unloadedModules) {
builder.addTargetId(unloadedModule);
}
scopes.add(builder.build());
}
}
@@ -90,6 +90,16 @@ public class CompositeScope extends ExportableUserDataHolderBase implements Comp
return modules.toArray(new Module[modules.size()]);
}
@NotNull
@Override
public Collection<String> getAffectedUnloadedModules() {
Set<String> unloadedModules = new LinkedHashSet<>();
for (final CompileScope compileScope : myScopes) {
ContainerUtil.addAll(unloadedModules, compileScope.getAffectedUnloadedModules());
}
return unloadedModules;
}
public <T> T getUserData(@NotNull Key<T> key) {
for (CompileScope compileScope : myScopes) {
T userData = compileScope.getUserData(key);
@@ -24,11 +24,13 @@ package com.intellij.compiler.impl;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.UnloadedModuleDescription;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.util.CommonProcessors;
import org.jetbrains.annotations.NotNull;
@@ -38,9 +40,10 @@ public class ModuleCompileScope extends FileIndexCompileScope {
private final Project myProject;
private final Set<Module> myScopeModules;
private final Module[] myModules;
private final Collection<String> myIncludedUnloadedModules;
public ModuleCompileScope(final Module module, boolean includeDependentModules) {
this(module.getProject(), Collections.singleton(module), includeDependentModules, false);
this(module.getProject(), Collections.singleton(module), Collections.emptyList(), includeDependentModules, false);
}
public ModuleCompileScope(Project project, final Module[] modules, boolean includeDependentModules) {
@@ -48,11 +51,12 @@ public class ModuleCompileScope extends FileIndexCompileScope {
}
public ModuleCompileScope(Project project, final Module[] modules, boolean includeDependentModules, boolean includeRuntimeDependencies) {
this(project, Arrays.asList(modules), includeDependentModules, includeRuntimeDependencies);
this(project, Arrays.asList(modules), Collections.emptyList(), includeDependentModules, includeRuntimeDependencies);
}
private ModuleCompileScope(Project project, final Collection<Module> modules, boolean includeDependentModules, boolean includeRuntimeDeps) {
public ModuleCompileScope(Project project, final Collection<Module> modules, Collection<String> includedUnloadedModules, boolean includeDependentModules, boolean includeRuntimeDeps) {
myProject = project;
myIncludedUnloadedModules = includedUnloadedModules;
myScopeModules = new HashSet<>();
for (Module module : modules) {
if (module == null) {
@@ -77,6 +81,12 @@ public class ModuleCompileScope extends FileIndexCompileScope {
return myScopeModules.toArray(new Module[myScopeModules.size()]);
}
@NotNull
@Override
public Collection<String> getAffectedUnloadedModules() {
return Collections.unmodifiableCollection(myIncludedUnloadedModules);
}
protected FileIndex[] getFileIndices() {
final FileIndex[] indices = new FileIndex[myScopeModules.size()];
int idx = 0;
@@ -87,7 +97,7 @@ public class ModuleCompileScope extends FileIndexCompileScope {
}
public boolean belongs(final String url) {
if (myScopeModules.isEmpty()) {
if (myScopeModules.isEmpty() && myIncludedUnloadedModules.isEmpty()) {
return false; // optimization
}
Module candidateModule = null;
@@ -142,6 +152,18 @@ public class ModuleCompileScope extends FileIndexCompileScope {
}
}
ModuleManager moduleManager = ModuleManager.getInstance(myProject);
for (String unloadedModule : myIncludedUnloadedModules) {
UnloadedModuleDescription moduleDescription = moduleManager.getUnloadedModuleDescription(unloadedModule);
if (moduleDescription != null) {
for (VirtualFilePointer pointer : moduleDescription.getContentRoots()) {
if (isUrlUnderRoot(url, pointer.getUrl())) {
return true;
}
}
}
}
return false;
}
@@ -0,0 +1,154 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.compiler.impl.vcs;
import com.intellij.CommonBundle;
import com.intellij.compiler.CompilerWorkspaceConfiguration;
import com.intellij.compiler.impl.ModuleCompileScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileStatusNotification;
import com.intellij.openapi.compiler.CompilerBundle;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.impl.DirectoryIndex;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vcs.CheckinProjectPanel;
import com.intellij.openapi.vcs.changes.CommitContext;
import com.intellij.openapi.vcs.changes.CommitExecutor;
import com.intellij.openapi.vcs.checkin.CheckinHandler;
import com.intellij.openapi.vcs.checkin.CheckinHandlerFactory;
import com.intellij.openapi.vcs.ui.RefreshableOnComponent;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.ui.NonFocusableCheckBox;
import com.intellij.util.PairConsumer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.JBUI;
import com.intellij.xml.util.XmlStringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author nik
*/
public class UnloadedModulesCompilationCheckinHandler extends CheckinHandler {
private final Project myProject;
private final CheckinProjectPanel myCheckinPanel;
public UnloadedModulesCompilationCheckinHandler(Project project, CheckinProjectPanel checkinPanel) {
myProject = project;
myCheckinPanel = checkinPanel;
}
@Nullable
@Override
public RefreshableOnComponent getBeforeCheckinConfigurationPanel() {
if (ModuleManager.getInstance(myProject).getUnloadedModuleDescriptions().isEmpty()) {
return null;
}
JCheckBox checkBox = new NonFocusableCheckBox(CompilerBundle.message("checkbox.text.compile.affected.unloaded.modules"));
return new RefreshableOnComponent() {
@Override
public JComponent getComponent() {
return JBUI.Panels.simplePanel().addToLeft(checkBox);
}
@Override
public void refresh() {
}
@Override
public void saveState() {
CompilerWorkspaceConfiguration.getInstance(myProject).COMPILE_AFFECTED_UNLOADED_MODULES_BEFORE_COMMIT = checkBox.isSelected();
}
@Override
public void restoreState() {
checkBox.setSelected(CompilerWorkspaceConfiguration.getInstance(myProject).COMPILE_AFFECTED_UNLOADED_MODULES_BEFORE_COMMIT);
}
};
}
@Override
public ReturnResult beforeCheckin(@Nullable CommitExecutor executor, PairConsumer<Object, Object> additionalDataConsumer) {
if (!CompilerWorkspaceConfiguration.getInstance(myProject).COMPILE_AFFECTED_UNLOADED_MODULES_BEFORE_COMMIT
|| ModuleManager.getInstance(myProject).getUnloadedModuleDescriptions().isEmpty()) {
return ReturnResult.COMMIT;
}
ProjectFileIndex fileIndex = ProjectFileIndex.getInstance(myProject);
CompilerManager compilerManager = CompilerManager.getInstance(myProject);
Set<Module> affectedModules = new LinkedHashSet<>();
for (VirtualFile file : myCheckinPanel.getVirtualFiles()) {
if (compilerManager.isCompilableFileType(file.getFileType())) {
ContainerUtil.addIfNotNull(affectedModules, fileIndex.getModuleForFile(file));
}
}
Set<String> affectedUnloadedModules = new LinkedHashSet<>();
for (Module module : affectedModules) {
affectedUnloadedModules.addAll(DirectoryIndex.getInstance(myProject).getDependentUnloadedModules(module));
}
if (affectedUnloadedModules.isEmpty()) {
return ReturnResult.COMMIT;
}
AtomicReference<BuildResult> result = new AtomicReference<>();
compilerManager.makeWithModalProgress(new ModuleCompileScope(myProject, affectedModules, affectedUnloadedModules, true, false),
new CompileStatusNotification() {
@Override
public void finished(boolean aborted, int errors, int warnings, CompileContext compileContext) {
result.set(
aborted ? BuildResult.CANCELED : errors > 0 ? BuildResult.FAILED : BuildResult.SUCCESSFUL);
}
});
if (result.get() == BuildResult.SUCCESSFUL) {
return ReturnResult.COMMIT;
}
String message = CompilerBundle.message("dialog.message.compilation.of.unloaded.modules.failed");
int answer = Messages.showYesNoCancelDialog(myProject, XmlStringUtil.wrapInHtml(message), CompilerBundle.message("dialog.title.compilation.failed"),
CompilerBundle.message("button.text.checkin.handler.commit"),
CompilerBundle.message("button.text.checkin.handler.show.errors"),
CommonBundle.getCancelButtonText(), null);
if (answer == Messages.CANCEL) {
return ReturnResult.CANCEL;
}
else if (answer == Messages.YES) {
return ReturnResult.COMMIT;
}
else {
ApplicationManager.getApplication().invokeLater(() -> {
final ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.MESSAGES_WINDOW);
if (toolWindow != null) {
toolWindow.activate(null, false);
}
}, ModalityState.NON_MODAL);
return ReturnResult.CLOSE_WINDOW;
}
}
private enum BuildResult { SUCCESSFUL, FAILED, CANCELED }
public static class Factory extends CheckinHandlerFactory {
@NotNull
@Override
public CheckinHandler createHandler(@NotNull CheckinProjectPanel panel, @NotNull CommitContext commitContext) {
return new UnloadedModulesCompilationCheckinHandler(panel.getProject(), panel);
}
}
}
@@ -78,6 +78,7 @@ public class CompilerTask extends Task.Backgroundable {
private static final String APP_ICON_ID = "compiler";
@NotNull
private final Object myContentId = new IDObject("content_id");
private final boolean myModal;
@NotNull
private Object mySessionId = myContentId; // by default sessionID should be unique, just as content ID
@@ -105,12 +106,18 @@ public class CompilerTask extends Task.Backgroundable {
public CompilerTask(@NotNull Project project, String contentName, final boolean headlessMode, boolean forceAsync,
boolean waitForPreviousSession, boolean compilationStartedAutomatically) {
this(project, contentName, headlessMode, forceAsync, waitForPreviousSession, compilationStartedAutomatically, false);
}
public CompilerTask(@NotNull Project project, String contentName, final boolean headlessMode, boolean forceAsync,
boolean waitForPreviousSession, boolean compilationStartedAutomatically, boolean modal) {
super(project, contentName);
myContentName = contentName;
myHeadlessMode = headlessMode;
myForceAsyncExecution = forceAsync;
myWaitForPreviousSession = waitForPreviousSession;
myCompilationStartedAutomatically = compilationStartedAutomatically;
myModal = modal;
}
@NotNull
@@ -149,7 +156,12 @@ public class CompilerTask extends Task.Backgroundable {
@Override
public boolean shouldStartInBackground() {
return true;
return !myModal;
}
@Override
public boolean isConditionalModal() {
return myModal;
}
public ProgressIndicator getIndicator() {
@@ -522,7 +522,8 @@ public class BuildManager implements Disposable {
final List<TargetTypeBuildScope> scopes = CmdlineProtoUtil.createAllModulesScopes(false);
final AutoMakeMessageHandler handler = new AutoMakeMessageHandler(project);
final TaskFuture future = scheduleBuild(
project, false, true, false, scopes, Collections.emptyList(), Collections.emptyMap(), handler
project, false, true, false, scopes, Collections.emptyList(), Collections.emptyMap(),
handler
);
if (future != null) {
myAutomakeFutures.put(future, project);
@@ -52,7 +52,7 @@ public class ArtifactBuildTargetScopeProvider extends BuildTargetScopeProvider {
final Set<Artifact> artifacts = ArtifactCompileScope.getArtifactsToBuild(project, baseScope, false);
if (ArtifactCompileScope.getArtifacts(baseScope) == null) {
Set<Module> modules = ArtifactUtil.getModulesIncludedInArtifacts(artifacts, project);
CompileScopeUtil.addScopesForModules(modules, scopes, forceBuild);
CompileScopeUtil.addScopesForModules(modules, Collections.emptyList(), scopes, forceBuild);
}
if (!artifacts.isEmpty()) {
TargetTypeBuildScope.Builder builder = TargetTypeBuildScope.newBuilder()
@@ -46,6 +46,7 @@ public class CompilerWorkspaceConfiguration implements PersistentStateComponent<
public int COMPILER_PROCESS_HEAP_SIZE = 700;
public String COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS = "";
public boolean REBUILD_ON_DEPENDENCY_CHANGE = true;
public boolean COMPILE_AFFECTED_UNLOADED_MODULES_BEFORE_COMMIT = true;
public static CompilerWorkspaceConfiguration getInstance(Project project) {
return ServiceManager.getService(project, CompilerWorkspaceConfiguration.class);
@@ -21,6 +21,9 @@ import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
/**
* Interface describing the current compilation scope.
* Only sources that belong to the scope are compiled.
@@ -56,4 +59,12 @@ public interface CompileScope extends ExportableUserDataHolder {
*/
@NotNull
Module[] getAffectedModules();
/**
* @return list of names of unloaded modules this scope affects.
*/
@NotNull
default Collection<String> getAffectedUnloadedModules() {
return Collections.emptyList();
}
}
@@ -221,6 +221,11 @@ public abstract class CompilerManager {
*/
public abstract void make(@NotNull CompileScope scope, @Nullable CompileStatusNotification callback);
/**
* Same as {@link #make(CompileScope, CompileStatusNotification)} but with modal progress window instead of background progress
*/
public abstract void makeWithModalProgress(@NotNull CompileScope scope, @Nullable CompileStatusNotification callback);
/**
* Compile all modified files and all files that depend on them from the scope given.
* Files are compiled according to dependencies between the modules they belong to. Compiler excludes are honored. All modules must belong to the same project
@@ -0,0 +1,39 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.compiler;
import com.intellij.compiler.impl.ModuleCompileScope;
import com.intellij.openapi.compiler.CompilerFilter;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.vfs.VirtualFile;
import java.io.File;
import java.util.Collections;
import java.util.List;
import static com.intellij.util.io.TestFileSystemBuilder.fs;
/**
* @author nik
*/
public class UnloadedModulesCompilationTest extends BaseCompilerTestCase {
public void testDoNotCompileUnloadedModulesByDefault() {
VirtualFile a = createFile("unloaded/src/A.java", "class A{ error }");
Module unloaded = addModule("unloaded", a.getParent());
List<String> unloadedList = Collections.singletonList(unloaded.getName());
ModuleManager.getInstance(myProject).setUnloadedModules(unloadedList);
buildAllModules().assertUpToDate();
}
public void testCompileUnloadedModulesIfExplicitlySpecified() {
VirtualFile a = createFile("unloaded/src/A.java", "class A{}");
Module unloaded = addModule("unloaded", a.getParent());
File outputDir = getOutputDir(unloaded, false);
List<String> unloadedList = Collections.singletonList(unloaded.getName());
ModuleManager.getInstance(myProject).setUnloadedModules(unloadedList);
make(new ModuleCompileScope(myProject, Collections.emptyList(), unloadedList, true, false), CompilerFilter.ALL);
fs().file("A.class").build().assertDirectoryEqual(outputDir);
}
}
@@ -5,4 +5,5 @@ package org.jetbrains.jps.api;
*/
public interface BuildParametersKeys {
String FORCE_MODEL_LOADING = "_force_model_loading";
String LOAD_UNLOADED_MODULES = "load_unloaded_modules";
}
@@ -129,7 +129,7 @@ public class BuildMain {
try {
FileSystemUtil.getAttributes(projectPathToPreload); // this will pre-load all FS optimizations
final BuildRunner runner = new BuildRunner(new JpsModelLoaderImpl(projectPathToPreload, globalsPathToPreload, null));
final BuildRunner runner = new BuildRunner(new JpsModelLoaderImpl(projectPathToPreload, globalsPathToPreload, false, null));
data.setRunner(runner);
final File dataStorageRoot = Utils.getDataStorageRoot(projectPathToPreload);
@@ -86,8 +86,7 @@ final class BuildSession implements Runnable, CanceledStatus {
@Nullable CmdlineRemoteProto.Message.ControllerMessage.FSEvent delta, @Nullable PreloadedData preloaded) {
mySessionId = sessionId;
myChannel = channel;
myPreloadedData = preloaded;
final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals = params.getGlobalSettings();
myProjectPath = FileUtil.toCanonicalPath(params.getProjectId());
String globalOptionsPath = FileUtil.toCanonicalPath(globals.getGlobalOptionsPath());
@@ -99,11 +98,24 @@ final class BuildSession implements Runnable, CanceledStatus {
builderParams.put(pair.getKey(), pair.getValue());
}
myInitialFSDelta = delta;
if (preloaded == null || preloaded.getRunner() == null) {
myBuildRunner = new BuildRunner(new JpsModelLoaderImpl(myProjectPath, globalOptionsPath, null));
boolean loadUnloadedModules = Boolean.parseBoolean(builderParams.get(BuildParametersKeys.LOAD_UNLOADED_MODULES));
if (loadUnloadedModules && preloaded != null) {
myPreloadedData = null;
ProjectDescriptor projectDescriptor = preloaded.getProjectDescriptor();
if (projectDescriptor != null) {
projectDescriptor.release();
preloaded.setProjectDescriptor(null);
}
}
else {
myBuildRunner = preloaded.getRunner();
myPreloadedData = preloaded;
}
if (myPreloadedData == null || myPreloadedData.getRunner() == null) {
myBuildRunner = new BuildRunner(new JpsModelLoaderImpl(myProjectPath, globalOptionsPath, loadUnloadedModules, null));
}
else {
myBuildRunner = myPreloadedData.getRunner();
}
myBuildRunner.setFilePaths(filePaths);
myBuildRunner.setBuilderParams(builderParams);
@@ -30,11 +30,16 @@ public class JpsModelLoaderImpl implements JpsModelLoader {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.cmdline.JpsModelLoaderImpl");
private final String myProjectPath;
private final String myGlobalOptionsPath;
private final boolean myLoadUnloadedModules;
private final ParameterizedRunnable<JpsModel> myModelInitializer;
public JpsModelLoaderImpl(String projectPath, String globalOptionsPath, @Nullable ParameterizedRunnable<JpsModel> initializer) {
public JpsModelLoaderImpl(String projectPath,
String globalOptionsPath,
boolean loadUnloadedModules,
@Nullable ParameterizedRunnable<JpsModel> initializer) {
myProjectPath = projectPath;
myGlobalOptionsPath = globalOptionsPath;
myLoadUnloadedModules = loadUnloadedModules;
myModelInitializer = initializer;
}
@@ -42,7 +47,7 @@ public class JpsModelLoaderImpl implements JpsModelLoader {
public JpsModel loadModel() throws IOException {
final long start = System.currentTimeMillis();
LOG.info("Loading model: project path = " + myProjectPath + ", global options path = " + myGlobalOptionsPath);
final JpsModel model = JpsSerializationManager.getInstance().loadModel(myProjectPath, myGlobalOptionsPath);
final JpsModel model = JpsSerializationManager.getInstance().loadModel(myProjectPath, myGlobalOptionsPath, myLoadUnloadedModules);
if (myModelInitializer != null) {
myModelInitializer.run(model);
}
@@ -67,12 +67,14 @@ public class JpsProjectLoader extends JpsLoaderBase {
public static final String CLASSPATH_DIR_ATTRIBUTE = "classpath-dir";
private final JpsProject myProject;
private final Map<String, String> myPathVariables;
private final boolean myLoadUnloadedModules;
private JpsProjectLoader(JpsProject project, Map<String, String> pathVariables, Path baseDir) {
private JpsProjectLoader(JpsProject project, Map<String, String> pathVariables, Path baseDir, boolean loadUnloadedModules) {
super(createProjectMacroExpander(pathVariables, baseDir));
myProject = project;
myPathVariables = pathVariables;
myProject.getContainer().setChild(JpsProjectSerializationDataExtensionImpl.ROLE, new JpsProjectSerializationDataExtensionImpl(baseDir));
myLoadUnloadedModules = loadUnloadedModules;
}
static JpsMacroExpander createProjectMacroExpander(Map<String, String> pathVariables, @NotNull Path baseDir) {
@@ -81,10 +83,17 @@ public class JpsProjectLoader extends JpsLoaderBase {
return expander;
}
public static void loadProject(final JpsProject project, Map<String, String> pathVariables, String projectPath) throws IOException {
public static void loadProject(final JpsProject project,
Map<String, String> pathVariables,
String projectPath) throws IOException {
loadProject(project, pathVariables, projectPath, false);
}
public static void loadProject(final JpsProject project, Map<String, String> pathVariables, String projectPath,
boolean loadUnloadedModules) throws IOException {
Path file = Paths.get(FileUtil.toCanonicalPath(projectPath));
if (Files.isRegularFile(file) && projectPath.endsWith(".ipr")) {
new JpsProjectLoader(project, pathVariables, file.getParent()).loadFromIpr(file);
new JpsProjectLoader(project, pathVariables, file.getParent(), loadUnloadedModules).loadFromIpr(file);
}
else {
Path dotIdea = file.resolve(PathMacroUtil.DIRECTORY_STORE_NAME);
@@ -98,7 +107,7 @@ public class JpsProjectLoader extends JpsLoaderBase {
else {
throw new IOException("Cannot find IntelliJ IDEA project files at " + projectPath);
}
new JpsProjectLoader(project, pathVariables, directory.getParent()).loadFromDirectory(directory);
new JpsProjectLoader(project, pathVariables, directory.getParent(), loadUnloadedModules).loadFromDirectory(directory);
}
}
@@ -236,7 +245,7 @@ public class JpsProjectLoader extends JpsLoaderBase {
if (componentRoot == null) return;
Set<String> unloadedModules = new HashSet<>();
if (Files.exists(workspaceFile)) {
if (!myLoadUnloadedModules && Files.exists(workspaceFile)) {
Element unloadedModulesList = JDomSerializationUtil.findComponent(loadRootElement(workspaceFile), "UnloadedModulesList");
for (Element element : JDOMUtil.getChildren(unloadedModulesList, "module")) {
unloadedModules.add(element.getAttributeValue("name"));
@@ -34,7 +34,12 @@ public abstract class JpsSerializationManager {
}
@NotNull
public abstract JpsModel loadModel(@NotNull String projectPath, @Nullable String optionsPath) throws IOException;
public JpsModel loadModel(@NotNull String projectPath, @Nullable String optionsPath) throws IOException {
return loadModel(projectPath, optionsPath, false);
}
@NotNull
public abstract JpsModel loadModel(@NotNull String projectPath, @Nullable String optionsPath, boolean loadUnloadedModules) throws IOException;
@NotNull
public abstract JpsProject loadProject(@NotNull String projectPath, @NotNull Map<String, String> pathVariables) throws IOException;
@@ -32,14 +32,14 @@ import java.util.Map;
public class JpsSerializationManagerImpl extends JpsSerializationManager {
@NotNull
@Override
public JpsModel loadModel(@NotNull String projectPath, @Nullable String optionsPath)
public JpsModel loadModel(@NotNull String projectPath, @Nullable String optionsPath, boolean loadUnloadedModules)
throws IOException {
JpsModel model = JpsElementFactory.getInstance().createModel();
if (optionsPath != null) {
JpsGlobalLoader.loadGlobalSettings(model.getGlobal(), optionsPath);
}
Map<String, String> pathVariables = JpsModelSerializationDataService.computeAllPathVariables(model.getGlobal());
JpsProjectLoader.loadProject(model.getProject(), pathVariables, projectPath);
JpsProjectLoader.loadProject(model.getProject(), pathVariables, projectPath, loadUnloadedModules);
return model;
}
@@ -127,7 +127,7 @@ public class Standalone {
return 1;
}
JpsModelLoaderImpl loader = new JpsModelLoaderImpl(projectPath, globalOptionsPath, initializer);
JpsModelLoaderImpl loader = new JpsModelLoaderImpl(projectPath, globalOptionsPath, false, initializer);
Set<String> modulesSet = new HashSet<>(Arrays.asList(modules));
List<String> artifactsList = Arrays.asList(artifacts);
File dataStorageRoot;
@@ -140,6 +140,13 @@ mesage.text.deployment.descriptor.file.not.exist=Deployment descriptor file ''{0
message.text.deployment.description.invalid.file=Invalid file
warning.text.file.has.been.changed=File has been changed during compilation, inspection validation skipped
dialog.message.compilation.of.unloaded.modules.failed=There are unloaded modules in the project which depend on changed files.<br>\
Compilation of these modules finished with errors.
dialog.title.compilation.failed=Compilation Failed
button.text.checkin.handler.commit=&Commit
button.text.checkin.handler.show.errors=&Show Errors
checkbox.text.compile.affected.unloaded.modules=Compile affected &unloaded modules
#artifacts
dialog.title.output.directory.for.artifact=Output Directory for Artifact
chooser.description.select.output.directory.for.0.artifact=Select output directory for ''{0}'' artifact
@@ -356,6 +356,8 @@
<programRunner id="defaultRunRunner" implementation="com.intellij.execution.impl.DefaultJavaProgramRunner"/>
<programRunner implementation="com.intellij.execution.runners.DefaultRunProgramRunner" order="last"/>
<checkinHandlerFactory implementation="com.intellij.compiler.impl.vcs.UnloadedModulesCompilationCheckinHandler$Factory"/>
<hectorComponentProvider implementation="com.intellij.codeInsight.daemon.impl.ImportPopupHectorComponentProvider"/>