Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support of setting the current working directory and environment variables. #3180

Merged
merged 1 commit into from Sep 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 10 additions & 1 deletion cpplite/cpplite.debugger/nbproject/project.xml
Expand Up @@ -60,13 +60,22 @@
<specification-version>1.59</specification-version>
</run-dependency>
</dependency>
<dependency>
<code-name-base>org.netbeans.modules.extexecution.base</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
<release-version>2</release-version>
<specification-version>1.20</specification-version>
</run-dependency>
</dependency>
<dependency>
<code-name-base>org.netbeans.modules.nativeimage.api</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
<release-version>0</release-version>
<specification-version>0.4</specification-version>
<specification-version>0.5</specification-version>
</run-dependency>
</dependency>
<dependency>
Expand Down
Expand Up @@ -50,6 +50,7 @@
import org.netbeans.api.debugger.DebuggerInfo;
import org.netbeans.api.debugger.DebuggerManager;
import org.netbeans.api.debugger.DebuggerManagerAdapter;
import org.netbeans.api.extexecution.base.ExplicitProcessParameters;
import org.netbeans.modules.cnd.debugger.gdb2.mi.MICommand;
import org.netbeans.modules.cnd.debugger.gdb2.mi.MICommandInjector;
import org.netbeans.modules.cnd.debugger.gdb2.mi.MIConst;
Expand All @@ -75,6 +76,7 @@
import org.openide.text.Annotatable;
import org.openide.text.Line;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.Pair;
import org.openide.util.RequestProcessor;

Expand Down Expand Up @@ -811,15 +813,20 @@ public Object[] getServices () {
CPPLiteDebugger debugger = es[0].lookupFirst(null, CPPLiteDebugger.class);
List<String> executable = new ArrayList<>();
executable.add(configuration.getDebugger());
executable.add("--interpreter=mi");
executable.add("--tty=" + pty.getSlaveName());
executable.add("--interpreter=mi"); // NOI18N
executable.add("--tty=" + pty.getSlaveName()); // NOI18N
if (configuration.isAttach()) {
executable.add("-p");
executable.add("-p"); // NOI18N
executable.add(Long.toString(configuration.getAttachProcessId()));
}
if (configuration.getExecutable().size() > 1) {
executable.add("--args"); // NOI18N
}
executable.addAll(configuration.getExecutable());
Process debuggee = new ProcessBuilder(executable).directory(configuration.getDirectory()).start();
new RequestProcessor(configuration.getDisplayName() + " (pty deallocator)").post(() -> {
ProcessBuilder processBuilder = new ProcessBuilder(executable);
setParameters(processBuilder, configuration);
Process debuggee = processBuilder.start();
new RequestProcessor(configuration.getDisplayName() + " (pty deallocator)").post(() -> { // NOI18N
try {
while (debuggee.isAlive()) {
try {
Expand Down Expand Up @@ -878,6 +885,25 @@ public void destroy() {
};
}

private static void setParameters(ProcessBuilder processBuilder, CPPLiteDebuggerConfig configuration) {
ExplicitProcessParameters processParameters = configuration.getProcessParameters();
if (processParameters.getWorkingDirectory() != null) {
processBuilder.directory(processParameters.getWorkingDirectory());
}
if (!processParameters.getEnvironmentVariables().isEmpty()) {
Map<String, String> environment = processBuilder.environment();
for (Map.Entry<String, String> entry : processParameters.getEnvironmentVariables().entrySet()) {
String env = entry.getKey();
String val = entry.getValue();
if (val != null) {
environment.put(env, val);
} else {
environment.remove(env);
}
}
}
}

private class BreakpointsHandler extends DebuggerManagerAdapter implements PropertyChangeListener {

private final Map<String, CPPLiteBreakpoint> breakpointsById = new ConcurrentHashMap<>();
Expand Down
Expand Up @@ -19,10 +19,12 @@

package org.netbeans.modules.cpplite.debugger;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.extexecution.base.ExplicitProcessParameters;
import org.openide.util.Exceptions;

/**
*
Expand All @@ -31,16 +33,33 @@
public final class CPPLiteDebuggerConfig {

private final List<String> executable;
private final File directory;
private final ExplicitProcessParameters processParameters;
@NullAllowed
private final Long processId;
private final String debugger;

public CPPLiteDebuggerConfig(List<String> executable, File directory, @NullAllowed Long processId, String debugger) {
this.executable = executable;
this.directory = directory;
public CPPLiteDebuggerConfig(List<String> executable, ExplicitProcessParameters processParameters, @NullAllowed Long processId, String debugger) {
this.processParameters = processParameters;
this.processId = processId;
this.debugger = debugger;
if (processParameters.isArgReplacement()) {
entlicher marked this conversation as resolved.
Show resolved Hide resolved
this.executable = new ArrayList<>();
this.executable.add(executable.get(0));
if (processParameters.getArguments() != null) {
this.executable.addAll(processParameters.getArguments());
}
} else {
if (processParameters.getArguments() != null) {
this.executable = new ArrayList<>();
this.executable.addAll(executable);
this.executable.addAll(processParameters.getArguments());
} else {
this.executable = executable;
}
}
if (processParameters.getLauncherArguments() != null) {
Exceptions.printStackTrace(new IllegalStateException("Launcher arguments " + processParameters.getLauncherArguments() + " can not be accepted by CPPLite debugger"));
}
}

public String getDisplayName() {
Expand All @@ -55,10 +74,10 @@ public List<String> getExecutable() {
}

/**
* Get the directory in which the executable command is to be launched.
* Get the parameters which the executable command is to be launched with.
*/
public File getDirectory() {
return directory;
public ExplicitProcessParameters getProcessParameters() {
return processParameters;
}

/**
Expand Down
Expand Up @@ -21,6 +21,7 @@
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.netbeans.api.extexecution.base.ExplicitProcessParameters;

import org.netbeans.modules.cpplite.debugger.CPPLiteDebugger;
import org.netbeans.modules.cpplite.debugger.CPPLiteDebuggerConfig;
Expand All @@ -38,8 +39,9 @@ public static Process startInDebugger(List<String> command) throws IOException {

public static Process startInDebugger(List<String> command, File directory) throws IOException {
CPPLiteDebugger[] debugger = new CPPLiteDebugger[] { null };
ExplicitProcessParameters processParameters = ExplicitProcessParameters.builder().workingDirectory(directory).build();
Process engineProcess = CPPLiteDebugger.startDebugging(
new CPPLiteDebuggerConfig(command, directory, null, "gdb"),
new CPPLiteDebuggerConfig(command, processParameters, null, "gdb"),
engine -> {
debugger[0] = engine.lookupFirst(null, CPPLiteDebugger.class);
});
Expand Down
Expand Up @@ -31,6 +31,7 @@
import org.netbeans.api.debugger.DebuggerEngine;
import org.netbeans.api.extexecution.ExecutionDescriptor;
import org.netbeans.api.extexecution.ExecutionService;
import org.netbeans.api.extexecution.base.ExplicitProcessParameters;
import org.netbeans.modules.cpplite.debugger.CPPFrame;
import org.netbeans.modules.cpplite.debugger.CPPLiteDebugger;
import org.netbeans.modules.cpplite.debugger.CPPLiteDebuggerConfig;
Expand All @@ -42,12 +43,14 @@
import org.netbeans.modules.nativeimage.api.debug.NIFrame;
import org.netbeans.modules.nativeimage.api.debug.NILineBreakpointDescriptor;
import org.netbeans.modules.nativeimage.api.debug.NIVariable;
import org.netbeans.modules.nativeimage.api.debug.StartDebugParameters;
import org.netbeans.modules.nativeimage.spi.debug.NIDebuggerProvider;
import org.netbeans.modules.nativeimage.spi.debug.filters.FrameDisplayer;

import org.openide.LifecycleManager;
import org.openide.util.RequestProcessor;
import org.netbeans.modules.nativeimage.spi.debug.filters.VariableDisplayer;
import org.openide.util.Lookup;

/**
*
Expand Down Expand Up @@ -85,10 +88,20 @@ public void setVariablesDisplayer(VariableDisplayer variablesDisplayer) {
}

@Override
public CompletableFuture<Void> start(List<String> command, File workingDirectory, String miDebugger, String displayName, ExecutionDescriptor executionDescriptor, Consumer<DebuggerEngine> startedEngine) {
public CompletableFuture<Void> start(StartDebugParameters debugParameters, Consumer<DebuggerEngine> startedEngine) {
if (debugger != null) {
throw new IllegalStateException("Debugger has started already.");
}
List<String> command = debugParameters.getCommand();
String miDebugger = debugParameters.getDebugger();
String displayName = debugParameters.getDisplayName();
ExecutionDescriptor executionDescriptor = debugParameters.getExecutionDescriptor();
Lookup contextLookup = debugParameters.getContextLookup();
ExplicitProcessParameters explicitParameters = contextLookup != null ? ExplicitProcessParameters.buildExplicitParameters(contextLookup) : null;
if (explicitParameters == null) {
explicitParameters = ExplicitProcessParameters.builder().workingDirectory(debugParameters.getWorkingDirectory()).build();
}
final ExplicitProcessParameters processParameters = explicitParameters;
if (executionDescriptor == null) {
executionDescriptor = new ExecutionDescriptor()
.showProgress(true)
Expand All @@ -104,7 +117,7 @@ public CompletableFuture<Void> start(List<String> command, File workingDirectory
try {
LifecycleManager.getDefault().saveAll();
engineProcess = CPPLiteDebugger.startDebugging(
new CPPLiteDebuggerConfig(command, workingDirectory, null, miDebugger),
new CPPLiteDebuggerConfig(command, processParameters, null, miDebugger),
engine -> {
debugger[0] = engine.lookupFirst(null, CPPLiteDebugger.class);
this.debugger = debugger[0];
Expand Down Expand Up @@ -147,10 +160,11 @@ public CompletableFuture<Void> attach(String executablePath, long processId, Str
if (debugger != null) {
throw new IllegalStateException("Debugger has started already.");
}
ExplicitProcessParameters processParameters = ExplicitProcessParameters.builder().workingDirectory(new File(System.getProperty("user.dir", ""))).build(); // NOI18N
CompletableFuture<Void> completed = new CompletableFuture<>();
try {
CPPLiteDebugger.startDebugging(
new CPPLiteDebuggerConfig(Collections.singletonList(executablePath), new File(System.getProperty("user.dir")), processId, miDebugger),
new CPPLiteDebuggerConfig(Collections.singletonList(executablePath), processParameters, processId, miDebugger),
engine -> {
CPPLiteDebugger debugger = engine.lookupFirst(null, CPPLiteDebugger.class);
this.debugger = debugger;
Expand Down
Expand Up @@ -18,21 +18,34 @@
*/
package org.netbeans.modules.cpplite.debugger;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import junit.framework.Test;

import org.netbeans.api.debugger.DebuggerEngine;
import org.netbeans.api.extexecution.base.ExplicitProcessParameters;
import org.netbeans.junit.NbModuleSuite;
import org.netbeans.junit.NbTestCase;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;

public abstract class AbstractDebugTest extends NbTestCase {

protected DebuggerEngine engine;
protected CPPLiteDebugger debugger;
protected Process process;
protected StringBuffer stdOut;
protected StringBuffer stdErr;

private final int[] suspendCount = new int[]{0};
private final int[] resumeCount = new int[]{0};
Expand All @@ -41,6 +54,14 @@ protected AbstractDebugTest(String s) {
super(s);
}

protected final static void createSourceFile(String fileName, File wd, String content) throws IOException {
FileObject source = FileUtil.createData(FileUtil.toFileObject(wd), "main.cpp");
try (OutputStream os = source.getOutputStream();
Writer w = new OutputStreamWriter(os)) {
w.append(content);
}
}

protected final static void compileC(String name, File wd) throws IOException, InterruptedException {
Process compile = new ProcessBuilder("gcc", "-o", name, "-g", name + ".c").directory(wd).start();
assertEquals(0, compile.waitFor());
Expand All @@ -52,9 +73,20 @@ protected final static void compileCPP(String name, File wd) throws IOException,
}

protected final void startDebugging(String name, File wd) throws IOException {
ExplicitProcessParameters processParameters = ExplicitProcessParameters.builder().workingDirectory(wd).build();
startDebugging(name, wd, processParameters);
}

protected final void startDebugging(String name, File wd, ExplicitProcessParameters processParameters) throws IOException {
startDebugging(Arrays.asList(new File(wd, name).getAbsolutePath()), processParameters);
}

protected final void startDebugging(List<String> executable, ExplicitProcessParameters processParameters) throws IOException {
this.process = CPPLiteDebugger.startDebugging(
new CPPLiteDebuggerConfig(Arrays.asList(new File(wd, name).getAbsolutePath()), wd, null, "gdb"),
new CPPLiteDebuggerConfig(executable, processParameters, null, "gdb"),
engine -> this.engine = engine);
stdOut = outputFrom(process.getInputStream());
stdErr = outputFrom(process.getErrorStream());
debugger = engine.lookupFirst(null, CPPLiteDebugger.class);
debugger.addStateListener(new CPPLiteDebugger.StateListener() {
@Override
Expand Down Expand Up @@ -120,4 +152,23 @@ protected final void assertStoppedAt(URI file, int line) {
public static Test suite() {
return NbModuleSuite.emptyConfiguration().gui(false).suite();
}

private static StringBuffer outputFrom(InputStream inputStream) {
StringBuffer buffer = new StringBuffer();
new Thread("Process output") {
@Override
public void run() {
try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = br.readLine()) != null) {
buffer.append(line);
buffer.append('\n');
}
} catch (IOException ex) {
buffer.append(ex);
}
}
}.start();
return buffer;
}
}