From 4a97c1643b32e24602576de5cf435272d2c91494 Mon Sep 17 00:00:00 2001 From: "Vladislav.Soroka" Date: Tue, 12 Jul 2016 15:52:09 +0300 Subject: [PATCH] external system aware make draft (IDEA-135128, IDEA-131627) --- .../compiler/actions/BuildArtifactAction.java | 29 +- .../compiler/actions/CompileAction.java | 5 +- .../compiler/actions/CompileDirtyAction.java | 4 +- .../actions/CompileProjectAction.java | 16 +- .../compiler/actions/MakeModuleAction.java | 4 +- ...ystemExecutionEnvironmentProviderImpl.java | 53 ++++ .../openapi/build/BuildSystemManagerImpl.java | 152 +++++++++ .../build/DefaultBuildSystemDriver.java | 146 +++++++++ .../openapi/build/ProjectBuildScope.java | 37 +++ .../BuildArtifactsBeforeRunTaskProvider.java | 21 +- .../openapi/build/ArtifactBuildTarget.java | 34 ++ .../intellij/openapi/build/BuildContext.java | 30 ++ .../intellij/openapi/build/BuildScope.java | 30 ++ .../openapi/build/BuildScopeImpl.java | 55 ++++ .../build/BuildStatusNotification.java | 31 ++ .../openapi/build/BuildSystemDriver.java | 54 ++++ .../openapi/build/BuildSystemManager.java | 89 ++++++ .../intellij/openapi/build/BuildTarget.java | 23 ++ .../openapi/build/ModuleBuildTarget.java | 34 ++ .../openapi/build/ModuleFilesBuildTarget.java | 43 +++ .../ExternalSystemExecutionSettings.java | 19 +- .../ExternalSystemRunConfiguration.java | 13 +- .../internal/AbstractExternalSystemTask.java | 3 +- .../ExternalSystemExecuteTaskTask.java | 12 +- .../manage/ExternalSystemTaskActivator.java | 2 +- .../util/ExternalSystemUiUtil.java | 21 +- .../util/ExternalSystemUtil.java | 13 + ...ildSystemExecutionEnvironmentProvider.java | 42 +++ .../runners/ExecutionEnvironmentBuilder.java | 15 +- .../resources/i18n/GradleBundle.properties | 1 + plugins/gradle/src/META-INF/plugin.xml | 2 + .../build/CachedModuleDataFinder.java | 60 ++++ .../GradleApplicationEnvironmentBuilder.java | 126 ++++++++ .../GradleArtifactBuildTasksProvider.java | 39 +++ .../build/GradleBuildSystemDriver.java | 296 ++++++++++++++++++ .../service/task/GradleTaskManager.java | 12 + .../settings/GradleRunnerConfigurable.form | 14 +- .../settings/GradleRunnerConfigurable.java | 38 ++- .../settings/GradleSystemRunningSettings.java | 24 +- resources/src/META-INF/IdeaPlugin.xml | 2 + resources/src/idea/RichPlatformPlugin.xml | 6 + 41 files changed, 1551 insertions(+), 99 deletions(-) create mode 100644 java/compiler/impl/src/com/intellij/openapi/build/BuildSystemExecutionEnvironmentProviderImpl.java create mode 100644 java/compiler/impl/src/com/intellij/openapi/build/BuildSystemManagerImpl.java create mode 100644 java/compiler/impl/src/com/intellij/openapi/build/DefaultBuildSystemDriver.java create mode 100644 java/compiler/impl/src/com/intellij/openapi/build/ProjectBuildScope.java create mode 100644 java/compiler/openapi/src/com/intellij/openapi/build/ArtifactBuildTarget.java create mode 100644 java/compiler/openapi/src/com/intellij/openapi/build/BuildContext.java create mode 100644 java/compiler/openapi/src/com/intellij/openapi/build/BuildScope.java create mode 100644 java/compiler/openapi/src/com/intellij/openapi/build/BuildScopeImpl.java create mode 100644 java/compiler/openapi/src/com/intellij/openapi/build/BuildStatusNotification.java create mode 100644 java/compiler/openapi/src/com/intellij/openapi/build/BuildSystemDriver.java create mode 100644 java/compiler/openapi/src/com/intellij/openapi/build/BuildSystemManager.java create mode 100644 java/compiler/openapi/src/com/intellij/openapi/build/BuildTarget.java create mode 100644 java/compiler/openapi/src/com/intellij/openapi/build/ModuleBuildTarget.java create mode 100644 java/compiler/openapi/src/com/intellij/openapi/build/ModuleFilesBuildTarget.java create mode 100644 platform/lang-api/src/com/intellij/execution/runners/BuildSystemExecutionEnvironmentProvider.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/CachedModuleDataFinder.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/GradleApplicationEnvironmentBuilder.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/GradleArtifactBuildTasksProvider.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/GradleBuildSystemDriver.java diff --git a/java/compiler/impl/src/com/intellij/compiler/actions/BuildArtifactAction.java b/java/compiler/impl/src/com/intellij/compiler/actions/BuildArtifactAction.java index bbfe3832c227..db817a5a7d0c 100644 --- a/java/compiler/impl/src/com/intellij/compiler/actions/BuildArtifactAction.java +++ b/java/compiler/impl/src/com/intellij/compiler/actions/BuildArtifactAction.java @@ -20,8 +20,7 @@ import com.intellij.notification.NotificationType; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonShortcuts; import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.compiler.CompileScope; -import com.intellij.openapi.compiler.CompilerManager; +import com.intellij.openapi.build.BuildSystemManager; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; @@ -42,7 +41,6 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.packaging.artifacts.Artifact; import com.intellij.packaging.impl.artifacts.ArtifactUtil; -import com.intellij.packaging.impl.compiler.ArtifactCompileScope; import com.intellij.packaging.impl.compiler.ArtifactsWorkspaceSettings; import com.intellij.ui.popup.list.ListPopupImpl; import com.intellij.util.containers.ContainerUtil; @@ -90,7 +88,7 @@ public class BuildArtifactAction extends DumbAwareAction { selectedIndices.add(0); selectedArtifacts.clear(); } - + for (Artifact artifact : artifacts) { final ArtifactPopupItem item = new ArtifactPopupItem(artifact, artifact.getName(), artifact.getArtifactType().getIcon()); if (selectedArtifacts.contains(artifact)) { @@ -98,10 +96,10 @@ public class BuildArtifactAction extends DumbAwareAction { } items.add(item); } - + final ProjectSettingsService projectSettingsService = ProjectSettingsService.getInstance(project); final ArtifactAwareProjectSettingsService settingsService = projectSettingsService instanceof ArtifactAwareProjectSettingsService ? (ArtifactAwareProjectSettingsService)projectSettingsService : null; - + final ChooseArtifactStep step = new ChooseArtifactStep(items, artifacts.get(0), project, settingsService); step.setDefaultOptionIndices(selectedIndices.toNativeArray()); @@ -121,20 +119,21 @@ public class BuildArtifactAction extends DumbAwareAction { } private static void doBuild(@NotNull Project project, final @NotNull List items, boolean rebuild) { - final Set artifacts = getArtifacts(items, project); - final CompileScope scope = ArtifactCompileScope.createArtifactsScope(project, artifacts, rebuild); - - ArtifactsWorkspaceSettings.getInstance(project).setArtifactsToBuild(artifacts); - //in external build we can set 'rebuild' flag per target type - CompilerManager.getInstance(project).make(scope, null); + final Artifact[] artifacts = getArtifacts(items, project); + if (rebuild) { + BuildSystemManager.getInstance(project).rebuild(artifacts); + } + else { + BuildSystemManager.getInstance(project).build(artifacts); + } } - private static Set getArtifacts(final List items, final Project project) { + private static Artifact[] getArtifacts(final List items, final Project project) { Set artifacts = new LinkedHashSet<>(); for (ArtifactPopupItem item : items) { artifacts.addAll(item.getArtifacts(project)); } - return artifacts; + return ContainerUtil.toArray(artifacts, new Artifact[artifacts.size()]); } private static class BuildArtifactItem extends ArtifactActionItem { @@ -167,7 +166,7 @@ public class BuildArtifactAction extends DumbAwareAction { Map outputPathContainingSourceRoots = new HashMap<>(); final List> toClean = new ArrayList<>(); - Set artifacts = getArtifacts(myArtifactPopupItems, myProject); + Artifact[] artifacts = getArtifacts(myArtifactPopupItems, myProject); for (Artifact artifact : artifacts) { String outputPath = artifact.getOutputFilePath(); if (outputPath != null) { diff --git a/java/compiler/impl/src/com/intellij/compiler/actions/CompileAction.java b/java/compiler/impl/src/com/intellij/compiler/actions/CompileAction.java index 1f9eff3dae55..a7227b554faa 100644 --- a/java/compiler/impl/src/com/intellij/compiler/actions/CompileAction.java +++ b/java/compiler/impl/src/com/intellij/compiler/actions/CompileAction.java @@ -18,6 +18,7 @@ package com.intellij.compiler.actions; import com.intellij.compiler.CompilerConfiguration; import com.intellij.idea.ActionsBundle; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.build.BuildSystemManager; import com.intellij.openapi.compiler.CompilerBundle; import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.fileTypes.FileType; @@ -37,12 +38,12 @@ public class CompileAction extends CompileActionBase { protected void doAction(DataContext dataContext, Project project) { final Module module = dataContext.getData(LangDataKeys.MODULE_CONTEXT); if (module != null) { - CompilerManager.getInstance(project).compile(module, null); + BuildSystemManager.getInstance(project).rebuild(module); } else { VirtualFile[] files = getCompilableFiles(project, dataContext.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY)); if (files.length > 0) { - CompilerManager.getInstance(project).compile(files, null); + BuildSystemManager.getInstance(project).compile(files); } } diff --git a/java/compiler/impl/src/com/intellij/compiler/actions/CompileDirtyAction.java b/java/compiler/impl/src/com/intellij/compiler/actions/CompileDirtyAction.java index e7c1e6b5c0f1..805497bed503 100644 --- a/java/compiler/impl/src/com/intellij/compiler/actions/CompileDirtyAction.java +++ b/java/compiler/impl/src/com/intellij/compiler/actions/CompileDirtyAction.java @@ -18,13 +18,13 @@ package com.intellij.compiler.actions; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.compiler.CompilerManager; +import com.intellij.openapi.build.BuildSystemManager; import com.intellij.openapi.project.Project; public class CompileDirtyAction extends CompileActionBase { protected void doAction(DataContext dataContext, Project project) { - CompilerManager.getInstance(project).make(null); + BuildSystemManager.getInstance(project).buildProjectDirty(); } public void update(AnActionEvent e){ diff --git a/java/compiler/impl/src/com/intellij/compiler/actions/CompileProjectAction.java b/java/compiler/impl/src/com/intellij/compiler/actions/CompileProjectAction.java index b26b0798f45b..b4a68e509f65 100644 --- a/java/compiler/impl/src/com/intellij/compiler/actions/CompileProjectAction.java +++ b/java/compiler/impl/src/com/intellij/compiler/actions/CompileProjectAction.java @@ -19,24 +19,24 @@ import com.intellij.history.LocalHistory; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.compiler.CompileContext; -import com.intellij.openapi.compiler.CompileStatusNotification; +import com.intellij.openapi.build.BuildContext; +import com.intellij.openapi.build.BuildStatusNotification; +import com.intellij.openapi.build.BuildSystemManager; import com.intellij.openapi.compiler.CompilerBundle; -import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.project.Project; public class CompileProjectAction extends CompileActionBase { protected void doAction(DataContext dataContext, final Project project) { - CompilerManager.getInstance(project).rebuild(new CompileStatusNotification() { - public void finished(boolean aborted, int errors, int warnings, final CompileContext compileContext) { + BuildSystemManager.getInstance(project).rebuildProject(new BuildStatusNotification() { + @Override + public void finished(boolean aborted, int errors, int warnings, BuildContext buildContext) { if (aborted || project.isDisposed()) { return; } String text = getTemplatePresentation().getText(); - LocalHistory.getInstance().putSystemLabel(project, errors == 0 - ? CompilerBundle.message("rebuild.lvcs.label.no.errors", text) - : CompilerBundle.message("rebuild.lvcs.label.with.errors", text)); + LocalHistory.getInstance().putSystemLabel( + project, CompilerBundle.message(errors == 0 ? "rebuild.lvcs.label.no.errors" : "rebuild.lvcs.label.with.errors", text)); } }); } diff --git a/java/compiler/impl/src/com/intellij/compiler/actions/MakeModuleAction.java b/java/compiler/impl/src/com/intellij/compiler/actions/MakeModuleAction.java index 08b85a8c7021..1dd3a8bccd24 100644 --- a/java/compiler/impl/src/com/intellij/compiler/actions/MakeModuleAction.java +++ b/java/compiler/impl/src/com/intellij/compiler/actions/MakeModuleAction.java @@ -16,8 +16,8 @@ package com.intellij.compiler.actions; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.build.BuildSystemManager; import com.intellij.openapi.compiler.CompilerBundle; -import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; @@ -36,7 +36,7 @@ public class MakeModuleAction extends CompileActionBase { modules = new Module[]{module}; } try { - CompilerManager.getInstance(project).make(modules[0].getProject(), modules, null); + BuildSystemManager.getInstance(project).buildDirty(modules); } catch (Exception e) { LOG.error(e); diff --git a/java/compiler/impl/src/com/intellij/openapi/build/BuildSystemExecutionEnvironmentProviderImpl.java b/java/compiler/impl/src/com/intellij/openapi/build/BuildSystemExecutionEnvironmentProviderImpl.java new file mode 100644 index 000000000000..ff19040bb17d --- /dev/null +++ b/java/compiler/impl/src/com/intellij/openapi/build/BuildSystemExecutionEnvironmentProviderImpl.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.build; + +import com.intellij.execution.ExecutionTarget; +import com.intellij.execution.Executor; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.configurations.ConfigurationPerRunnerSettings; +import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.configurations.RunnerSettings; +import com.intellij.execution.runners.BuildSystemExecutionEnvironmentProvider; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Vladislav.Soroka + * @since 5/11/2016 + */ +public class BuildSystemExecutionEnvironmentProviderImpl implements BuildSystemExecutionEnvironmentProvider { + + @Nullable + @Override + public ExecutionEnvironment createExecutionEnvironment(@NotNull RunProfile runProfile, + @NotNull Executor executor, + @NotNull ExecutionTarget target, + @NotNull Project project, + @Nullable RunnerSettings runnerSettings, + @Nullable ConfigurationPerRunnerSettings configurationSettings, + @Nullable RunnerAndConfigurationSettings settings) { + for (BuildSystemDriver buildSystemDriver : BuildSystemDriver.EP_NAME.getExtensions()) { + if (buildSystemDriver.canRun(executor.getId(), runProfile)) { + return buildSystemDriver.createExecutionEnvironment( + runProfile, executor, target, project, runnerSettings, configurationSettings, settings); + } + } + return null; + } +} diff --git a/java/compiler/impl/src/com/intellij/openapi/build/BuildSystemManagerImpl.java b/java/compiler/impl/src/com/intellij/openapi/build/BuildSystemManagerImpl.java new file mode 100644 index 000000000000..606c069215cf --- /dev/null +++ b/java/compiler/impl/src/com/intellij/openapi/build/BuildSystemManagerImpl.java @@ -0,0 +1,152 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.build; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.packaging.artifacts.Artifact; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.intellij.util.containers.ContainerUtil.list; +import static com.intellij.util.containers.ContainerUtil.map; + +/** + * @author Vladislav.Soroka + * @since 5/11/2016 + */ +public class BuildSystemManagerImpl extends BuildSystemManager { + + private final BuildSystemDriver myDefaultBuildSystemDriver = new DefaultBuildSystemDriver(); + + public BuildSystemManagerImpl(@NotNull Project project) { + super(project); + } + + @Override + public void buildDirty(@NotNull Module[] modules, @Nullable BuildStatusNotification callback) { + BuildScope buildScope = new BuildScopeImpl(map(list(modules), ModuleBuildTarget::new)); + doBuild(buildScope, true, callback); + } + + @Override + public void rebuild(@NotNull Module[] modules, @Nullable BuildStatusNotification callback) { + BuildScope buildScope = new BuildScopeImpl(map(list(modules), ModuleBuildTarget::new)); + doBuild(buildScope, false, callback); + } + + @Override + public void compile(@NotNull VirtualFile[] files, @Nullable BuildStatusNotification callback) { + List buildTargets = Arrays.stream(files) + .collect(Collectors.groupingBy(file -> ProjectFileIndex.SERVICE.getInstance(myProject).getModuleForFile(file, false))) + .entrySet().stream() + .map(entry -> new ModuleFilesBuildTarget(entry.getKey(), entry.getValue())) + .collect(Collectors.toList()); + + BuildScope buildScope = new BuildScopeImpl(buildTargets); + doBuild(buildScope, false, callback); + } + + @Override + public void build(@NotNull Artifact[] artifacts, @Nullable BuildStatusNotification callback) { + doBuild(artifacts, callback, true); + } + + @Override + public void rebuild(@NotNull Artifact[] artifacts, @Nullable BuildStatusNotification callback) { + doBuild(artifacts, callback, false); + } + + @Override + public void buildDirty(@NotNull BuildScope scope, @Nullable BuildStatusNotification callback) { + doBuild(scope, true, callback); + } + + @Override + public void rebuild(@NotNull BuildScope scope, @Nullable BuildStatusNotification callback) { + doBuild(scope, false, callback); + } + + @Override + public void buildProjectDirty(@Nullable BuildStatusNotification callback) { + doBuild(new ProjectBuildScope(myProject), true, callback); + } + + @Override + public void rebuildProject(@Nullable BuildStatusNotification callback) { + doBuild(new ProjectBuildScope(myProject), false, callback); + } + + @NotNull + private static BuildSystemDriver[] getBuildDrivers() { + return BuildSystemDriver.EP_NAME.getExtensions(); + } + + private void doBuild(@NotNull Artifact[] artifacts, @Nullable BuildStatusNotification callback, boolean isIncrementalBuild) { + BuildScope buildScope = new BuildScopeImpl(map(list(artifacts), ArtifactBuildTarget::new)); + doBuild(buildScope, isIncrementalBuild, callback); + } + + private void doBuild(@NotNull BuildScope scope, boolean isIncrementalBuild, @Nullable BuildStatusNotification callback) { + Map> toBuild = + scope.getTargets().stream().collect(Collectors.groupingBy(buildTarget -> { + for (BuildSystemDriver driver : getBuildDrivers()) { + if (driver.canBuild(buildTarget)) return driver; + } + return myDefaultBuildSystemDriver; + })); + + for (Map.Entry> entry : toBuild.entrySet()) { + BuildSystemDriver driver = entry.getKey(); + BuildScope buildScope = toBuild.size() == 1 ? scope : new BuildScopeImpl(entry.getValue(), scope.getSessionId()); + driver.build(new BuildContextImpl(myProject, buildScope, isIncrementalBuild), callback); + } + } + + private static class BuildContextImpl implements BuildContext { + private final BuildScope myBuildScope; + private final boolean myIsIncrementalBuild; + private final Project myProject; + + public BuildContextImpl(Project project, BuildScope buildScope, boolean isIncrementalBuild) { + myProject = project; + myBuildScope = buildScope; + myIsIncrementalBuild = isIncrementalBuild; + } + + @Override + public Project getProject() { + return myProject; + } + + @Override + public BuildScope getScope() { + return myBuildScope; + } + + @Override + public boolean isIncrementalBuild() { + return myIsIncrementalBuild; + } + } +} diff --git a/java/compiler/impl/src/com/intellij/openapi/build/DefaultBuildSystemDriver.java b/java/compiler/impl/src/com/intellij/openapi/build/DefaultBuildSystemDriver.java new file mode 100644 index 000000000000..0668209eb61c --- /dev/null +++ b/java/compiler/impl/src/com/intellij/openapi/build/DefaultBuildSystemDriver.java @@ -0,0 +1,146 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.build; + +import com.intellij.compiler.impl.ModuleCompileScope; +import com.intellij.execution.ExecutionTarget; +import com.intellij.execution.Executor; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.configurations.ConfigurationPerRunnerSettings; +import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.configurations.RunnerSettings; +import com.intellij.execution.impl.ExecutionManagerImpl; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.openapi.compiler.CompileScope; +import com.intellij.openapi.compiler.CompileStatusNotification; +import com.intellij.openapi.compiler.CompilerManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.packaging.artifacts.Artifact; +import com.intellij.packaging.impl.compiler.ArtifactCompileScope; +import com.intellij.packaging.impl.compiler.ArtifactsWorkspaceSettings; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @author Vladislav.Soroka + * @since 5/11/2016 + */ +public class DefaultBuildSystemDriver extends BuildSystemDriver { + @Override + public void build(@NotNull BuildContext buildContext, @Nullable BuildStatusNotification callback) { + CompileStatusNotification compileNotification = + callback == null ? null : (aborted, errors, warnings, compileContext) -> callback.finished(aborted, errors, warnings, buildContext); + if (buildContext.getScope() instanceof ProjectBuildScope) { + buildProject(buildContext, compileNotification); + } + else { + Map, List> targetsMap = + buildContext.getScope().getTargets().stream().collect(Collectors.groupingBy(BuildTarget::getClass)); + + buildModulesTargets(buildContext, compileNotification, targetsMap); + buildFilesTargets(buildContext, compileNotification, targetsMap); + buildArtifactsTargets(buildContext, compileNotification, targetsMap); + } + } + + @Override + public boolean canBuild(@NotNull BuildTarget buildTarget) { + return true; + } + + @Override + public boolean canRun(@NotNull String executorId, @NotNull RunProfile runProfile) { + return true; + } + + @Override + public ExecutionEnvironment createExecutionEnvironment(@NotNull RunProfile runProfile, + @NotNull Executor executor, + @NotNull ExecutionTarget executionTarget, + @NotNull Project project, + @Nullable RunnerSettings runnerSettings, + @Nullable ConfigurationPerRunnerSettings configurationSettings, + @Nullable RunnerAndConfigurationSettings settings) { + return null; + } + + private static void buildProject(BuildContext buildContext, CompileStatusNotification callback) { + Project project = buildContext.getProject(); + if (buildContext.isIncrementalBuild()) { + CompilerManager.getInstance(project).make(callback); + } + else { + CompilerManager.getInstance(project).rebuild(callback); + } + } + + private static void buildModulesTargets(@NotNull BuildContext buildContext, + @Nullable CompileStatusNotification compileNotification, + @NotNull Map, List> targetsMap) { + Project project = buildContext.getProject(); + Collection buildTargets = targetsMap.get(ModuleBuildTarget.class); + if (!ContainerUtil.isEmpty(buildTargets)) { + Module[] modules = ContainerUtil.map2Array(buildTargets, Module.class, target -> ModuleBuildTarget.class.cast(target).getModule()); + if (buildContext.isIncrementalBuild()) { + CompilerManager.getInstance(project).make(project, modules, compileNotification); + } + else { + ModuleCompileScope compileScope = new ModuleCompileScope(project, modules, true); + ExecutionManagerImpl.EXECUTION_SESSION_ID_KEY.set(compileScope, buildContext.getScope().getSessionId()); + CompilerManager.getInstance(project).compile(compileScope, compileNotification); + } + } + } + + private static void buildFilesTargets(@NotNull BuildContext buildContext, + @Nullable CompileStatusNotification compileNotification, + @NotNull Map, List> targetsMap) { + Collection filesTargets = targetsMap.get(ModuleFilesBuildTarget.class); + if (!ContainerUtil.isEmpty(filesTargets)) { + VirtualFile[] files = filesTargets.stream() + .flatMap(target -> Stream.of(ModuleFilesBuildTarget.class.cast(target).getFiles())) + .toArray(VirtualFile[]::new); + CompilerManager.getInstance(buildContext.getProject()).compile(files, compileNotification); + } + } + + private static void buildArtifactsTargets(@NotNull BuildContext buildContext, + @Nullable CompileStatusNotification compileNotification, + @NotNull Map, List> targetsMap) { + Collection artifactsTargets = targetsMap.get(ArtifactBuildTarget.class); + if (!ContainerUtil.isEmpty(artifactsTargets)) { + Project project = buildContext.getProject(); + Collection artifacts = artifactsTargets.stream() + .map(target -> ArtifactBuildTarget.class.cast(target).getArtifact()) + .collect(Collectors.toList()); + + final CompileScope scope = ArtifactCompileScope.createArtifactsScope(project, artifacts, !buildContext.isIncrementalBuild()); + ArtifactsWorkspaceSettings.getInstance(project).setArtifactsToBuild(artifacts); + ExecutionManagerImpl.EXECUTION_SESSION_ID_KEY.set(scope, buildContext.getScope().getSessionId()); + //in external build we can set 'rebuild' flag per target type + CompilerManager.getInstance(project).make(scope, compileNotification); + } + } +} diff --git a/java/compiler/impl/src/com/intellij/openapi/build/ProjectBuildScope.java b/java/compiler/impl/src/com/intellij/openapi/build/ProjectBuildScope.java new file mode 100644 index 000000000000..133ffd94276f --- /dev/null +++ b/java/compiler/impl/src/com/intellij/openapi/build/ProjectBuildScope.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.build; + +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.project.Project; +import com.intellij.util.containers.ContainerUtil; + +/** + * @author Vladislav.Soroka + * @since 7/6/2016 + */ +public class ProjectBuildScope extends BuildScopeImpl { + private final Project myProject; + + public ProjectBuildScope(final Project project) { + super(ContainerUtil.map(ModuleManager.getInstance(project).getModules(), ModuleBuildTarget::new)); + myProject = project; + } + + public Project getProject() { + return myProject; + } +} diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java b/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java index 3ecb3db2a550..4113a2fbb8a7 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java @@ -29,14 +29,14 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.Result; -import com.intellij.openapi.compiler.*; +import com.intellij.openapi.build.*; +import com.intellij.openapi.compiler.CompilerBundle; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Ref; import com.intellij.packaging.artifacts.*; -import com.intellij.packaging.impl.compiler.ArtifactCompileScope; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.JBUI; @@ -175,9 +175,13 @@ public class BuildArtifactsBeforeRunTaskProvider extends BeforeRunTaskProvider artifactBuildTargets = ContainerUtil.map(artifacts, ArtifactBuildTarget::new); + Object sessionId = ExecutionManagerImpl.EXECUTION_SESSION_ID_KEY.get(env); finished.down(); - manager.make(scope, CompilerFilter.ALL, callback); + BuildSystemManager.getInstance(myProject).buildDirty(new BuildScopeImpl(artifactBuildTargets, sessionId), callback); }, ModalityState.NON_MODAL); finished.waitFor(); diff --git a/java/compiler/openapi/src/com/intellij/openapi/build/ArtifactBuildTarget.java b/java/compiler/openapi/src/com/intellij/openapi/build/ArtifactBuildTarget.java new file mode 100644 index 000000000000..be35ee75c562 --- /dev/null +++ b/java/compiler/openapi/src/com/intellij/openapi/build/ArtifactBuildTarget.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.build; + +import com.intellij.packaging.artifacts.Artifact; + +/** + * @author Vladislav.Soroka + * @since 5/14/2016 + */ +public class ArtifactBuildTarget implements BuildTarget { + private final Artifact myArtifact; + + public ArtifactBuildTarget(Artifact artifact) { + myArtifact = artifact; + } + + public Artifact getArtifact() { + return myArtifact; + } +} diff --git a/java/compiler/openapi/src/com/intellij/openapi/build/BuildContext.java b/java/compiler/openapi/src/com/intellij/openapi/build/BuildContext.java new file mode 100644 index 000000000000..9a2ef203017d --- /dev/null +++ b/java/compiler/openapi/src/com/intellij/openapi/build/BuildContext.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.build; + +import com.intellij.openapi.project.Project; + +/** + * @author Vladislav.Soroka + * @since 4/29/2016 + */ +public interface BuildContext { + Project getProject(); + + BuildScope getScope(); + + boolean isIncrementalBuild(); +} diff --git a/java/compiler/openapi/src/com/intellij/openapi/build/BuildScope.java b/java/compiler/openapi/src/com/intellij/openapi/build/BuildScope.java new file mode 100644 index 000000000000..b18c8ddb0d49 --- /dev/null +++ b/java/compiler/openapi/src/com/intellij/openapi/build/BuildScope.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.build; + +import java.util.Collection; + +/** + * @author Vladislav.Soroka + * @since 4/29/2016 + */ +public interface BuildScope { + Collection getTargets(); + + void setSessionId(Object sessionId); + + Object getSessionId(); +} diff --git a/java/compiler/openapi/src/com/intellij/openapi/build/BuildScopeImpl.java b/java/compiler/openapi/src/com/intellij/openapi/build/BuildScopeImpl.java new file mode 100644 index 000000000000..bf505b6c806a --- /dev/null +++ b/java/compiler/openapi/src/com/intellij/openapi/build/BuildScopeImpl.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.build; + +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +/** + * @author Vladislav.Soroka + * @since 5/11/2016 + */ +public class BuildScopeImpl implements BuildScope { + private final Collection myTargets; + @Nullable + private Object mySessionId; + + public BuildScopeImpl(Collection targets) { + myTargets = targets; + } + + public BuildScopeImpl(Collection targets, @Nullable Object sessionId) { + myTargets = targets; + mySessionId = sessionId; + } + + @Override + public Collection getTargets() { + return myTargets; + } + + @Override + public void setSessionId(@Nullable Object sessionId) { + mySessionId = sessionId; + } + + @Nullable + @Override + public Object getSessionId() { + return mySessionId; + } +} diff --git a/java/compiler/openapi/src/com/intellij/openapi/build/BuildStatusNotification.java b/java/compiler/openapi/src/com/intellij/openapi/build/BuildStatusNotification.java new file mode 100644 index 000000000000..f8546145b402 --- /dev/null +++ b/java/compiler/openapi/src/com/intellij/openapi/build/BuildStatusNotification.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.build; + +/** + * @author Vladislav.Soroka + * @since 4/29/2016 + */ +public interface BuildStatusNotification { + /** + * + * @param aborted true if the build has been cancelled. + * @param errors error count + * @param warnings warning count + * @param buildContext context for the build + */ + void finished(boolean aborted, int errors, int warnings, final BuildContext buildContext); +} diff --git a/java/compiler/openapi/src/com/intellij/openapi/build/BuildSystemDriver.java b/java/compiler/openapi/src/com/intellij/openapi/build/BuildSystemDriver.java new file mode 100644 index 000000000000..d3299e7f66d2 --- /dev/null +++ b/java/compiler/openapi/src/com/intellij/openapi/build/BuildSystemDriver.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.build; + +import com.intellij.execution.ExecutionTarget; +import com.intellij.execution.Executor; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.configurations.ConfigurationPerRunnerSettings; +import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.configurations.RunnerSettings; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * TODO + * get compiled files status + * + * @author Vladislav.Soroka + * @since 4/29/2016 + */ +public abstract class BuildSystemDriver { + + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.buildSystemDriver"); + + public abstract void build(@NotNull BuildContext buildContext, @Nullable BuildStatusNotification callback); + + public abstract boolean canBuild(@NotNull BuildTarget buildTarget); + + public abstract boolean canRun(@NotNull String executorId, @NotNull RunProfile runProfile); + + public abstract ExecutionEnvironment createExecutionEnvironment(@NotNull RunProfile runProfile, + @NotNull Executor executor, + @NotNull ExecutionTarget executionTarget, + @NotNull Project project, + @Nullable RunnerSettings runnerSettings, + @Nullable ConfigurationPerRunnerSettings configurationSettings, + @Nullable RunnerAndConfigurationSettings settings); +} diff --git a/java/compiler/openapi/src/com/intellij/openapi/build/BuildSystemManager.java b/java/compiler/openapi/src/com/intellij/openapi/build/BuildSystemManager.java new file mode 100644 index 000000000000..02a8bccbc7c6 --- /dev/null +++ b/java/compiler/openapi/src/com/intellij/openapi/build/BuildSystemManager.java @@ -0,0 +1,89 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.build; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.packaging.artifacts.Artifact; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Provides services to build project, modules, files or artifacts. + *

+ * + * @author Vladislav.Soroka + * @since 4/29/2016 + */ +public abstract class BuildSystemManager { + protected final @NotNull Project myProject; + + public BuildSystemManager(@NotNull Project project) { + myProject = project; + } + + public static BuildSystemManager getInstance(Project project) { + return ServiceManager.getService(project, BuildSystemManager.class); + } + + public abstract void buildProjectDirty(@Nullable BuildStatusNotification callback); + + public void buildProjectDirty() { + buildProjectDirty(null); + } + + public abstract void rebuildProject(@Nullable BuildStatusNotification callback); + + public void rebuildProject() { + rebuildProject(null); + } + + public abstract void buildDirty(@NotNull Module[] modules, @Nullable BuildStatusNotification callback); + + public void buildDirty(@NotNull Module... modules) { + buildDirty(modules, null); + } + + public abstract void rebuild(@NotNull Module[] modules, @Nullable BuildStatusNotification callback); + + public void rebuild(@NotNull Module... modules) { + rebuild(modules, null); + } + + public abstract void compile(@NotNull VirtualFile[] files, @Nullable BuildStatusNotification callback); + + public void compile(@NotNull VirtualFile... files) { + compile(files, null); + } + + public abstract void build(@NotNull Artifact[] artifacts, @Nullable BuildStatusNotification callback); + + public void build(@NotNull Artifact[] artifacts) { + build(artifacts, null); + } + + public abstract void rebuild(@NotNull Artifact[] artifacts, @Nullable BuildStatusNotification callback); + + public void rebuild(@NotNull Artifact... artifacts) { + rebuild(artifacts, null); + } + + public abstract void buildDirty(@NotNull BuildScope scope, @Nullable BuildStatusNotification callback); + + public abstract void rebuild(@NotNull BuildScope scope, @Nullable BuildStatusNotification callback); +} diff --git a/java/compiler/openapi/src/com/intellij/openapi/build/BuildTarget.java b/java/compiler/openapi/src/com/intellij/openapi/build/BuildTarget.java new file mode 100644 index 000000000000..a0314129c46a --- /dev/null +++ b/java/compiler/openapi/src/com/intellij/openapi/build/BuildTarget.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.build; + +/** + * @author Vladislav.Soroka + * @since 5/11/2016 + */ +public interface BuildTarget { +} diff --git a/java/compiler/openapi/src/com/intellij/openapi/build/ModuleBuildTarget.java b/java/compiler/openapi/src/com/intellij/openapi/build/ModuleBuildTarget.java new file mode 100644 index 000000000000..5226d40485cd --- /dev/null +++ b/java/compiler/openapi/src/com/intellij/openapi/build/ModuleBuildTarget.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.build; + +import com.intellij.openapi.module.Module; + +/** + * @author Vladislav.Soroka + * @since 5/11/2016 + */ +public class ModuleBuildTarget implements BuildTarget { + private final Module myModule; + + public ModuleBuildTarget(Module module) { + myModule = module; + } + + public Module getModule() { + return myModule; + } +} diff --git a/java/compiler/openapi/src/com/intellij/openapi/build/ModuleFilesBuildTarget.java b/java/compiler/openapi/src/com/intellij/openapi/build/ModuleFilesBuildTarget.java new file mode 100644 index 000000000000..7a60d4d036fe --- /dev/null +++ b/java/compiler/openapi/src/com/intellij/openapi/build/ModuleFilesBuildTarget.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.build; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ArrayUtil; + +import java.util.Collection; + +/** + * @author Vladislav.Soroka + * @since 5/14/2016 + */ +public class ModuleFilesBuildTarget extends ModuleBuildTarget { + private final VirtualFile[] myFiles; + + public ModuleFilesBuildTarget(Module module, VirtualFile[] files) { + super(module); + myFiles = files; + } + + public ModuleFilesBuildTarget(Module module, Collection files) { + this(module, ArrayUtil.toObjectArray(files, VirtualFile.class)); + } + + public VirtualFile[] getFiles() { + return myFiles; + } +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/settings/ExternalSystemExecutionSettings.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/settings/ExternalSystemExecutionSettings.java index a568c3bdf187..fb073b6a4025 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/settings/ExternalSystemExecutionSettings.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/settings/ExternalSystemExecutionSettings.java @@ -1,8 +1,12 @@ package com.intellij.openapi.externalSystem.model.settings; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.UserDataHolder; +import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.util.SystemProperties; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.Serializable; import java.util.concurrent.atomic.AtomicBoolean; @@ -23,7 +27,7 @@ import java.util.concurrent.atomic.AtomicReference; * @author Denis Zhdanov * @since 8/9/11 12:12 PM */ -public class ExternalSystemExecutionSettings implements Serializable { +public class ExternalSystemExecutionSettings implements Serializable, UserDataHolder { public static final String REMOTE_PROCESS_IDLE_TTL_IN_MS_KEY = "external.system.remote.process.idle.ttl.ms"; private static final int DEFAULT_REMOTE_PROCESS_TTL_MS = 60000; @@ -36,6 +40,8 @@ public class ExternalSystemExecutionSettings implements Serializable { @NotNull private final AtomicReference myNotificationListener = new AtomicReference<>(); + @NotNull private transient UserDataHolderBase myUserData = new UserDataHolderBase(); + public ExternalSystemExecutionSettings() { int ttl = SystemProperties.getIntProperty(REMOTE_PROCESS_IDLE_TTL_IN_MS_KEY, DEFAULT_REMOTE_PROCESS_TTL_MS); setRemoteProcessIdleTtlInMs(ttl); @@ -60,6 +66,17 @@ public class ExternalSystemExecutionSettings implements Serializable { myVerboseProcessing.set(verboseProcessing); } + @Nullable + @Override + public U getUserData(@NotNull Key key) { + return myUserData.getUserData(key); + } + + @Override + public void putUserData(@NotNull Key key, U value) { + myUserData.putUserData(key, value); + } + @Override public int hashCode() { int result = (int)(myRemoteProcessIdleTtlInMs.get() ^ (myRemoteProcessIdleTtlInMs.get() >>> 32)); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java index e5da09761d8b..d90e6560e4ad 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java @@ -27,10 +27,7 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.options.SettingsEditorGroup; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.InvalidDataException; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.util.*; import com.intellij.util.ExceptionUtil; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.net.NetUtils; @@ -106,10 +103,13 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase { @Nullable @Override public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException { - return new MyRunnableState(mySettings, getProject(), DefaultDebugExecutor.EXECUTOR_ID.equals(executor.getId()), this, env); + MyRunnableState runnableState = + new MyRunnableState(mySettings, getProject(), DefaultDebugExecutor.EXECUTOR_ID.equals(executor.getId()), this, env); + copyUserDataTo(runnableState); + return runnableState; } - public static class MyRunnableState implements RunProfileState { + public static class MyRunnableState extends UserDataHolderBase implements RunProfileState { @NotNull private final ExternalSystemTaskExecutionSettings mySettings; @NotNull private final Project myProject; @@ -173,6 +173,7 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase { mySettings.getVmOptions(), mySettings.getScriptParameters(), debuggerSetup); + copyUserDataTo(task); final MyProcessHandler processHandler = new MyProcessHandler(task); final ExternalSystemExecutionConsoleManager diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/AbstractExternalSystemTask.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/AbstractExternalSystemTask.java index 1d820106c9d3..8bf30368ac95 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/AbstractExternalSystemTask.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/AbstractExternalSystemTask.java @@ -11,6 +11,7 @@ import com.intellij.openapi.externalSystem.service.notification.*; import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; @@ -24,7 +25,7 @@ import java.util.concurrent.atomic.AtomicReference; * @author Denis Zhdanov * @since 1/24/12 7:03 AM */ -public abstract class AbstractExternalSystemTask implements ExternalSystemTask { +public abstract class AbstractExternalSystemTask extends UserDataHolderBase implements ExternalSystemTask { private static final Logger LOG = Logger.getInstance("#" + AbstractExternalSystemTask.class.getName()); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemExecuteTaskTask.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemExecuteTaskTask.java index abcc32fa7391..83d9ff945fbd 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemExecuteTaskTask.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemExecuteTaskTask.java @@ -25,10 +25,11 @@ import com.intellij.openapi.externalSystem.service.RemoteExternalSystemFacade; import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemTaskManager; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.project.Project; -import com.intellij.util.Function; +import com.intellij.openapi.util.Key; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.execution.ParametersListUtil; +import com.intellij.util.keyFMap.KeyFMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,8 +42,6 @@ import java.util.List; */ public class ExternalSystemExecuteTaskTask extends AbstractExternalSystemTask { - @NotNull private static final Function MAPPER = task -> task.getName(); - @NotNull private final List myTasksToExecute; @Nullable private final String myVmOptions; @Nullable private String myScriptParameters; @@ -112,9 +111,14 @@ public class ExternalSystemExecuteTaskTask extends AbstractExternalSystemTask { ExternalSystemExecutionSettings settings = ExternalSystemApiUtil.getExecutionSettings(getIdeProject(), getExternalProjectPath(), getExternalSystemId()); + KeyFMap keyFMap = getUserMap(); + for (Key key : keyFMap.getKeys()) { + settings.putUserData(key, keyFMap.get(key)); + } + RemoteExternalSystemFacade facade = manager.getFacade(getIdeProject(), getExternalProjectPath(), getExternalSystemId()); RemoteExternalSystemTaskManager taskManager = facade.getTaskManager(); - List taskNames = ContainerUtilRt.map2List(myTasksToExecute, MAPPER); + List taskNames = ContainerUtilRt.map2List(myTasksToExecute, ExternalTaskPojo::getName); final List vmOptions = parseCmdParameters(myVmOptions); final List scriptParametersList = parseCmdParameters(myScriptParameters); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemTaskActivator.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemTaskActivator.java index 92965f708253..0951ea401d58 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemTaskActivator.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemTaskActivator.java @@ -233,7 +233,7 @@ public class ExternalSystemTaskActivator { targetDone.up(); } }, - ProgressExecutionMode.IN_BACKGROUND_ASYNC); + ProgressExecutionMode.IN_BACKGROUND_ASYNC, false); targetDone.waitFor(); return result.get(); } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUiUtil.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUiUtil.java index 3a4cf7146e2d..e24fa408fb85 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUiUtil.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUiUtil.java @@ -21,33 +21,20 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.externalSystem.ExternalSystemManager; import com.intellij.openapi.externalSystem.ExternalSystemUiAware; import com.intellij.openapi.externalSystem.model.ProjectSystemId; -import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo; -import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo; -import com.intellij.openapi.externalSystem.service.task.ui.ExternalSystemTasksTreeModel; import com.intellij.openapi.externalSystem.service.ui.DefaultExternalSystemUiAware; -import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.ui.popup.BalloonBuilder; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.ui.awt.RelativePoint; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.ui.GridBag; -import com.intellij.util.ui.UIUtil; -import gnu.trove.THashMap; +import com.intellij.util.ui.JBUI; import org.jetbrains.annotations.NotNull; import javax.swing.*; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.MutableTreeNode; -import javax.swing.tree.TreeNode; import java.awt.*; import java.awt.event.InputEvent; import java.lang.reflect.Field; -import java.util.*; -import java.util.List; /** * @author Denis Zhdanov @@ -55,7 +42,7 @@ import java.util.List; */ public class ExternalSystemUiUtil { - public static final int INSETS = 7; + public static final int INSETS = 5; private static final int BALLOON_FADEOUT_TIME = 5000; private ExternalSystemUiUtil() { @@ -91,13 +78,13 @@ public class ExternalSystemUiUtil { @NotNull public static GridBag getLabelConstraints(int indentLevel) { - Insets insets = new Insets(INSETS, INSETS + INSETS * indentLevel, 0, INSETS); + Insets insets = JBUI.insets(INSETS, INSETS + INSETS * indentLevel, 0, INSETS); return new GridBag().anchor(GridBagConstraints.WEST).weightx(0).insets(insets); } @NotNull public static GridBag getFillLineConstraints(int indentLevel) { - Insets insets = new Insets(INSETS, INSETS + INSETS * indentLevel, 0, INSETS); + Insets insets = JBUI.insets(INSETS, INSETS + INSETS * indentLevel, 0, INSETS); return new GridBag().weightx(1).coverLine().fillCellHorizontally().anchor(GridBagConstraints.WEST).insets(insets); } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java index bbb356a4a521..db19a71f6a9f 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java @@ -520,11 +520,24 @@ public class ExternalSystemUtil { @NotNull final ProjectSystemId externalSystemId, @Nullable final TaskCallback callback, @NotNull final ProgressExecutionMode progressExecutionMode) { + runTask(taskSettings, executorId, project, externalSystemId, callback, progressExecutionMode, true); + } + + public static void runTask(@NotNull final ExternalSystemTaskExecutionSettings taskSettings, + @NotNull final String executorId, + @NotNull final Project project, + @NotNull final ProjectSystemId externalSystemId, + @Nullable final TaskCallback callback, + @NotNull final ProgressExecutionMode progressExecutionMode, + boolean activateToolWindowBeforeRun) { final Pair pair = createRunner(taskSettings, executorId, project, externalSystemId); if (pair == null) return; final ProgramRunner runner = pair.first; final ExecutionEnvironment environment = pair.second; + RunnerAndConfigurationSettings runnerAndConfigurationSettings = environment.getRunnerAndConfigurationSettings(); + assert runnerAndConfigurationSettings != null; + runnerAndConfigurationSettings.setActivateToolWindowBeforeRun(activateToolWindowBeforeRun); final TaskUnderProgress task = new TaskUnderProgress() { @Override diff --git a/platform/lang-api/src/com/intellij/execution/runners/BuildSystemExecutionEnvironmentProvider.java b/platform/lang-api/src/com/intellij/execution/runners/BuildSystemExecutionEnvironmentProvider.java new file mode 100644 index 000000000000..44dbd7e95959 --- /dev/null +++ b/platform/lang-api/src/com/intellij/execution/runners/BuildSystemExecutionEnvironmentProvider.java @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2016 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.execution.runners; + +import com.intellij.execution.ExecutionTarget; +import com.intellij.execution.Executor; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.configurations.ConfigurationPerRunnerSettings; +import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.configurations.RunnerSettings; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Vladislav.Soroka + * @since 6/2/2016 + */ +public interface BuildSystemExecutionEnvironmentProvider { + + @Nullable + ExecutionEnvironment createExecutionEnvironment(@NotNull RunProfile runProfile, + @NotNull Executor executor, + @NotNull ExecutionTarget target, + @NotNull Project project, + @Nullable RunnerSettings runnerSettings, + @Nullable ConfigurationPerRunnerSettings configurationSettings, + @Nullable RunnerAndConfigurationSettings settings); +} diff --git a/platform/lang-api/src/com/intellij/execution/runners/ExecutionEnvironmentBuilder.java b/platform/lang-api/src/com/intellij/execution/runners/ExecutionEnvironmentBuilder.java index 551658f79708..1717abc396b0 100644 --- a/platform/lang-api/src/com/intellij/execution/runners/ExecutionEnvironmentBuilder.java +++ b/platform/lang-api/src/com/intellij/execution/runners/ExecutionEnvironmentBuilder.java @@ -22,6 +22,7 @@ import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.configurations.RunnerSettings; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.UserDataHolderBase; import org.jetbrains.annotations.NotNull; @@ -165,7 +166,10 @@ public final class ExecutionEnvironmentBuilder { @NotNull public ExecutionEnvironment build() { - if (myRunner == null) { + ExecutionEnvironment environment = ServiceManager.getService(myProject, BuildSystemExecutionEnvironmentProvider.class).createExecutionEnvironment( + myRunProfile, myExecutor, myTarget, myProject, myRunnerSettings, myConfigurationSettings, myRunnerAndConfigurationSettings); + + if (environment == null && myRunner == null) { if (myRunnerId == null) { myRunner = RunnerRegistry.getInstance().getRunner(myExecutor.getId(), myRunProfile); } @@ -174,12 +178,15 @@ public final class ExecutionEnvironmentBuilder { } } - if (myRunner == null) { + if (environment == null && myRunner == null) { throw new IllegalStateException("Runner must be specified"); } - ExecutionEnvironment environment = new ExecutionEnvironment(myRunProfile, myExecutor, myTarget, myProject, myRunnerSettings, myConfigurationSettings, myContentToReuse, - myRunnerAndConfigurationSettings, myRunner); + if (environment == null) { + environment = new ExecutionEnvironment(myRunProfile, myExecutor, myTarget, myProject, myRunnerSettings, + myConfigurationSettings, myContentToReuse, myRunnerAndConfigurationSettings, myRunner); + } + if (myAssignNewId) { environment.assignNewExecutionId(); } diff --git a/plugins/gradle/resources/i18n/GradleBundle.properties b/plugins/gradle/resources/i18n/GradleBundle.properties index c086eef4199d..8ecfed645180 100644 --- a/plugins/gradle/resources/i18n/GradleBundle.properties +++ b/plugins/gradle/resources/i18n/GradleBundle.properties @@ -7,6 +7,7 @@ gradle.settings.text.wrapper.customization.compatibility=Gradle wrapper customiz gradle.settings.text.use.local.distribution=Use local gradle distribution gradle.settings.text.use.bundled.distribution=Use bundled gradle distribution: ({0}) gradle.settings.text.create.module.per.sourceset=Create separate module per source set +gradle.settings.text.use.gradle.aware.make=Delegate IDE build/run actions to gradle gradle.settings.text.home.path=Gradle home: gradle.settings.text.jvm.path=Gradle JVM: diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index 0cf2e69aaf86..71f65f1ffba7 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -53,6 +53,7 @@ + @@ -77,6 +78,7 @@ + diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/CachedModuleDataFinder.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/CachedModuleDataFinder.java new file mode 100644 index 000000000000..caa74f52f8b5 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/CachedModuleDataFinder.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2016 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 org.jetbrains.plugins.gradle.execution.build; + +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.ProjectKeys; +import com.intellij.openapi.externalSystem.model.project.ModuleData; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.BooleanFunction; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData; + +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 5/14/2016 + */ +public class CachedModuleDataFinder { + private Map> cache = ContainerUtil.newHashMap(); + + @Nullable + public DataNode findModuleData(final DataNode parentNode, final String projectPath) { + DataNode node = cache.get(projectPath); + if (node != null) return node; + + //noinspection unchecked + return (DataNode)ExternalSystemApiUtil.findFirstRecursively(parentNode, new BooleanFunction>() { + @Override + public boolean fun(DataNode node) { + if ((ProjectKeys.MODULE.equals(node.getKey()) || + GradleSourceSetData.KEY.equals(node.getKey())) && node.getData() instanceof ModuleData) { + String externalProjectPath = ((ModuleData)node.getData()).getLinkedExternalProjectPath(); + //noinspection unchecked + DataNode myNode = (DataNode)node; + cache.put(externalProjectPath, myNode); + + return StringUtil.equals(projectPath, ((ModuleData)node.getData()).getLinkedExternalProjectPath()); + } + + return false; + } + }); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/GradleApplicationEnvironmentBuilder.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/GradleApplicationEnvironmentBuilder.java new file mode 100644 index 000000000000..d30392eae8a0 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/GradleApplicationEnvironmentBuilder.java @@ -0,0 +1,126 @@ +/* + * Copyright 2000-2016 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 org.jetbrains.plugins.gradle.execution.build; + +import com.intellij.execution.ExecutionTarget; +import com.intellij.execution.Executor; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.application.ApplicationConfiguration; +import com.intellij.execution.configurations.ConfigurationPerRunnerSettings; +import com.intellij.execution.configurations.JavaParameters; +import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.configurations.RunnerSettings; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.runners.ProgramRunner; +import com.intellij.execution.util.JavaParametersUtil; +import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings; +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiClass; +import org.intellij.lang.annotations.Language; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.service.task.GradleTaskManager; +import org.jetbrains.plugins.gradle.util.GradleConstants; + +import java.util.Collections; + +/** + * TODO take into account applied 'application' gradle plugins or existing JavaExec tasks + * + * @author Vladislav.Soroka + * @since 6/21/2016 + */ +public class GradleApplicationEnvironmentBuilder { + + @Nullable + public ExecutionEnvironment build(@NotNull RunProfile runProfile, + @NotNull Executor executor, + @NotNull ExecutionTarget executionTarget, + @NotNull Project project, + @Nullable RunnerSettings runnerSettings, + @Nullable ConfigurationPerRunnerSettings configurationSettings, + @Nullable RunnerAndConfigurationSettings settings) { + ApplicationConfiguration applicationConfiguration = (ApplicationConfiguration)runProfile; + PsiClass mainClass = applicationConfiguration.getMainClass(); + if(mainClass == null) return null; + + Module module = ProjectFileIndex.SERVICE.getInstance(project).getModuleForFile(mainClass.getContainingFile().getVirtualFile()); + String externalProjectPath = ExternalSystemApiUtil.getExternalProjectPath(module); + String projectId = ExternalSystemApiUtil.getExternalProjectId(module); + if (projectId == null || !projectId.startsWith(":")) { + projectId = ":"; + } else { + if(!projectId.equals(":")) { + projectId = projectId.substring(0, projectId.lastIndexOf(':')); + } + } + + final JavaParameters params = new JavaParameters(); + JavaParametersUtil.configureConfiguration(params, applicationConfiguration); + params.getVMParametersList().addParametersString(applicationConfiguration.getVMParameters()); + + StringBuilder parametersString = new StringBuilder(); + for (String parameter : params.getProgramParametersList().getParameters()) { + parametersString.append("args '").append(parameter).append("'\n"); + } + + StringBuilder vmParametersString = new StringBuilder(); + for (String parameter : params.getVMParametersList().getParameters()) { + vmParametersString.append("jvmArgs '").append(parameter).append("'\n"); + } + + + ExternalSystemTaskExecutionSettings taskSettings = new ExternalSystemTaskExecutionSettings(); + taskSettings.setExternalSystemIdString(GradleConstants.SYSTEM_ID.getId()); + taskSettings.setExternalProjectPath(externalProjectPath); + final String runAppTaskName = "run " + mainClass.getName(); + taskSettings.setTaskNames(Collections.singletonList(runAppTaskName)); + + final Pair environmentPair = + ExternalSystemUtil.createRunner(taskSettings, executor.getId(), project, GradleConstants.SYSTEM_ID); + if (environmentPair != null) { + RunnerAndConfigurationSettings runnerAndConfigurationSettings = environmentPair.second.getRunnerAndConfigurationSettings(); + assert runnerAndConfigurationSettings != null; + ExternalSystemRunConfiguration runConfiguration = (ExternalSystemRunConfiguration)runnerAndConfigurationSettings.getConfiguration(); + + @Language("Groovy") + String initScript = "projectsEvaluated {\n" + + " rootProject.allprojects {\n" + + " if(project.path == '" + projectId + "' && project.sourceSets) {\n" + + " project.tasks.create(name: '" + runAppTaskName + "', overwrite: true, type: JavaExec) {\n" + + " classpath = project.sourceSets.main.runtimeClasspath\n" + + " main = '" + mainClass.getQualifiedName() + "'\n" + + parametersString.toString() + + vmParametersString.toString() + + " }\n" + + " }\n" + + " }\n" + + "}\n"; + + runConfiguration.putUserData(GradleTaskManager.INIT_SCRIPT_KEY, initScript); + return environmentPair.second; + } + else { + return null; + } + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/GradleArtifactBuildTasksProvider.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/GradleArtifactBuildTasksProvider.java new file mode 100644 index 000000000000..a4b2bad5fbe0 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/GradleArtifactBuildTasksProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2016 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 org.jetbrains.plugins.gradle.execution.build; + +import com.intellij.openapi.build.BuildContext; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo; +import com.intellij.packaging.artifacts.Artifact; +import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; + +/** + * @author Vladislav.Soroka + * @since 7/11/2016 + */ +public interface GradleArtifactBuildTasksProvider { + ExtensionPointName EP_NAME = + ExtensionPointName.create("org.jetbrains.plugins.gradle.artifactBuildTasksProvider"); + + boolean isApplicable(@NotNull Artifact artifact); + + void addArtifactsTargetsBuildTasks(@NotNull BuildContext buildContext, + @NotNull Consumer cleanTasksConsumer, + @NotNull Consumer buildTasksConsumer, + @NotNull Artifact artifact); +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/GradleBuildSystemDriver.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/GradleBuildSystemDriver.java new file mode 100644 index 000000000000..a3a4a8d48d8e --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/GradleBuildSystemDriver.java @@ -0,0 +1,296 @@ +/* + * Copyright 2000-2016 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 org.jetbrains.plugins.gradle.execution.build; + +import com.intellij.execution.ExecutionTarget; +import com.intellij.execution.Executor; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.application.ApplicationConfiguration; +import com.intellij.execution.configurations.ConfigurationPerRunnerSettings; +import com.intellij.execution.configurations.JavaRunConfigurationModule; +import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.configurations.RunnerSettings; +import com.intellij.execution.executors.DefaultRunExecutor; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.openapi.build.*; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.ExternalProjectInfo; +import com.intellij.openapi.externalSystem.model.ProjectKeys; +import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings; +import com.intellij.openapi.externalSystem.model.project.ModuleData; +import com.intellij.openapi.externalSystem.model.project.ProjectData; +import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.task.TaskCallback; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.packaging.artifacts.Artifact; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.settings.GradleProjectSettings; +import org.jetbrains.plugins.gradle.settings.GradleSettings; +import org.jetbrains.plugins.gradle.settings.GradleSystemRunningSettings; +import org.jetbrains.plugins.gradle.util.GradleConstants; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * TODO automatically create exploded-war task + * task explodedWar(type: Copy) { + * into "$buildDir/explodedWar" + * with war + * } + * + * @author Vladislav.Soroka + * @since 5/11/2016 + */ +public class GradleBuildSystemDriver extends BuildSystemDriver { + @Override + public void build(@NotNull BuildContext buildContext, @Nullable BuildStatusNotification buildCallback) { + String executionName = null; + if (buildContext.getScope() instanceof ProjectBuildScope) { + executionName = buildContext.isIncrementalBuild() ? "Make" : "Rebuild"; + } + + MultiMap buildTasksMap = MultiMap.createLinkedSet(); + MultiMap cleanTasksMap = MultiMap.createLinkedSet(); + + Map, List> targetsMap = + buildContext.getScope().getTargets().stream().collect(Collectors.groupingBy(BuildTarget::getClass)); + addModulesTargetsBuildTasks(buildContext, targetsMap, cleanTasksMap, buildTasksMap); + addFilesTargetsBuildTasks(buildContext, targetsMap, cleanTasksMap, buildTasksMap); + addArtifactsTargetsBuildTasks(buildContext, targetsMap, cleanTasksMap, buildTasksMap); + // TODO send a message if nothing to build + Set rootPaths = buildTasksMap.keySet(); + + AtomicInteger successCounter = new AtomicInteger(); + AtomicInteger errorCounter = new AtomicInteger(); + + TaskCallback taskCallback = buildCallback == null ? null : new TaskCallback() { + @Override + public void onSuccess() { + handle(true); + } + + @Override + public void onFailure() { + handle(false); + } + + private void handle(boolean success) { + int successes = success ? successCounter.incrementAndGet() : successCounter.get(); + int errors = success ? errorCounter.get() : errorCounter.incrementAndGet(); + if (successes + errors == rootPaths.size()) { + buildCallback.finished(false, errors, 0, buildContext); + } + } + }; + + String gradleVmOptions = GradleSettings.getInstance(buildContext.getProject()).getGradleVmOptions(); + for (String rootProjectPath : rootPaths) { + Collection buildTasks = buildTasksMap.get(rootProjectPath); + if (buildTasks.isEmpty()) continue; + Collection cleanTasks = cleanTasksMap.get(rootProjectPath); + + ExternalSystemTaskExecutionSettings settings = new ExternalSystemTaskExecutionSettings(); + settings.setExecutionName(executionName); + settings.setExternalProjectPath(rootProjectPath); + settings.setTaskNames(ContainerUtil.collect(ContainerUtil.concat(cleanTasks, buildTasks).iterator())); + //settings.setScriptParameters(scriptParameters); + settings.setVmOptions(gradleVmOptions); + settings.setExternalSystemIdString(GradleConstants.SYSTEM_ID.getId()); + ExternalSystemUtil.runTask(settings, DefaultRunExecutor.EXECUTOR_ID, buildContext.getProject(), GradleConstants.SYSTEM_ID, + taskCallback, ProgressExecutionMode.IN_BACKGROUND_ASYNC, false); + } + } + + @Override + public boolean canBuild(@NotNull BuildTarget buildTarget) { + if (!GradleSystemRunningSettings.getInstance().isUseGradleAwareMake()) return false; + if (buildTarget instanceof ModuleBuildTarget) { + return ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, ((ModuleBuildTarget)buildTarget).getModule()); + } + if (buildTarget instanceof ArtifactBuildTarget) { + Artifact artifact = ((ArtifactBuildTarget)buildTarget).getArtifact(); + for (GradleArtifactBuildTasksProvider buildTasksProvider : GradleArtifactBuildTasksProvider.EP_NAME.getExtensions()) { + if (buildTasksProvider.isApplicable(artifact)) return true; + } + } + return false; + } + + @Override + public boolean canRun(@NotNull String executorId, @NotNull RunProfile runProfile) { + if (!GradleSystemRunningSettings.getInstance().isUseGradleAwareMake()) return false; + if (runProfile instanceof ApplicationConfiguration) { + JavaRunConfigurationModule module = ((ApplicationConfiguration)runProfile).getConfigurationModule(); + return ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module.getModule()); + } + return false; + } + + @Override + public ExecutionEnvironment createExecutionEnvironment(@NotNull RunProfile runProfile, + @NotNull Executor executor, + @NotNull ExecutionTarget executionTarget, + @NotNull Project project, + @Nullable RunnerSettings runnerSettings, + @Nullable ConfigurationPerRunnerSettings configurationSettings, + @Nullable RunnerAndConfigurationSettings settings) { + if (runProfile instanceof ApplicationConfiguration) { + return new GradleApplicationEnvironmentBuilder().build( + runProfile, executor, executionTarget, project, runnerSettings, configurationSettings, settings); + } + return null; + } + + private static void addModulesTargetsBuildTasks(@NotNull BuildContext buildContext, + @NotNull Map, List> targetsMap, + @NotNull MultiMap cleanTasksMap, + @NotNull MultiMap buildTasksMap) { + Collection buildTargets = targetsMap.get(ModuleBuildTarget.class); + if (!ContainerUtil.isEmpty(buildTargets)) { + Module[] modules = ContainerUtil.map2Array(buildTargets, Module.class, target -> ModuleBuildTarget.class.cast(target).getModule()); + addModulesTargetsBuildTasks(buildContext, modules, cleanTasksMap, buildTasksMap); + } + } + + private static void addFilesTargetsBuildTasks(BuildContext buildContext, + Map, List> targetsMap, + MultiMap cleanTasksMap, MultiMap buildTasksMap) { + Collection buildTargets = targetsMap.get(ModuleFilesBuildTarget.class); + if (!ContainerUtil.isEmpty(buildTargets)) { + // TODO there should be 'gradle' way to build files instead of the whole related modules + Module[] modules = + ContainerUtil.map2Array(buildTargets, Module.class, target -> ModuleFilesBuildTarget.class.cast(target).getModule()); + addModulesTargetsBuildTasks(buildContext, modules, cleanTasksMap, buildTasksMap); + } + } + + private static void addModulesTargetsBuildTasks(@NotNull BuildContext buildContext, + @NotNull Module[] modules, + @NotNull MultiMap cleanTasksMap, + @NotNull MultiMap buildTasksMap) { + + final CachedModuleDataFinder moduleDataFinder = new CachedModuleDataFinder(); + for (Module module : modules) { + final String rootProjectPath = ExternalSystemApiUtil.getExternalRootProjectPath(module); + if (rootProjectPath == null) continue; + + final String projectId = ExternalSystemApiUtil.getExternalProjectId(module); + if (projectId == null) continue; + final String externalProjectPath = ExternalSystemApiUtil.getExternalProjectPath(module); + if (externalProjectPath == null || StringUtil.endsWith(externalProjectPath, "buildSrc")) continue; + + ExternalProjectInfo projectData = + ProjectDataManager.getInstance().getExternalProjectData(module.getProject(), GradleConstants.SYSTEM_ID, rootProjectPath); + if (projectData == null) continue; + + DataNode projectStructure = projectData.getExternalProjectStructure(); + if (projectStructure == null) continue; + + final DataNode moduleDataNode = moduleDataFinder.findModuleData(projectStructure, externalProjectPath); + if (moduleDataNode == null) continue; + + + List tasks = ContainerUtil.mapNotNull(ExternalSystemApiUtil.findAll(moduleDataNode, ProjectKeys.TASK), + node -> node.getData().isInherited() ? null : node.getData().getName()); + + Collection cleanTasks = cleanTasksMap.getModifiable(rootProjectPath); + Collection buildTasks = buildTasksMap.getModifiable(rootProjectPath); + final String moduleType = ExternalSystemApiUtil.getExternalModuleType(module); + final String gradlePath; + + if (GradleConstants.GRADLE_SOURCE_SET_MODULE_TYPE_KEY.equals(moduleType)) { + int lastColonIndex = projectId.lastIndexOf(':'); + assert lastColonIndex != -1; + int firstColonIndex = projectId.indexOf(':'); + + gradlePath = projectId.substring(firstColonIndex, lastColonIndex); + String sourceSetName = projectId.substring(lastColonIndex + 1); + String task = "main".equals(sourceSetName) ? "classes" : sourceSetName + "Classes"; + if (tasks.contains(task)) { + if (!buildContext.isIncrementalBuild()) { + cleanTasks.add(gradlePath + ":clean" + StringUtil.capitalize(task)); + } + buildTasks.add(gradlePath + ":" + task); + } + else if ("main".equals(sourceSetName) || "test".equals(sourceSetName)) { + if (!buildContext.isIncrementalBuild()) { + cleanTasks.add(gradlePath + ":clean"); + } + buildTasks.add(gradlePath + ":build"); + } + } + else { + GradleProjectSettings projectSettings = + GradleSettings.getInstance(buildContext.getProject()).getLinkedProjectSettings(rootProjectPath); + boolean sourceSetAwareMode = projectSettings != null && projectSettings.isResolveModulePerSourceSet(); + if (!sourceSetAwareMode) { + gradlePath = projectId.charAt(0) == ':' ? projectId : ""; + if (!buildContext.isIncrementalBuild()) { + if (tasks.contains("classes")) { + cleanTasks.add((StringUtil.equals(rootProjectPath, externalProjectPath) ? ":cleanClasses" : gradlePath + ":cleanClasses")); + } + else { + cleanTasks.add((StringUtil.equals(rootProjectPath, externalProjectPath) ? "clean" : gradlePath + ":clean")); + } + } + if (tasks.contains("classes")) { + buildTasks.add((StringUtil.equals(rootProjectPath, externalProjectPath) ? ":classes" : gradlePath + ":classes")); + } + else { + buildTasks.add((StringUtil.equals(rootProjectPath, externalProjectPath) ? "build" : gradlePath + ":build")); + } + } + } + } + } + + private static void addArtifactsTargetsBuildTasks(BuildContext buildContext, + Map, List> targetsMap, + MultiMap cleanTasksMap, MultiMap buildTasksMap) { + + Collection buildTargets = targetsMap.get(ArtifactBuildTarget.class); + if (!ContainerUtil.isEmpty(buildTargets)) { + Artifact[] artifacts = + ContainerUtil.map2Array(buildTargets, Artifact.class, target -> ArtifactBuildTarget.class.cast(target).getArtifact()); + + for (Artifact artifact : artifacts) { + for (GradleArtifactBuildTasksProvider buildTasksProvider : GradleArtifactBuildTasksProvider.EP_NAME.getExtensions()) { + if (buildTasksProvider.isApplicable(artifact)) { + buildTasksProvider.addArtifactsTargetsBuildTasks( + buildContext, + task -> cleanTasksMap.putValue(task.getLinkedExternalProjectPath(), task.getName()), + task -> buildTasksMap.putValue(task.getLinkedExternalProjectPath(), task.getName()), + artifact + ); + } + } + } + } + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java index b35c80917398..7e15d616fbbe 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java @@ -23,6 +23,7 @@ import com.intellij.openapi.externalSystem.model.task.event.ExternalSystemTaskEx import com.intellij.openapi.externalSystem.task.AbstractExternalSystemTaskManager; import com.intellij.openapi.externalSystem.task.ExternalSystemTaskManager; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; @@ -54,6 +55,8 @@ import java.util.Map; public class GradleTaskManager extends AbstractExternalSystemTaskManager implements ExternalSystemTaskManager { + public static final Key INIT_SCRIPT_KEY = Key.create("INIT_SCRIPT_KEY"); + private final GradleExecutionHelper myHelper = new GradleExecutionHelper(); private final Map myCancellationMap = ContainerUtil.newConcurrentMap(); @@ -100,6 +103,15 @@ public class GradleTaskManager extends AbstractExternalSystemTaskManager

- + @@ -10,23 +10,29 @@ - + - + - + + + + + + + diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleRunnerConfigurable.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleRunnerConfigurable.java index 4b29bd1d304f..15c89cbecd90 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleRunnerConfigurable.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleRunnerConfigurable.java @@ -17,11 +17,9 @@ package org.jetbrains.plugins.gradle.settings; import com.intellij.openapi.options.BaseConfigurable; import com.intellij.openapi.options.ConfigurationException; -import com.intellij.openapi.options.SearchableConfigurable; -import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComboBox; +import com.intellij.ui.components.JBCheckBox; import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.util.GradleBundle; @@ -32,22 +30,16 @@ import java.util.Objects; * @author Vladislav.Soroka * @since 11/2/2015 */ -public class GradleRunnerConfigurable extends BaseConfigurable implements SearchableConfigurable { +public class GradleRunnerConfigurable extends BaseConfigurable { private JPanel myMainPanel; + private JBCheckBox myGradleAwareMakeCheckBox; private ComboBox myPreferredTestRunner; private static final TestRunnerItem[] TEST_RUNNER_ITEMS = new TestRunnerItem[]{ new TestRunnerItem(GradleSystemRunningSettings.PreferredTestRunner.PLATFORM_TEST_RUNNER), new TestRunnerItem(GradleSystemRunningSettings.PreferredTestRunner.GRADLE_TEST_RUNNER), new TestRunnerItem(GradleSystemRunningSettings.PreferredTestRunner.CHOOSE_PER_TEST)}; - - private final Project myProject; - - public GradleRunnerConfigurable(Project project) { - myProject = project; - } - @Nls @Override public String getDisplayName() { @@ -62,15 +54,19 @@ public class GradleRunnerConfigurable extends BaseConfigurable implements Search @Override public void apply() throws ConfigurationException { - GradleSystemRunningSettings.getInstance().setPreferredTestRunner( - ((TestRunnerItem)myPreferredTestRunner.getSelectedItem()).value); + boolean gradleMakeEnabled = myGradleAwareMakeCheckBox.isSelected(); + GradleSystemRunningSettings settings = GradleSystemRunningSettings.getInstance(); + settings.setUseGradleAwareMake(gradleMakeEnabled); + settings.setPreferredTestRunner(((TestRunnerItem)myPreferredTestRunner.getSelectedItem()).value); } @Override public void reset() { GradleSystemRunningSettings settings = GradleSystemRunningSettings.getInstance(); - final TestRunnerItem item = getItem(settings.getPreferredTestRunner()); + final TestRunnerItem item = getItem(settings.getLastPreferredTestRunner()); myPreferredTestRunner.setSelectedItem(item); + boolean gradleMakeEnabled = settings.isUseGradleAwareMake(); + enableGradleMake(gradleMakeEnabled); } @Nullable @@ -86,6 +82,7 @@ public class GradleRunnerConfigurable extends BaseConfigurable implements Search GradleSystemRunningSettings.PreferredTestRunner preferredTestRunner = selectedItem == null ? GradleSystemRunningSettings.PreferredTestRunner.CHOOSE_PER_TEST : selectedItem.value; uiSettings.setPreferredTestRunner(preferredTestRunner); + uiSettings.setUseGradleAwareMake(myGradleAwareMakeCheckBox.isSelected()); GradleSystemRunningSettings settings = GradleSystemRunningSettings.getInstance(); return !settings.equals(uiSettings); } @@ -94,14 +91,15 @@ public class GradleRunnerConfigurable extends BaseConfigurable implements Search public void disposeUIResources() { } - @NotNull - @Override - public String getId() { - return "reference.settings.project.gradle.running"; + private void createUIComponents() { + myGradleAwareMakeCheckBox = new JBCheckBox(GradleBundle.message("gradle.settings.text.use.gradle.aware.make")); + myGradleAwareMakeCheckBox.addActionListener(e -> enableGradleMake(myGradleAwareMakeCheckBox.isSelected())); + myPreferredTestRunner = new ComboBox(getItems()); } - private void createUIComponents() { - myPreferredTestRunner = new ComboBox(getItems()); + private void enableGradleMake(boolean enable) { + myGradleAwareMakeCheckBox.setSelected(enable); + myPreferredTestRunner.setEnabled(!enable); } private static TestRunnerItem getItem(GradleSystemRunningSettings.PreferredTestRunner preferredTestRunner) { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSystemRunningSettings.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSystemRunningSettings.java index d1acdf650ddd..ecc38b78780f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSystemRunningSettings.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSystemRunningSettings.java @@ -31,6 +31,7 @@ import java.util.Objects; @State(name = "GradleSystemRunningSettings", storages = @Storage("gradle.run.settings.xml")) public class GradleSystemRunningSettings implements PersistentStateComponent { + private boolean myUseGradleAwareMake; @NotNull private PreferredTestRunner myPreferredTestRunner = PreferredTestRunner.PLATFORM_TEST_RUNNER; @NotNull @@ -43,17 +44,24 @@ public class GradleSystemRunningSettings implements PersistentStateComponent + + diff --git a/resources/src/idea/RichPlatformPlugin.xml b/resources/src/idea/RichPlatformPlugin.xml index 9026a94e5a43..efbf76042d90 100644 --- a/resources/src/idea/RichPlatformPlugin.xml +++ b/resources/src/idea/RichPlatformPlugin.xml @@ -172,6 +172,12 @@ + + + +