mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Gradle: cross-cutting debug of the Gradle groovy DSL(daemon) and subsequent java forked tasks (IDEA-119494)
This commit is contained in:
+22
-1
@@ -79,6 +79,8 @@ import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.openapi.externalSystem.util.ExternalSystemUtil.convert;
|
||||
@@ -92,9 +94,11 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i
|
||||
SMRunnerConsolePropertiesProvider {
|
||||
public static final Key<InputStream> RUN_INPUT_KEY = Key.create("RUN_INPUT_KEY");
|
||||
public static final Key<Class<? extends BuildProgressListener>> PROGRESS_LISTENER_KEY = Key.create("PROGRESS_LISTENER_KEY");
|
||||
public static final String DEBUG_SETUP_PREFIX = "-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=";
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(ExternalSystemRunConfiguration.class);
|
||||
private ExternalSystemTaskExecutionSettings mySettings = new ExternalSystemTaskExecutionSettings();
|
||||
private static final boolean DISABLE_FORK_DEBUGGER = Boolean.getBoolean("external.system.disable.fork.debugger.");
|
||||
|
||||
public ExternalSystemRunConfiguration(@NotNull ProjectSystemId externalSystemId,
|
||||
Project project,
|
||||
@@ -219,6 +223,7 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i
|
||||
@Nullable private RunContentDescriptor myContentDescriptor;
|
||||
|
||||
private final int myDebugPort;
|
||||
private ServerSocket myForkSocket = null;
|
||||
|
||||
public MyRunnableState(@NotNull ExternalSystemTaskExecutionSettings settings,
|
||||
@NotNull Project project,
|
||||
@@ -249,6 +254,19 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i
|
||||
return myDebugPort;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ServerSocket getForkSocket() {
|
||||
if (myForkSocket == null && !DISABLE_FORK_DEBUGGER) {
|
||||
try {
|
||||
myForkSocket = new ServerSocket(0, 0, InetAddress.getByName("127.0.0.1"));
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
return myForkSocket;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ExecutionResult execute(Executor executor, @NotNull ProgramRunner runner) throws ExecutionException {
|
||||
@@ -266,7 +284,10 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i
|
||||
|
||||
String jvmAgentSetup;
|
||||
if (myDebugPort > 0) {
|
||||
jvmAgentSetup = "-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=" + myDebugPort;
|
||||
jvmAgentSetup = DEBUG_SETUP_PREFIX + myDebugPort;
|
||||
if (getForkSocket() != null) {
|
||||
jvmAgentSetup += " -forkSocket" + getForkSocket().getLocalPort();
|
||||
}
|
||||
}
|
||||
else {
|
||||
ParametersList parametersList = extensionsJP.getVMParametersList();
|
||||
|
||||
+208
-20
@@ -18,18 +18,40 @@ package com.intellij.openapi.externalSystem.service.execution;
|
||||
import com.intellij.build.BuildView;
|
||||
import com.intellij.debugger.impl.GenericDebuggerRunner;
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.ProgramRunnerUtil;
|
||||
import com.intellij.execution.RunManager;
|
||||
import com.intellij.execution.RunnerAndConfigurationSettings;
|
||||
import com.intellij.execution.configurations.ConfigurationFactory;
|
||||
import com.intellij.execution.configurations.RemoteConnection;
|
||||
import com.intellij.execution.configurations.RunProfile;
|
||||
import com.intellij.execution.configurations.RunProfileState;
|
||||
import com.intellij.execution.executors.DefaultDebugExecutor;
|
||||
import com.intellij.execution.process.ProcessAdapter;
|
||||
import com.intellij.execution.process.ProcessEvent;
|
||||
import com.intellij.execution.process.ProcessHandler;
|
||||
import com.intellij.execution.remote.RemoteConfiguration;
|
||||
import com.intellij.execution.remote.RemoteConfigurationType;
|
||||
import com.intellij.execution.runners.ExecutionEnvironment;
|
||||
import com.intellij.execution.runners.ExecutionEnvironmentBuilder;
|
||||
import com.intellij.execution.ui.ExecutionConsole;
|
||||
import com.intellij.execution.ui.RunContentDescriptor;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.wm.ToolWindowId;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.ui.content.Content;
|
||||
import com.intellij.ui.content.ContentManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 6/7/13 11:18 AM
|
||||
@@ -52,30 +74,18 @@ public class ExternalSystemTaskDebugRunner extends GenericDebuggerRunner {
|
||||
@Override
|
||||
protected RunContentDescriptor createContentDescriptor(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment) throws ExecutionException {
|
||||
if (state instanceof ExternalSystemRunConfiguration.MyRunnableState) {
|
||||
int port = ((ExternalSystemRunConfiguration.MyRunnableState)state).getDebugPort();
|
||||
ExternalSystemRunConfiguration.MyRunnableState myRunnableState = (ExternalSystemRunConfiguration.MyRunnableState)state;
|
||||
int port = myRunnableState.getDebugPort();
|
||||
if (port > 0) {
|
||||
RemoteConnection connection = new RemoteConnection(true, "127.0.0.1", String.valueOf(port), true);
|
||||
RunContentDescriptor runContentDescriptor = attachVirtualMachine(state, environment, connection, true);
|
||||
RunContentDescriptor runContentDescriptor = doGetRunContentDescriptor(myRunnableState, environment, port);
|
||||
if (runContentDescriptor == null) return null;
|
||||
|
||||
((ExternalSystemRunConfiguration.MyRunnableState)state).setContentDescriptor(runContentDescriptor);
|
||||
|
||||
ExecutionConsole executionConsole = runContentDescriptor.getExecutionConsole();
|
||||
if(executionConsole instanceof BuildView) {
|
||||
return runContentDescriptor;
|
||||
ProcessHandler processHandler = runContentDescriptor.getProcessHandler();
|
||||
final ServerSocket socket = myRunnableState.getForkSocket();
|
||||
if (socket != null && processHandler != null) {
|
||||
new ForkedDebuggerThread(processHandler, socket, environment.getProject()).start();
|
||||
}
|
||||
RunContentDescriptor descriptor =
|
||||
new RunContentDescriptor(runContentDescriptor.getExecutionConsole(), runContentDescriptor.getProcessHandler(),
|
||||
runContentDescriptor.getComponent(), runContentDescriptor.getDisplayName(),
|
||||
runContentDescriptor.getIcon(), null,
|
||||
runContentDescriptor.getRestartActions()) {
|
||||
@Override
|
||||
public boolean isHiddenContent() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
descriptor.setRunnerLayoutUi(runContentDescriptor.getRunnerLayoutUi());
|
||||
return descriptor;
|
||||
return runContentDescriptor;
|
||||
}
|
||||
else {
|
||||
LOG.warn("Can't attach debugger to external system task execution. Reason: target debug port is unknown");
|
||||
@@ -90,4 +100,182 @@ public class ExternalSystemTaskDebugRunner extends GenericDebuggerRunner {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private RunContentDescriptor doGetRunContentDescriptor(@NotNull ExternalSystemRunConfiguration.MyRunnableState state,
|
||||
@NotNull ExecutionEnvironment environment,
|
||||
int port) throws ExecutionException {
|
||||
RemoteConnection connection = new RemoteConnection(true, "127.0.0.1", String.valueOf(port), true);
|
||||
RunContentDescriptor runContentDescriptor = attachVirtualMachine(state, environment, connection, true);
|
||||
if (runContentDescriptor == null) return null;
|
||||
|
||||
state.setContentDescriptor(runContentDescriptor);
|
||||
|
||||
ExecutionConsole executionConsole = runContentDescriptor.getExecutionConsole();
|
||||
if (executionConsole instanceof BuildView) {
|
||||
return runContentDescriptor;
|
||||
}
|
||||
RunContentDescriptor descriptor =
|
||||
new RunContentDescriptor(runContentDescriptor.getExecutionConsole(), runContentDescriptor.getProcessHandler(),
|
||||
runContentDescriptor.getComponent(), runContentDescriptor.getDisplayName(),
|
||||
runContentDescriptor.getIcon(), null,
|
||||
runContentDescriptor.getRestartActions()) {
|
||||
@Override
|
||||
public boolean isHiddenContent() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
descriptor.setRunnerLayoutUi(runContentDescriptor.getRunnerLayoutUi());
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
private static class ForkedDebuggerThread extends Thread {
|
||||
private final ProcessHandler myProcessHandler;
|
||||
private final ServerSocket mySocket;
|
||||
private final Project myProject;
|
||||
|
||||
public ForkedDebuggerThread(ProcessHandler processHandler, ServerSocket socket, Project project) {
|
||||
super("external task forked debugger runner");
|
||||
setDaemon(true);
|
||||
myProcessHandler = processHandler;
|
||||
mySocket = socket;
|
||||
myProject = project;
|
||||
myProcessHandler.addProcessListener(new ProcessAdapter() {
|
||||
@Override
|
||||
public void processTerminated(@NotNull ProcessEvent event) {
|
||||
closeSocket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processWillTerminate(@NotNull ProcessEvent event, boolean willBeDestroyed) {
|
||||
closeSocket();
|
||||
}
|
||||
|
||||
void closeSocket() {
|
||||
try {
|
||||
mySocket.close();
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!myProcessHandler.isProcessTerminated() && !myProcessHandler.isProcessTerminating() && !mySocket.isClosed()) {
|
||||
try {
|
||||
Socket accept = mySocket.accept();
|
||||
handleForkedProcessSignal(accept, myProject, myProcessHandler);
|
||||
}
|
||||
catch (EOFException ignored) {
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
mySocket.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleForkedProcessSignal(Socket accept, Project project, ProcessHandler processHandler) throws IOException {
|
||||
try {
|
||||
DataInputStream stream = new DataInputStream(accept.getInputStream());
|
||||
try {
|
||||
int signal = stream.readInt();
|
||||
String processName = stream.readUTF();
|
||||
if (signal > 0) {
|
||||
String debugPort = String.valueOf(signal);
|
||||
attachVM(project, processName, debugPort, new Callback() {
|
||||
@Override
|
||||
public void processStarted(RunContentDescriptor descriptor) {
|
||||
// select tab for the forked process only when it has been suspended
|
||||
descriptor.setSelectContentWhenAdded(false);
|
||||
|
||||
// restore selection of the 'main' tab to avoid flickering of the reused content tab when no suspend events occur
|
||||
ProcessHandler processHandler = descriptor.getProcessHandler();
|
||||
if (processHandler != null) {
|
||||
processHandler.addProcessListener(new ProcessAdapter() {
|
||||
@Override
|
||||
public void processTerminated(@NotNull ProcessEvent event) {
|
||||
final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);
|
||||
ContentManager contentManager = toolWindowManager.getToolWindow(ToolWindowId.DEBUG).getContentManager();
|
||||
Content content = descriptor.getAttachedContent();
|
||||
if (content != null) {
|
||||
ApplicationManager.getApplication().invokeLater(() -> contentManager.removeContent(content, true));
|
||||
}
|
||||
}
|
||||
});
|
||||
try {
|
||||
accept.getOutputStream().write(0);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (signal == 0) {
|
||||
// remove content for terminated forked processes
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);
|
||||
ContentManager contentManager = toolWindowManager.getToolWindow(ToolWindowId.DEBUG).getContentManager();
|
||||
Content content = contentManager.findContent(processName);
|
||||
if (content != null) {
|
||||
RunContentDescriptor descriptor = content.getUserData(RunContentDescriptor.DESCRIPTOR_KEY);
|
||||
if (descriptor != null) {
|
||||
ProcessHandler handler = descriptor.getProcessHandler();
|
||||
if (handler != null) {
|
||||
handler.destroyProcess();
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
accept.getOutputStream().write(0);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
accept.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void attachVM(@NotNull Project project, String runConfigName, @NotNull String debugPort, Callback callback) {
|
||||
RemoteConfigurationType remoteConfigurationType = RemoteConfigurationType.getInstance();
|
||||
ConfigurationFactory factory = remoteConfigurationType.getFactory();
|
||||
RunnerAndConfigurationSettings runSettings = RunManager.getInstance(project).createRunConfiguration(runConfigName, factory);
|
||||
runSettings.setActivateToolWindowBeforeRun(false);
|
||||
|
||||
RemoteConfiguration configuration = (RemoteConfiguration)runSettings.getConfiguration();
|
||||
configuration.HOST = "localhost";
|
||||
configuration.PORT = debugPort;
|
||||
configuration.USE_SOCKET_TRANSPORT = true;
|
||||
configuration.SERVER_MODE = true;
|
||||
|
||||
try {
|
||||
ExecutionEnvironment environment = ExecutionEnvironmentBuilder.create(DefaultDebugExecutor.getDebugExecutorInstance(), runSettings)
|
||||
.contentToReuse(null)
|
||||
.dataContext(null)
|
||||
.activeTarget()
|
||||
.build();
|
||||
ProgramRunnerUtil.executeConfigurationAsync(environment, true, true, callback);
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.externalSystem.rt.execution;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* @author Vladislav.Soroka
|
||||
*/
|
||||
public class ForkedDebuggerHelper {
|
||||
|
||||
public static String setupDebugger(String processName, int debugPort) {
|
||||
String setup = "";
|
||||
try {
|
||||
if (debugPort > -1) {
|
||||
int debugAddress = findAvailableSocketPort();
|
||||
if (debugAddress > -1) {
|
||||
setup = "-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=" + debugAddress;
|
||||
send(debugAddress, processName, debugPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
//noinspection CallToPrintStackTrace
|
||||
e.printStackTrace();
|
||||
}
|
||||
return setup;
|
||||
}
|
||||
|
||||
public static void processFinished(String processName, int debugPort) {
|
||||
send(0, processName, debugPort);
|
||||
}
|
||||
|
||||
private static void send(int signal, String processName, int debugPort) {
|
||||
try {
|
||||
Socket socket = new Socket("127.0.0.1", debugPort);
|
||||
try {
|
||||
DataOutputStream stream = new DataOutputStream(socket.getOutputStream());
|
||||
try {
|
||||
stream.writeInt(signal);
|
||||
stream.writeUTF(processName);
|
||||
// wait for the signal handling
|
||||
int read = socket.getInputStream().read();
|
||||
}
|
||||
finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
// copied from NetUtils
|
||||
protected static int findAvailableSocketPort() throws IOException {
|
||||
final ServerSocket serverSocket = new ServerSocket(0);
|
||||
try {
|
||||
int port = serverSocket.getLocalPort();
|
||||
// workaround for linux : calling close() immediately after opening socket
|
||||
// may result that socket is not closed
|
||||
//noinspection SynchronizationOnLocalVariableOrMethodParameter
|
||||
synchronized (serverSocket) {
|
||||
try {
|
||||
//noinspection WaitNotInLoop
|
||||
serverSocket.wait(1);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
System.err.println(e);
|
||||
}
|
||||
}
|
||||
return port;
|
||||
}
|
||||
finally {
|
||||
serverSocket.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,18 +15,16 @@
|
||||
*/
|
||||
package org.jetbrains.plugins.gradle.config;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.externalSystem.ExternalSystemModulePropertyManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtilCore;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
@@ -34,41 +32,27 @@ import com.intellij.psi.util.CachedValue;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap;
|
||||
import com.intellij.util.lang.UrlClassLoader;
|
||||
import com.sun.jdi.AbsentInformationException;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import org.gradle.groovy.scripts.TextResourceScriptSource;
|
||||
import org.gradle.internal.resource.BasicTextResourceLoader;
|
||||
import org.gradle.internal.resource.TextResource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.service.GradleInstallationManager;
|
||||
import org.jetbrains.plugins.groovy.extensions.debugger.ScriptPositionManagerHelper;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
|
||||
import org.jetbrains.plugins.groovy.runner.GroovyScriptUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author John Murph
|
||||
*/
|
||||
public class GradlePositionManager extends ScriptPositionManagerHelper {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.gradle.config.GradlePositionManager");
|
||||
|
||||
private static final Pattern GRADLE_CLASS_PATTERN = Pattern.compile(".*_gradle_.*");
|
||||
private static final String SCRIPT_CLOSURE_PREFIX = "build_";
|
||||
private static final Key<CachedValue<ClassLoader>> GRADLE_CLASS_LOADER = Key.create("GRADLE_CLASS_LOADER");
|
||||
private static final Key<CachedValue<Map<File, String>>> GRADLE_CLASS_NAME = Key.create("GRADLE_CLASS_NAME");
|
||||
|
||||
private final GradleInstallationManager myLibraryManager;
|
||||
|
||||
public GradlePositionManager(@NotNull GradleInstallationManager manager) {
|
||||
myLibraryManager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAppropriateRuntimeName(@NotNull final String runtimeName) {
|
||||
return runtimeName.startsWith(SCRIPT_CLOSURE_PREFIX) || GRADLE_CLASS_PATTERN.matcher(runtimeName).matches();
|
||||
@@ -92,12 +76,28 @@ public class GradlePositionManager extends ScriptPositionManagerHelper {
|
||||
|
||||
final File scriptFile = VfsUtilCore.virtualToIoFile(virtualFile);
|
||||
final String className = CachedValuesManager.getManager(module.getProject())
|
||||
.getCachedValue(module, GRADLE_CLASS_NAME, new ScriptSourceMapCalculator(module), false).get(scriptFile);
|
||||
.getCachedValue(module, GRADLE_CLASS_NAME, new ScriptSourceMapCalculator(module), false)
|
||||
.get(scriptFile);
|
||||
return className == null ? "" : className;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiFile getExtraScriptIfNotFound(@NotNull ReferenceType refType, @NotNull String runtimeName, @NotNull Project project, @NotNull GlobalSearchScope scope) {
|
||||
public String customizeClassName(@NotNull PsiClass psiClass) {
|
||||
PsiFile file = psiClass.getContainingFile();
|
||||
if (file instanceof GroovyFile) {
|
||||
return getRuntimeScriptName((GroovyFile)file);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiFile getExtraScriptIfNotFound(@NotNull ReferenceType refType,
|
||||
@NotNull String runtimeName,
|
||||
@NotNull Project project,
|
||||
@NotNull GlobalSearchScope scope) {
|
||||
String sourceFilePath = getScriptForClassName(refType);
|
||||
if (sourceFilePath == null) return null;
|
||||
|
||||
@@ -120,37 +120,7 @@ public class GradlePositionManager extends ScriptPositionManagerHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ClassLoader getGradleClassLoader(@NotNull final Module module) {
|
||||
final Project project = module.getProject();
|
||||
return CachedValuesManager.getManager(project).getCachedValue(module, GRADLE_CLASS_LOADER,
|
||||
() -> CachedValueProvider.Result.create(createGradleClassLoader(module), ProjectRootManager.getInstance(project)), false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ClassLoader createGradleClassLoader(@NotNull Module module) {
|
||||
String rootProjectPath = ExternalSystemModulePropertyManager.getInstance(module).getRootProjectPath();
|
||||
if (StringUtil.isEmpty(rootProjectPath)) {
|
||||
return null;
|
||||
}
|
||||
final VirtualFile sdkHome = myLibraryManager.getGradleHome(module, module.getProject(), rootProjectPath);
|
||||
if (sdkHome == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<URL> urls = new ArrayList<>();
|
||||
final VirtualFile libDir = sdkHome.findChild("lib");
|
||||
assert libDir != null;
|
||||
for (final VirtualFile child : libDir.getChildren()) {
|
||||
if ("jar".equals(child.getExtension())) {
|
||||
urls.add(VfsUtilCore.convertToURL(child.getUrl()));
|
||||
}
|
||||
}
|
||||
|
||||
return UrlClassLoader.build().urls(urls).get();
|
||||
}
|
||||
|
||||
private class ScriptSourceMapCalculator implements CachedValueProvider<Map<File, String>> {
|
||||
private static class ScriptSourceMapCalculator implements CachedValueProvider<Map<File, String>> {
|
||||
private final Module myModule;
|
||||
|
||||
public ScriptSourceMapCalculator(Module module) {
|
||||
@@ -159,36 +129,15 @@ public class GradlePositionManager extends ScriptPositionManagerHelper {
|
||||
|
||||
@Override
|
||||
public Result<Map<File, String>> compute() {
|
||||
final Map<File, String> result = ConcurrentFactoryMap.createMap(scriptFile -> calcClassName(scriptFile));
|
||||
final Map<File, String> result = ConcurrentFactoryMap.createMap(ScriptSourceMapCalculator::calcClassName);
|
||||
return Result.create(result, ProjectRootManager.getInstance(myModule.getProject()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String calcClassName(File scriptFile) {
|
||||
final ClassLoader loader = getGradleClassLoader(myModule);
|
||||
if (loader != null) {
|
||||
Class<?> fileScriptSource;
|
||||
try {
|
||||
fileScriptSource = Class.forName("org.gradle.groovy.scripts.UriScriptSource", true, loader);
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
try {
|
||||
fileScriptSource = Class.forName("org.gradle.groovy.scripts.FileScriptSource", true, loader); //before 0.9
|
||||
}
|
||||
catch (ClassNotFoundException e1) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
final Object source = fileScriptSource.getConstructor(String.class, File.class).newInstance("script", scriptFile);
|
||||
return (String)fileScriptSource.getMethod("getClassName").invoke(source);
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
private static String calcClassName(File scriptFile) {
|
||||
TextResource resource = new BasicTextResourceLoader().loadFile("script", scriptFile);
|
||||
TextResourceScriptSource scriptSource = new TextResourceScriptSource(resource);
|
||||
return scriptSource.getClassName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+45
-12
@@ -92,6 +92,7 @@ import static com.intellij.openapi.util.Pair.pair;
|
||||
import static org.jetbrains.plugins.gradle.service.project.GradleProjectResolver.CONFIGURATION_ARTIFACTS;
|
||||
import static org.jetbrains.plugins.gradle.service.project.GradleProjectResolver.MODULES_OUTPUTS;
|
||||
import static org.jetbrains.plugins.gradle.service.project.GradleProjectResolverUtil.*;
|
||||
import static org.jetbrains.plugins.gradle.service.task.GradleTaskManager.getForkedDebuggerSetup;
|
||||
|
||||
/**
|
||||
* {@link BaseGradleProjectResolverExtension} provides base implementation of Gradle project resolver.
|
||||
@@ -727,21 +728,53 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver
|
||||
@Nullable String jvmAgentSetup,
|
||||
@NotNull Consumer<String> initScriptConsumer) {
|
||||
if (!StringUtil.isEmpty(jvmAgentSetup)) {
|
||||
final String names = "[\"" + StringUtil.join(taskNames, "\", \"") + "\"]";
|
||||
final String[] lines = {
|
||||
"gradle.taskGraph.beforeTask { Task task ->",
|
||||
" if (task instanceof JavaForkOptions && (" + names + ".contains(task.name) || " + names + ".contains(task.path))) {",
|
||||
" def jvmArgs = task.jvmArgs.findAll{!it?.startsWith('-agentlib:jdwp') && !it?.startsWith('-Xrunjdwp')}",
|
||||
" jvmArgs << '" + jvmAgentSetup.trim().replace("\\", "\\\\") + '\'',
|
||||
" task.jvmArgs = jvmArgs",
|
||||
" }" +
|
||||
"}",
|
||||
};
|
||||
final String script = StringUtil.join(lines, SystemProperties.getLineSeparator());
|
||||
initScriptConsumer.consume(script);
|
||||
int debugPort = getForkedDebuggerSetup(jvmAgentSetup);
|
||||
if (debugPort != -1) {
|
||||
setupDebugForAllJvmForkedTasks(initScriptConsumer, debugPort);
|
||||
}
|
||||
else {
|
||||
final String names = "[\"" + StringUtil.join(taskNames, "\", \"") + "\"]";
|
||||
final String[] lines = {
|
||||
"gradle.taskGraph.beforeTask { Task task ->",
|
||||
" if (task instanceof JavaForkOptions && (" + names + ".contains(task.name) || " + names + ".contains(task.path))) {",
|
||||
" def jvmArgs = task.jvmArgs.findAll{!it?.startsWith('-agentlib:jdwp') && !it?.startsWith('-Xrunjdwp')}",
|
||||
" jvmArgs << '" + jvmAgentSetup.trim().replace("\\", "\\\\") + '\'',
|
||||
" task.jvmArgs = jvmArgs",
|
||||
" }" +
|
||||
"}",
|
||||
};
|
||||
final String script = StringUtil.join(lines, SystemProperties.getLineSeparator());
|
||||
initScriptConsumer.consume(script);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setupDebugForAllJvmForkedTasks(@NotNull Consumer<String> initScriptConsumer, int debugPort) {
|
||||
// external-system-rt.jar
|
||||
String esRtJarPath = PathUtil.getCanonicalPath(PathManager.getJarPathForClass(ExternalSystemSourceType.class));
|
||||
final String[] lines = {
|
||||
"initscript {",
|
||||
" dependencies {",
|
||||
" classpath files(\"" + esRtJarPath + "\")",
|
||||
" }",
|
||||
"}",
|
||||
"gradle.taskGraph.beforeTask { Task task ->",
|
||||
" if (task instanceof JavaForkOptions) {",
|
||||
" def jvmArgs = task.jvmArgs.findAll{!it?.startsWith('-agentlib:jdwp') && !it?.startsWith('-Xrunjdwp')}",
|
||||
" vmArgs << com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper.setupDebugger(task.path, " + debugPort + ")",
|
||||
" task.jvmArgs = jvmArgs",
|
||||
" }",
|
||||
"}",
|
||||
"gradle.taskGraph.afterTask { Task task ->",
|
||||
" if (task instanceof JavaForkOptions) {",
|
||||
" com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper.processFinished(task.path, " + debugPort + ")",
|
||||
" }",
|
||||
"}",
|
||||
};
|
||||
final String script = StringUtil.join(lines, SystemProperties.getLineSeparator());
|
||||
initScriptConsumer.consume(script);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enhanceRemoteProcessing(@NotNull SimpleJavaParameters parameters) throws ExecutionException {
|
||||
PathsList classPath = parameters.getClassPath();
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId;
|
||||
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener;
|
||||
import com.intellij.openapi.externalSystem.model.task.event.ExternalSystemProgressEventUnsupportedImpl;
|
||||
import com.intellij.openapi.externalSystem.model.task.event.ExternalSystemTaskExecutionEvent;
|
||||
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration;
|
||||
import com.intellij.openapi.externalSystem.task.ExternalSystemTaskManager;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
|
||||
import com.intellij.openapi.util.Key;
|
||||
@@ -85,6 +86,10 @@ public class GradleTaskManager implements ExternalSystemTaskManager<GradleExecut
|
||||
|
||||
GradleExecutionSettings effectiveSettings =
|
||||
settings == null ? new GradleExecutionSettings(null, null, DistributionType.BUNDLED, false) : settings;
|
||||
|
||||
if (getForkedDebuggerSetup(jvmAgentSetup) != -1) {
|
||||
effectiveSettings.withVmOption(jvmAgentSetup);
|
||||
}
|
||||
Function<ProjectConnection, Void> f = connection -> {
|
||||
try {
|
||||
appendInitScriptArgument(taskNames, jvmAgentSetup, effectiveSettings);
|
||||
@@ -127,6 +132,20 @@ public class GradleTaskManager implements ExternalSystemTaskManager<GradleExecut
|
||||
myHelper.execute(projectPath, effectiveSettings, f);
|
||||
}
|
||||
|
||||
public static int getForkedDebuggerSetup(@Nullable String jvmAgentSetup) {
|
||||
if (jvmAgentSetup != null && jvmAgentSetup.startsWith(ExternalSystemRunConfiguration.DEBUG_SETUP_PREFIX)) {
|
||||
int forkSocketIndex = jvmAgentSetup.indexOf("-forkSocket");
|
||||
if (forkSocketIndex > 0) {
|
||||
try {
|
||||
return Integer.parseInt(jvmAgentSetup.substring(forkSocketIndex + "-forkSocket".length()));
|
||||
}
|
||||
catch (NumberFormatException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static void appendInitScriptArgument(@NotNull List<String> taskNames,
|
||||
@Nullable String jvmAgentSetup,
|
||||
@NotNull GradleExecutionSettings effectiveSettings) {
|
||||
|
||||
Reference in New Issue
Block a user