diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/execution/ExternalSystemExecutionConsoleManager.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/execution/ExternalSystemExecutionConsoleManager.java index 6ab3679a6f98..b9f78c8c62d6 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/execution/ExternalSystemExecutionConsoleManager.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/execution/ExternalSystemExecutionConsoleManager.java @@ -21,6 +21,7 @@ import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.ui.ExecutionConsole; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTask; @@ -50,4 +51,6 @@ public interface ExternalSystemExecutionConsoleManager myTaskNames = ContainerUtilRt.newArrayList(); private List myTaskDescriptions = ContainerUtilRt.newArrayList(); + @Nullable private String myExecutionName; private String myExternalSystemIdString; private String myExternalProjectPath; private String myVmOptions; private String myScriptParameters; + @Nullable + public String getExecutionName() { + return myExecutionName; + } + + public void setExecutionName(@Nullable String executionName) { + myExecutionName = executionName; + } + public String getExternalSystemIdString() { return myExternalSystemIdString; } @@ -99,6 +110,7 @@ public class ExternalSystemTaskExecutionSettings implements Cloneable { @Override public ExternalSystemTaskExecutionSettings clone() { ExternalSystemTaskExecutionSettings result = new ExternalSystemTaskExecutionSettings(); + result.setExecutionName(getExecutionName()); result.setExternalSystemIdString(getExternalSystemIdString()); result.setExternalProjectPath(getExternalProjectPath()); result.setVmOptions(getVmOptions()); @@ -111,6 +123,7 @@ public class ExternalSystemTaskExecutionSettings implements Cloneable { @Override public int hashCode() { int result = myTaskNames != null ? myTaskNames.hashCode() : 0; + result = 31 * result + (myExecutionName != null ? myExecutionName.hashCode() : 0); result = 31 * result + (myExternalSystemIdString != null ? myExternalSystemIdString.hashCode() : 0); result = 31 * result + (myExternalProjectPath != null ? myExternalProjectPath.hashCode() : 0); result = 31 * result + (myVmOptions != null ? myVmOptions.hashCode() : 0); @@ -125,6 +138,10 @@ public class ExternalSystemTaskExecutionSettings implements Cloneable { ExternalSystemTaskExecutionSettings settings = (ExternalSystemTaskExecutionSettings)o; + if (myExecutionName != null ? !myExecutionName.equals(settings.myExecutionName) : settings.myExecutionName != null) { + return false; + } + if (myExternalProjectPath != null ? !myExternalProjectPath.equals(settings.myExternalProjectPath) : settings.myExternalProjectPath != null) diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskNotificationListener.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskNotificationListener.java index 4eff1de35e7e..cf74790621d8 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskNotificationListener.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskNotificationListener.java @@ -48,6 +48,14 @@ public interface ExternalSystemTaskNotificationListener { */ void onTaskOutput(@NotNull ExternalSystemTaskId id, @NotNull String text, boolean stdOut); + ///** + // * Notifies about stdin during the task execution + // * + // * @param id id of the task being executed + // * @param text text produced by external system during the target task execution + // */ + //void onTaskInput(@NotNull ExternalSystemTaskId id, @NotNull String text); + /** * Notifies that task with the given id is finished. * diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/task/TaskCallback.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/task/TaskCallback.java new file mode 100644 index 000000000000..ce6a11324e6f --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/task/TaskCallback.java @@ -0,0 +1,26 @@ +/* + * Copyright 2000-2014 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.externalSystem.task; + +/** + * @author Vladislav.Soroka + * @since 6/19/2014 + */ +public interface TaskCallback { + void onSuccess(); + + void onFailure(); +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/task/TaskCallbackAdapter.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/task/TaskCallbackAdapter.java new file mode 100644 index 000000000000..250af07934d0 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/task/TaskCallbackAdapter.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 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.externalSystem.task; + +/** + * @author Vladislav.Soroka + * @since 6/19/2014 + */ +public class TaskCallbackAdapter implements TaskCallback { + @Override + public void onSuccess() {} + + @Override + public void onFailure() {} +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java index eda9ad99da16..8d0c9790f3e1 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java @@ -33,6 +33,7 @@ import com.intellij.openapi.externalSystem.service.ParametersEnhancer; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.roots.OrderRootType; @@ -49,10 +50,10 @@ import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.containers.TransferToEDTQueue; import com.intellij.util.lang.UrlClassLoader; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; @@ -665,4 +666,14 @@ public class ExternalSystemApiUtil { //noinspection unchecked return (T)loader.loadClass(clazz.getName()).newInstance(); } + + @Contract("_, null -> false") + public static boolean isExternalSystemAwareModule(@NotNull ProjectSystemId systemId, @Nullable Module module) { + return module != null && systemId.getId().equals(module.getOptionValue(ExternalSystemConstants.EXTERNAL_SYSTEM_ID_KEY)); + } + + @Nullable + public static String getExternalProjectPath(@Nullable Module module) { + return module != null ? module.getOptionValue(ExternalSystemConstants.LINKED_PROJECT_PATH_KEY) : null; + } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/AbstractExternalSystemTaskConfigurationType.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/AbstractExternalSystemTaskConfigurationType.java index 1345d495921b..3eb1dd6f4420 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/AbstractExternalSystemTaskConfigurationType.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/AbstractExternalSystemTaskConfigurationType.java @@ -109,7 +109,9 @@ public abstract class AbstractExternalSystemTaskConfigurationType implements Con @NotNull public static String generateName(@NotNull Project project, @NotNull ExternalSystemTaskExecutionSettings settings) { - return generateName(project, settings.getExternalSystemId(), settings.getExternalProjectPath(), settings.getTaskNames()); + return generateName( + project, settings.getExternalSystemId(), settings.getExternalProjectPath(), settings.getTaskNames(), settings.getExecutionName() + ); } @NotNull @@ -121,8 +123,16 @@ public abstract class AbstractExternalSystemTaskConfigurationType implements Con public static String generateName(@NotNull Project project, @NotNull ProjectSystemId externalSystemId, @Nullable String externalProjectPath, - @NotNull List taskNames) - { + @NotNull List taskNames) { + return generateName(project, externalSystemId, externalProjectPath, taskNames, null); + } + + @NotNull + public static String generateName(@NotNull Project project, + @NotNull ProjectSystemId externalSystemId, + @Nullable String externalProjectPath, + @NotNull List taskNames, + @Nullable String executionName) { ExternalSystemManager manager = ExternalSystemApiUtil.getManager(externalSystemId); assert manager != null; AbstractExternalSystemSettings s = manager.getSettingsProvider().fun(project); @@ -168,12 +178,16 @@ public abstract class AbstractExternalSystemTaskConfigurationType implements Con } buffer.append("["); - if (!taskNames.isEmpty()) { + if (!StringUtil.isEmpty(executionName)) { + buffer.append(executionName); + } + else if (!taskNames.isEmpty()) { for (String taskName : taskNames) { buffer.append(taskName).append(" "); } buffer.setLength(buffer.length() - 1); } + buffer.append("]"); return buffer.toString(); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/DefaultExternalSystemExecutionConsoleManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/DefaultExternalSystemExecutionConsoleManager.java index b2a6bfd99b68..87b68e90bd69 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/DefaultExternalSystemExecutionConsoleManager.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/DefaultExternalSystemExecutionConsoleManager.java @@ -22,6 +22,7 @@ import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ExecutionConsole; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.externalSystem.execution.ExternalSystemExecutionConsoleManager; import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTask; @@ -67,4 +68,9 @@ public class DefaultExternalSystemExecutionConsoleManager implements ExternalSys public boolean isApplicableFor(@NotNull ExternalSystemTask task) { return true; } + + @Override + public AnAction[] getRestartActions() { + return new AnAction[0]; + } } 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 4c27ae11a446..8b68dcc1ab03 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 @@ -43,8 +43,7 @@ import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.IOException; -import java.io.OutputStream; +import java.io.*; import java.util.List; /** @@ -236,12 +235,15 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase { }); } }); - return new DefaultExecutionResult(consoleView, processHandler); + DefaultExecutionResult result = new DefaultExecutionResult(consoleView, processHandler); + result.setRestartActions(consoleManager.getRestartActions()); + return result; } } private static class MyProcessHandler extends ProcessHandler { private final ExternalSystemExecuteTaskTask myTask; + @Nullable private volatile OutputStream myOutputStream; public MyProcessHandler(ExternalSystemExecuteTaskTask task) { myTask = task; diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemTasksTree.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemTasksTree.java index 12828629a616..76c94b061bfb 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemTasksTree.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemTasksTree.java @@ -208,6 +208,8 @@ public class ExternalSystemTasksTree extends Tree implements Producer pair = createRunner(taskSettings, executorId, project, externalSystemId); if (pair == null) return; - try { - pair.first.execute(pair.second, callback); - } - catch (ExecutionException e) { - LOG.warn("Can't execute task " + taskSettings, e); - } + final ProgramRunner runner = pair.first; + final ExecutionEnvironment environment = pair.second; + + final TaskUnderProgress task = new TaskUnderProgress() { + @Override + public void execute(@NotNull ProgressIndicator indicator) { + final Semaphore targetDone = new Semaphore(); + final Ref result = new Ref(false); + final Disposable disposable = Disposer.newDisposable(); + + project.getMessageBus().connect(disposable).subscribe(ExecutionManager.EXECUTION_TOPIC, new ExecutionAdapter() { + public void processStartScheduled(final String executorIdLocal, final ExecutionEnvironment environmentLocal) { + if (executorId.equals(executorIdLocal) && environment.equals(environmentLocal)) { + targetDone.down(); + } + } + + public void processNotStarted(final String executorIdLocal, @NotNull final ExecutionEnvironment environmentLocal) { + if (executorId.equals(executorIdLocal) && environment.equals(environmentLocal)) { + targetDone.up(); + } + } + + public void processStarted(final String executorIdLocal, + @NotNull final ExecutionEnvironment environmentLocal, + @NotNull final ProcessHandler handler) { + if (executorId.equals(executorIdLocal) && environment.equals(environmentLocal)) { + handler.addProcessListener(new ProcessAdapter() { + public void processTerminated(ProcessEvent event) { + result.set(event.getExitCode() == 0); + targetDone.up(); + } + }); + } + } + }); + + try { + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + @Override + public void run() { + try { + runner.execute(environment); + } + catch (ExecutionException e) { + targetDone.up(); + LOG.error(e); + } + } + }, ModalityState.NON_MODAL); + } + catch (Exception e) { + LOG.error(e); + Disposer.dispose(disposable); + return; + } + + targetDone.waitFor(); + Disposer.dispose(disposable); + + if (callback != null) { + if (result.get()) { + callback.onSuccess(); + } + else { + callback.onFailure(); + } + } + } + }; + + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + final String title = AbstractExternalSystemTaskConfigurationType.generateName(project, taskSettings); + switch (progressExecutionMode) { + case MODAL_SYNC: + new Task.Modal(project, title, true) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + task.execute(indicator); + } + }.queue(); + break; + case IN_BACKGROUND_ASYNC: + new Task.Backgroundable(project, title) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + task.execute(indicator); + } + }.queue(); + break; + case START_IN_FOREGROUND_ASYNC: + new Task.Backgroundable(project, title, true, PerformInBackgroundOption.DEAF) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + task.execute(indicator); + } + }.queue(); + } + } + }); } @Nullable @@ -579,7 +684,11 @@ public class ExternalSystemUtil { RunnerAndConfigurationSettings settings = RunManager.getInstance(project).createRunConfiguration(name, configurationType.getFactory()); ExternalSystemRunConfiguration runConfiguration = (ExternalSystemRunConfiguration)settings.getConfiguration(); runConfiguration.getSettings().setExternalProjectPath(taskSettings.getExternalProjectPath()); - runConfiguration.getSettings().setTaskNames(taskSettings.getTaskNames()); + runConfiguration.getSettings().setTaskNames(ContainerUtil.newArrayList(taskSettings.getTaskNames())); + runConfiguration.getSettings().setTaskDescriptions(ContainerUtil.newArrayList(taskSettings.getTaskDescriptions())); + runConfiguration.getSettings().setVmOptions(taskSettings.getVmOptions()); + runConfiguration.getSettings().setScriptParameters(taskSettings.getScriptParameters()); + runConfiguration.getSettings().setExecutionName(taskSettings.getExecutionName()); return Pair.create(runner, new ExecutionEnvironment(executor, runner, settings, project)); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleManager.java index b011f2d90016..9e28016c60ad 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleManager.java @@ -30,9 +30,7 @@ import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecution import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo; import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo; import com.intellij.openapi.externalSystem.model.project.ProjectData; -import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType; import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode; -import com.intellij.openapi.externalSystem.service.internal.ExternalSystemProcessingManager; import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback; import com.intellij.openapi.externalSystem.service.project.ExternalSystemProjectResolver; import com.intellij.openapi.externalSystem.service.project.autoimport.CachingExternalSystemAutoImportAware; @@ -53,6 +51,8 @@ import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Function; +import com.intellij.util.PathUtil; +import com.intellij.util.PathsList; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.messages.MessageBusConnection; import icons.GradleIcons; @@ -74,11 +74,7 @@ import javax.swing.*; import java.io.File; import java.io.IOException; import java.net.URL; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.locks.ReentrantLock; +import java.util.*; /** * @author Denis Zhdanov @@ -198,9 +194,20 @@ public class GradleManager @Override public void enhanceRemoteProcessing(@NotNull SimpleJavaParameters parameters) throws ExecutionException { + final Set additionalEntries = ContainerUtilRt.newHashSet(); for (GradleProjectResolverExtension extension : RESOLVER_EXTENSIONS.getValue()) { + ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(extension.getClass())); + for (Class aClass : extension.getExtraProjectModelClasses()) { + ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(aClass)); + } extension.enhanceRemoteProcessing(parameters); } + + final PathsList classPath = parameters.getClassPath(); + for (String entry : additionalEntries) { + classPath.add(entry); + } + parameters.getVMParametersList().addProperty( ExternalSystemConstants.EXTERNAL_SYSTEM_ID_KEY, GradleConstants.SYSTEM_ID.getId()); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java index 126f0db8a15b..05771091bebf 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java @@ -79,7 +79,7 @@ public class GradleScriptType extends GroovyRunnableScriptType { private static final Pattern MAIN_CLASS_NAME_PATTERN = Pattern.compile("\nSTARTER_MAIN_CLASS=(.*)\n"); - public static final GroovyScriptType INSTANCE = new GradleScriptType(); + public static final GradleScriptType INSTANCE = new GradleScriptType(); private GradleScriptType() { super(GradleConstants.EXTENSION); @@ -264,7 +264,7 @@ public class GradleScriptType extends GroovyRunnableScriptType { if (scriptPath == null) { throw new CantRunException("Target script is undefined"); } - params.getProgramParametersList().add("--build-file"); + params.getProgramParametersList().add("--project-dir"); params.getProgramParametersList().add(FileUtil.toSystemDependentName(scriptPath)); params.getProgramParametersList().addParametersString(configuration.getProgramParameters()); params.getProgramParametersList().addParametersString(scriptParameters); @@ -273,7 +273,7 @@ public class GradleScriptType extends GroovyRunnableScriptType { } @NotNull - private static String findMainClass(VirtualFile gradleHome, VirtualFile script, Project project) { + private static String findMainClass(VirtualFile gradleHome, @Nullable VirtualFile script, Project project) { final String userDefined = System.getProperty("gradle.launcher.class"); if (StringUtil.isNotEmpty(userDefined)) { return userDefined; @@ -298,9 +298,12 @@ public class GradleScriptType extends GroovyRunnableScriptType { } } - final PsiFile grFile = PsiManager.getInstance(project).findFile(script); - if (grFile != null && JavaPsiFacade.getInstance(project).findClass("org.gradle.BootstrapMain", grFile.getResolveScope()) != null) { - return "org.gradle.BootstrapMain"; + final PsiFile grFile; + if (script != null) { + grFile = PsiManager.getInstance(project).findFile(script); + if (grFile != null && JavaPsiFacade.getInstance(project).findClass("org.gradle.BootstrapMain", grFile.getResolveScope()) != null) { + return "org.gradle.BootstrapMain"; + } } return "org.gradle.launcher.GradleMain"; diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/GradleTestsExecutionConsoleManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/GradleTestsExecutionConsoleManager.java index 77e6333ba019..4fd22407f7f8 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/GradleTestsExecutionConsoleManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/GradleTestsExecutionConsoleManager.java @@ -27,6 +27,7 @@ import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView; import com.intellij.execution.testframework.sm.runner.ui.TestTreeRenderer; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.execution.ui.ExecutionConsole; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.externalSystem.execution.ExternalSystemExecutionConsoleManager; import com.intellij.openapi.externalSystem.model.ProjectSystemId; @@ -193,4 +194,9 @@ public class GradleTestsExecutionConsoleManager implements ExternalSystemExecuti } return false; } + + @Override + public AnAction[] getRestartActions() { + return new AnAction[0]; + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/AbstractProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/AbstractProjectResolverExtension.java index 946b00b1f126..1d8addd31369 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/AbstractProjectResolverExtension.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/AbstractProjectResolverExtension.java @@ -26,6 +26,7 @@ import com.intellij.openapi.externalSystem.model.task.TaskData; import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; import com.intellij.openapi.externalSystem.util.Order; import com.intellij.openapi.util.KeyValue; +import com.intellij.util.Consumer; import org.gradle.tooling.model.idea.IdeaModule; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -54,7 +55,7 @@ public abstract class AbstractProjectResolverExtension implements GradleProjectR } @Override - public void setNext(@Nullable GradleProjectResolverExtension next) { + public void setNext(@NotNull GradleProjectResolverExtension next) { // there always should be at least gradle basic resolver further in the chain //noinspection ConstantConditions assert next != null; @@ -131,6 +132,12 @@ public abstract class AbstractProjectResolverExtension implements GradleProjectR return Collections.emptySet(); } + @NotNull + @Override + public Set getToolingExtensionsClasses() { + return Collections.emptySet(); + } + @NotNull @Override public List> getExtraJvmArgs() { @@ -162,4 +169,10 @@ public abstract class AbstractProjectResolverExtension implements GradleProjectR @Override public void preImportCheck() { } + + @Override + public void enhanceTaskProcessing(@NotNull List taskNames, + @Nullable String debuggerSetup, + @NotNull Consumer initScriptConsumer) { + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java index 8873f25c4157..6f43559f7a11 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java @@ -37,10 +37,7 @@ import com.intellij.openapi.util.KeyValue; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; -import com.intellij.util.BooleanFunction; -import com.intellij.util.Function; -import com.intellij.util.PathUtil; -import com.intellij.util.PathsList; +import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.net.HttpConfigurable; @@ -59,6 +56,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.model.*; import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData; +import org.jetbrains.plugins.gradle.tooling.builder.ModelBuildScriptClasspathBuilderImpl; import org.jetbrains.plugins.gradle.tooling.internal.init.Init; import org.jetbrains.plugins.gradle.util.GradleBundle; import org.jetbrains.plugins.gradle.util.GradleConstants; @@ -91,7 +89,7 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver } @Override - public void setNext(@Nullable GradleProjectResolverExtension next) { + public void setNext(@NotNull GradleProjectResolverExtension next) { // should be the last extension in the chain } @@ -324,6 +322,17 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver GradleBuild.class, ModuleExtendedModel.class, BuildScriptClasspathModel.class); } + @NotNull + @Override + public Set getToolingExtensionsClasses() { + return ContainerUtil.set( + // gradle-tooling-extension-api jar + ProjectImportAction.class, + // gradle-tooling-extension-impl jar + ModelBuildScriptClasspathBuilderImpl.class + ); + } + @NotNull @Override public List> getExtraJvmArgs() { @@ -360,6 +369,23 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver public void preImportCheck() { } + @Override + public void enhanceTaskProcessing(@NotNull List taskNames, + @Nullable String debuggerSetup, + @NotNull Consumer initScriptConsumer) { + if (!StringUtil.isEmpty(debuggerSetup)) { + final String[] lines = { + "gradle.taskGraph.beforeTask { Task task ->", + " if (task instanceof JavaForkOptions) {", + " task.jvmArgs '" + debuggerSetup.trim() + '\'', + " }" + + "}", + }; + final String script = StringUtil.join(lines, SystemProperties.getLineSeparator()); + initScriptConsumer.consume(script); + } + } + @Override public void enhanceRemoteProcessing(@NotNull SimpleJavaParameters parameters) throws ExecutionException { PathsList classPath = parameters.getClassPath(); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleExecutionHelper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleExecutionHelper.java index 3a761b550192..e44c2f937264 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleExecutionHelper.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleExecutionHelper.java @@ -47,7 +47,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Field; -import java.util.*; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; @@ -382,14 +385,15 @@ public class GradleExecutionHelper { } @Nullable - public static File generateInitScript(boolean isBuildSrcProject) { + public static File generateInitScript(boolean isBuildSrcProject, @NotNull Set toolingExtensionClasses) { InputStream stream = Init.class.getResourceAsStream("/org/jetbrains/plugins/gradle/tooling/internal/init/init.gradle"); try { if (stream == null) { LOG.warn("Can't get init script template"); return null; } - String s = FileUtil.loadTextAndClose(stream).replaceFirst(Pattern.quote("${EXTENSIONS_JARS_PATH}"), getToolingExtensionsJarPaths()); + final String toolingExtensionsJarPaths = getToolingExtensionsJarPaths(toolingExtensionClasses); + String s = FileUtil.loadTextAndClose(stream).replaceFirst(Pattern.quote("${EXTENSIONS_JARS_PATH}"), toolingExtensionsJarPaths); if (isBuildSrcProject) { String buildSrcDefaultInitScript = getBuildSrcDefaultInitScript(); if (buildSrcDefaultInitScript == null) return null; @@ -482,17 +486,10 @@ public class GradleExecutionHelper { } @NotNull - private static String getToolingExtensionsJarPaths() throws ClassNotFoundException { - final ArrayList> list = ContainerUtil.newArrayList( - // add gradle-tooling-extension-api jar - Class.forName("org.jetbrains.plugins.gradle.model.ProjectImportAction"), - // add gradle-tooling-extension-impl jar - Class.forName("org.jetbrains.plugins.gradle.tooling.builder.ModelBuildScriptClasspathBuilderImpl") - ); - + private static String getToolingExtensionsJarPaths(@NotNull Set toolingExtensionClasses) { StringBuilder buf = new StringBuilder(); buf.append('['); - for (Iterator> it = list.iterator(); it.hasNext(); ) { + for (Iterator it = toolingExtensionClasses.iterator(); it.hasNext(); ) { Class aClass = it.next(); String jarPath = PathUtil.getCanonicalPath(PathUtil.getJarPathForClass(aClass)); buf.append('\"').append(jarPath).append('\"'); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java index 1df5e1e2ef9e..142e0ae4d8a9 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java @@ -87,33 +87,11 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver> extensionClasses = settings.getResolverExtensions(); - - Deque extensions = new ArrayDeque(); - for (ClassHolder holder : extensionClasses) { - final GradleProjectResolverExtension extension; - try { - extension = holder.getTargetClass().newInstance(); - } - catch (Throwable e) { - throw new IllegalArgumentException( - String.format("Can't instantiate project resolve extension for class '%s'", holder.getTargetClassName()), e); - } - final GradleProjectResolverExtension previous = extensions.peekLast(); - if (previous != null) { - previous.setNext(extension); - } - extensions.add(extension); - } - projectResolverChain = extensions.peekFirst(); - } - else { - projectResolverChain = new BaseGradleProjectResolverExtension(); } + final GradleProjectResolverExtension projectResolverChain = createProjectResolverChain(settings); final DataNode resultProjectDataNode = myHelper.execute( projectPath, settings, new ProjectConnectionDataNodeFunction( @@ -145,6 +123,7 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver> extraJvmArgs = new ArrayList>(); final List commandLineArgs = ContainerUtil.newArrayList(); + final Set toolingExtensionClasses = ContainerUtil.newHashSet(); for (GradleProjectResolverExtension resolverExtension = projectResolverChain; resolverExtension != null; @@ -159,6 +138,8 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver moduleTasks = projectResolverChain.populateModuleTasks(ideaModule, moduleDataNode, projectDataNode); allTasks.addAll(moduleTasks); } @@ -299,8 +280,11 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver resultProjectDataNode, @NotNull final ProjectConnectionDataNodeFunction projectConnectionDataNodeFunction) { - if (projectConnectionDataNodeFunction.myIsPreviewMode || GradleEnvironment.DISABLE_ENHANCED_TOOLING_API || - !new File(projectConnectionDataNodeFunction.myProjectPath).isDirectory()) return; + if (projectConnectionDataNodeFunction.myIsPreviewMode + || GradleEnvironment.DISABLE_ENHANCED_TOOLING_API + || !new File(projectConnectionDataNodeFunction.myProjectPath).isDirectory()) { + return; + } final DataNode buildSrcModuleDataNode = ExternalSystemApiUtil.find(resultProjectDataNode, ProjectKeys.MODULE, new BooleanFunction>() { @@ -369,4 +353,48 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver> extensionClasses = settings.getResolverExtensions(); + + Deque extensions = new ArrayDeque(); + for (ClassHolder holder : extensionClasses) { + final GradleProjectResolverExtension extension; + try { + extension = holder.getTargetClass().newInstance(); + } + catch (Throwable e) { + throw new IllegalArgumentException( + String.format("Can't instantiate project resolve extension for class '%s'", holder.getTargetClassName()), e); + } + final GradleProjectResolverExtension previous = extensions.peekLast(); + if (previous != null) { + previous.setNext(extension); + if (previous.getNext() != extension) { + throw new AssertionError("Illegal next resolver got, current resolver class is " + previous.getClass().getName()); + } + } + extensions.add(extension); + } + projectResolverChain = extensions.peekFirst(); + + GradleProjectResolverExtension resolverExtension = projectResolverChain; + assert resolverExtension != null; + while (resolverExtension.getNext() != null) { + resolverExtension = resolverExtension.getNext(); + } + if (!(resolverExtension instanceof BaseGradleProjectResolverExtension)) { + throw new AssertionError("Illegal last resolver got of class " + resolverExtension.getClass().getName()); + } + } + else { + projectResolverChain = new BaseGradleProjectResolverExtension(); + } + + return projectResolverChain; + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java index 145225ce45d4..b727005db845 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java @@ -25,6 +25,7 @@ import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.model.task.TaskData; import com.intellij.openapi.externalSystem.service.ParametersEnhancer; import com.intellij.openapi.util.KeyValue; +import com.intellij.util.Consumer; import org.gradle.tooling.model.idea.IdeaModule; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,7 +51,7 @@ public interface GradleProjectResolverExtension extends ParametersEnhancer { void setProjectResolverContext(@NotNull ProjectResolverContext projectResolverContext); - void setNext(@Nullable GradleProjectResolverExtension projectResolverExtension); + void setNext(@NotNull GradleProjectResolverExtension projectResolverExtension); @Nullable GradleProjectResolverExtension getNext(); @@ -98,6 +99,14 @@ public interface GradleProjectResolverExtension extends ParametersEnhancer { @NotNull Set getExtraProjectModelClasses(); + /** + * add paths containing these classes to classpath of gradle tooling extension + * + * @return classes to be available for gradle + */ + @NotNull + Set getToolingExtensionsClasses(); + @NotNull List> getExtraJvmArgs(); @@ -111,4 +120,6 @@ public interface GradleProjectResolverExtension extends ParametersEnhancer { * Performs project configuration and other checks before the actual project import (before invocation of gradle tooling API). */ void preImportCheck(); + + void enhanceTaskProcessing(@NotNull List taskNames, @Nullable String debuggerSetup, @NotNull Consumer initScriptConsumer); } 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 5837c5c103ce..ad8bfea8d856 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 @@ -25,6 +25,7 @@ import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; +import com.intellij.util.Consumer; import com.intellij.util.Function; import com.intellij.util.SystemProperties; import com.intellij.util.containers.ContainerUtil; @@ -33,6 +34,8 @@ import org.gradle.tooling.ProjectConnection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.service.project.GradleExecutionHelper; +import org.jetbrains.plugins.gradle.service.project.GradleProjectResolver; +import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverExtension; import org.jetbrains.plugins.gradle.settings.GradleExecutionSettings; import org.jetbrains.plugins.gradle.util.GradleConstants; @@ -75,18 +78,32 @@ public class GradleTaskManager extends AbstractExternalSystemTaskManager f = new Function() { @Override public Void fun(ProjectConnection connection) { - if (!StringUtil.isEmpty(debuggerSetup)) { + + final List initScripts = ContainerUtil.newArrayList(); + final GradleProjectResolverExtension projectResolverChain = GradleProjectResolver.createProjectResolverChain(settings); + for (GradleProjectResolverExtension resolverExtension = projectResolverChain; + resolverExtension != null; + resolverExtension = resolverExtension.getNext()) { + final String resolverClassName = resolverExtension.getClass().getName(); + resolverExtension.enhanceTaskProcessing(taskNames, debuggerSetup, new Consumer() { + @Override + public void consume(String script) { + if (StringUtil.isNotEmpty(script)) { + ContainerUtil.addAllNotNull( + initScripts, + "//-- Generated by " + resolverClassName, + script, + "//"); + } + } + }); + } + + if (!initScripts.isEmpty()) { try { final File tempFile = FileUtil.createTempFile("init", ".gradle"); tempFile.deleteOnExit(); - final String[] lines = { - "gradle.taskGraph.beforeTask { Task task ->", - " if (task instanceof JavaForkOptions) {", - " task.jvmArgs '" + debuggerSetup.trim() + '\'', - "}}", - }; - FileUtil.writeToFile(tempFile, StringUtil.join(lines, SystemProperties.getLineSeparator())); - + FileUtil.writeToFile(tempFile, StringUtil.join(initScripts, SystemProperties.getLineSeparator())); ContainerUtil.addAll(scriptParameters, GradleConstants.INIT_SCRIPT_CMD_OPTION, tempFile.getAbsolutePath()); } catch (IOException e) { diff --git a/plugins/gradle/tooling-extension-api/gradle-tooling-extension-api.iml b/plugins/gradle/tooling-extension-api/gradle-tooling-extension-api.iml index 898ae3d4e65c..e115edc96975 100644 --- a/plugins/gradle/tooling-extension-api/gradle-tooling-extension-api.iml +++ b/plugins/gradle/tooling-extension-api/gradle-tooling-extension-api.iml @@ -11,7 +11,7 @@ - + diff --git a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/tooling/ModelBuilderService.java b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/tooling/ModelBuilderService.java index cd29943a4b0b..7254a916c5a2 100644 --- a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/tooling/ModelBuilderService.java +++ b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/tooling/ModelBuilderService.java @@ -18,11 +18,13 @@ package org.jetbrains.plugins.gradle.tooling; import org.gradle.api.Project; import org.jetbrains.annotations.NotNull; +import java.io.Serializable; + /** * @author Vladislav.Soroka * @since 11/5/13 */ -public interface ModelBuilderService { +public interface ModelBuilderService extends Serializable { boolean canBuild(String modelName); Object buildAll(String modelName, Project project); diff --git a/plugins/gradle/tooling-extension-impl/testSources/org/jetbrains/plugins/gradle/tooling/builder/AbstractModelBuilderTest.java b/plugins/gradle/tooling-extension-impl/testSources/org/jetbrains/plugins/gradle/tooling/builder/AbstractModelBuilderTest.java index e961117f7d2d..b00e0f506524 100644 --- a/plugins/gradle/tooling-extension-impl/testSources/org/jetbrains/plugins/gradle/tooling/builder/AbstractModelBuilderTest.java +++ b/plugins/gradle/tooling-extension-impl/testSources/org/jetbrains/plugins/gradle/tooling/builder/AbstractModelBuilderTest.java @@ -15,16 +15,23 @@ */ package org.jetbrains.plugins.gradle.tooling.builder; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.testFramework.UsefulTestCase; +import com.intellij.util.Function; import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; import org.gradle.tooling.BuildActionExecuter; import org.gradle.tooling.GradleConnector; import org.gradle.tooling.ProjectConnection; import org.gradle.tooling.internal.consumer.DefaultGradleConnector; +import org.gradle.tooling.model.DomainObjectSet; +import org.gradle.tooling.model.idea.IdeaModule; import org.gradle.util.GradleVersion; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.model.BuildScriptClasspathModel; +import org.jetbrains.plugins.gradle.model.ClasspathEntryModel; import org.jetbrains.plugins.gradle.model.ProjectImportAction; import org.jetbrains.plugins.gradle.service.project.GradleExecutionHelper; import org.jetbrains.plugins.gradle.util.GradleConstants; @@ -39,13 +46,12 @@ import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Set; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; /** @@ -58,7 +64,7 @@ public abstract class AbstractModelBuilderTest { public static final String GRADLE_v1_9 = "1.9"; public static final String GRADLE_v1_10 = "1.10"; public static final String GRADLE_v1_11 = "1.11"; - public static final String GRADLE_v1_12 = "1.12-rc-1"; + public static final String GRADLE_v1_12 = "1.12"; public static final Pattern TEST_METHOD_NAME_PATTERN = Pattern.compile("(.*)\\[(\\d*)\\]"); @@ -136,13 +142,31 @@ public abstract class AbstractModelBuilderTest { final ProjectImportAction projectImportAction = new ProjectImportAction(false); projectImportAction.addExtraProjectModelClasses(getModels()); BuildActionExecuter buildActionExecutor = connection.action(projectImportAction); - File initScript = GradleExecutionHelper.generateInitScript(false); + File initScript = GradleExecutionHelper.generateInitScript(false, getToolingExtensionClasses()); assertNotNull(initScript); buildActionExecutor.withArguments(GradleConstants.INIT_SCRIPT_CMD_OPTION, initScript.getAbsolutePath()); allModels = buildActionExecutor.run(); assertNotNull(allModels); } + @NotNull + private Set getToolingExtensionClasses() { + final Set classes = ContainerUtil.set( + // gradle-tooling-extension-api jar + ProjectImportAction.class, + // gradle-tooling-extension-impl jar + ModelBuildScriptClasspathBuilderImpl.class + ); + + ContainerUtil.addAllNotNull(classes, doGetToolingExtensionClasses()); + return classes; + } + + @NotNull + protected Set doGetToolingExtensionClasses() { + return Collections.emptySet(); + } + @After public void tearDown() throws Exception { if (testDir != null) { @@ -152,6 +176,43 @@ public abstract class AbstractModelBuilderTest { protected abstract Set getModels(); + + protected Map getModulesMap(final Class aClass) { + final DomainObjectSet ideaModules = allModels.getIdeaProject().getModules(); + + final String filterKey = "to_filter"; + final Map map = ContainerUtil.map2Map(ideaModules, new Function>() { + @Override + public Pair fun(IdeaModule module) { + final T value = allModels.getExtraProject(module, aClass); + final String key = value != null ? module.getGradleProject().getPath() : filterKey; + return Pair.create(key, value); + } + }); + + map.remove(filterKey); + return map; + } + + protected void assertBuildClasspath(String projectPath, String... classpath) { + final Map classpathModelMap = getModulesMap(BuildScriptClasspathModel.class); + final BuildScriptClasspathModel classpathModel = classpathModelMap.get(projectPath); + + assertNotNull(classpathModel); + + final List classpathEntryModels = classpathModel.getClasspath().getAll(); + assertEquals(classpath.length, classpathEntryModels.size()); + + for (int i = 0, length = classpath.length; i < length; i++) { + String classpathEntry = classpath[i]; + final ClasspathEntryModel classpathEntryModel = classpathEntryModels.get(i); + assertNotNull(classpathEntryModel); + assertEquals(1, classpathEntryModel.getClasses().size()); + final String path = classpathEntryModel.getClasses().iterator().next(); + assertEquals(classpathEntry, new File(path).getName()); + } + } + private static void ensureTempDirCreated() throws IOException { if (ourTempDir != null) return; diff --git a/plugins/groovy/jetgroovy.iml b/plugins/groovy/jetgroovy.iml index aa40a30a8f49..4ae317b2555c 100644 --- a/plugins/groovy/jetgroovy.iml +++ b/plugins/groovy/jetgroovy.iml @@ -36,6 +36,7 @@ + diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 90db9586fb90..f16d2c195482 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -69,6 +69,7 @@ + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcCliCommandExecutor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcCliCommandExecutor.java new file mode 100644 index 000000000000..120c5abf189b --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcCliCommandExecutor.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2014 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.groovy.mvc; + +import com.intellij.execution.configurations.GeneralCommandLine; +import com.intellij.openapi.module.Module; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Vladislav.Soroka + * @since 6/19/2014 + */ +public class MvcCliCommandExecutor extends MvcCommandExecutor { + @Override + protected boolean isApplicable(Module module) { + return true; + } + + @Nullable + @Override + protected ConsoleProcessDescriptor doRun(@NotNull Module module, + @NotNull MvcFramework framework, + @NotNull MvcCommand mvcCommand, + @Nullable Runnable onDone, + boolean showConsole, + boolean closeOnDone, + String... input) { + final GeneralCommandLine commandLine = framework.createCommandAndShowErrors(null, module, mvcCommand); + if (commandLine == null) return null; + return MvcConsole.executeProcess(module, commandLine, onDone, closeOnDone, input); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcCommandExecutor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcCommandExecutor.java new file mode 100644 index 000000000000..c4c791ba0042 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcCommandExecutor.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2014 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.groovy.mvc; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.module.Module; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Vladislav.Soroka + * @since 6/19/2014 + */ +public abstract class MvcCommandExecutor { + private static final ExtensionPointName EP_NAME = + ExtensionPointName.create("org.intellij.groovy.mvc.command.executor"); + + @Nullable + public static ConsoleProcessDescriptor run(@NotNull Module module, + @NotNull MvcFramework framework, + @NotNull MvcCommand mvcCommand, + @Nullable Runnable onDone, + boolean closeOnDone, + String... input) { + return run(module, framework, mvcCommand, onDone, true, closeOnDone, input); + } + + @Nullable + public static ConsoleProcessDescriptor run(@NotNull Module module, + @NotNull MvcFramework framework, + @NotNull MvcCommand mvcCommand, + @Nullable Runnable onDone, + boolean showConsole, + boolean closeOnDone, + String... input) { + for (MvcCommandExecutor executor : EP_NAME.getExtensions()) { + if (executor.isApplicable(module)) { + return executor.doRun(module, framework, mvcCommand, onDone, showConsole, closeOnDone, input); + } + } + + // fallback to default CLI implementation + return new MvcCliCommandExecutor().doRun(module, framework, mvcCommand, onDone, showConsole, closeOnDone, input); + } + + protected abstract boolean isApplicable(Module module); + + @Nullable + protected abstract ConsoleProcessDescriptor doRun(@NotNull Module module, + @NotNull MvcFramework framework, + @NotNull MvcCommand mvcCommand, + @Nullable Runnable onDone, + boolean showConsole, + boolean closeOnDone, + String... input); +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcRunTarget.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcRunTarget.java index 6efc6665504e..ad856e862223 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcRunTarget.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcRunTarget.java @@ -15,7 +15,6 @@ */ package org.jetbrains.plugins.groovy.mvc; -import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.module.Module; import org.jetbrains.annotations.NotNull; @@ -34,13 +33,8 @@ public class MvcRunTarget extends MvcActionBase { } Module selectedModule = dialog.getSelectedModule(); - MvcCommand cmd = MvcCommand.parse(dialog.getTargetArguments()); - - final GeneralCommandLine commandLine = framework.createCommandAndShowErrors(dialog.getVmOptions(), selectedModule, cmd); - if (commandLine == null) return; - - MvcConsole.executeProcess(selectedModule, commandLine, null, false); + MvcCommandExecutor.run(selectedModule, framework, cmd, null, false); } }