Skip to content

Commit

Permalink
feat(clion): Add working directory to CLion Run configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
Borja Lorente committed Jun 2, 2023
1 parent a65a9a3 commit f9c0391
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package com.google.idea.blaze.base.run.state;

import com.google.common.base.Strings;
import com.google.idea.blaze.base.ui.UiUtil;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.LabeledComponent;
import com.intellij.openapi.ui.TextBrowseFolderListener;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import java.nio.file.Path;
import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.swing.JComponent;
import org.jdom.Element;

/**
* State to enable setting a Working Directory for run configurations. Currently, it's only
* supported for CLion debug runs. When every debugger supports it, it can be moved into the general
* {@link RunConfigurationState}.
*/
public class WorkingDirectoryState implements RunConfigurationState {

private static final String WORKING_DIRECTORY_ATTR = "working-directory";

@Nullable
private Optional<Path> workingDirectory = Optional.empty();

@Nullable
public Optional<Path> getWorkingDirectory() {
return workingDirectory;
}

public void setWorkingDirectory(@Nullable String workingDirectory) {
if (!Strings.isNullOrEmpty(workingDirectory)) {
this.workingDirectory = Optional.of(Path.of(workingDirectory));
}
}

@Override
public void readExternal(Element element) throws InvalidDataException {
String attr = element.getAttributeValue(WORKING_DIRECTORY_ATTR);
if (Strings.isNullOrEmpty(attr)) {
workingDirectory = Optional.empty();
} else {
workingDirectory = Optional.of(Path.of(element.getAttributeValue(WORKING_DIRECTORY_ATTR)));
}
}

@Override
public void writeExternal(Element element) throws WriteExternalException {
if (workingDirectory.isEmpty()) {
element.removeAttribute(WORKING_DIRECTORY_ATTR);
} else {
element.setAttribute(WORKING_DIRECTORY_ATTR, workingDirectory.get().toString());
}
}

@Override
public RunConfigurationStateEditor getEditor(Project project) {
return new WorkingDirectoryStateEditor();
}

private static class WorkingDirectoryStateEditor implements RunConfigurationStateEditor {

private final TextFieldWithBrowseButton component = new TextFieldWithBrowseButton();

@Override
public void resetEditorFrom(RunConfigurationState genericState) {
WorkingDirectoryState state = (WorkingDirectoryState) genericState;
component.setText(state.getWorkingDirectory().map(Path::toString).orElse(""));
}

@Override
public void applyEditorTo(RunConfigurationState genericState) {
WorkingDirectoryState state = (WorkingDirectoryState) genericState;
state.setWorkingDirectory(component.getText());
}

@Override
public JComponent createComponent() {
LabeledComponent withLabel = new LabeledComponent<TextFieldWithBrowseButton>();
withLabel.setText("Working directory (only set when debugging):");
component.addBrowseFolderListener(new TextBrowseFolderListener(
FileChooserDescriptorFactory.createSingleFolderDescriptor()));
withLabel.setComponent(component);
return UiUtil.createBox(withLabel);
}

@Override
public void setComponentEnabled(boolean enabled) {
component.setEnabled(enabled);
}
}
}
41 changes: 30 additions & 11 deletions clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrLauncher.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,12 @@
import com.jetbrains.cidr.execution.debugger.remote.CidrRemotePathMapping;
import com.jetbrains.cidr.execution.testing.google.CidrGoogleTestConsoleProperties;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;

/**
* Handles running/debugging cc_test and cc_binary targets in CLion. Sets up gdb when debugging, and
Expand All @@ -94,11 +97,13 @@ public final class BlazeCidrLauncher extends CidrLauncher {
BlazeCidrLauncher(
BlazeCommandRunConfiguration configuration,
BlazeCidrRunConfigurationRunner runner,
ExecutionEnvironment env) {
ExecutionEnvironment env
) {
this.configuration = configuration;
this.handlerState = (BlazeCidrRunConfigState) configuration.getHandler().getState();
this.runner = runner;
this.env = env;

this.project = configuration.getProject();
}

Expand Down Expand Up @@ -205,6 +210,23 @@ public ImmutableList<ProcessListener> createProcessListeners(BlazeContext contex
});
}

@NotNull
private File selectWorkingDir(@Nonnull Optional<Path> runConfigWorkingDir,
File workspaceRootDirectory) {
if (runConfigWorkingDir.isPresent()) {
return runConfigWorkingDir.get().toFile();
}

File workingDir =
new File(runner.executableToDebug + ".runfiles", workspaceRootDirectory.getName());

if (workingDir.exists()) {
return workingDir;
}

return workspaceRootDirectory;
}

@Override
public CidrDebugProcess createDebugProcess(CommandLineState state, XDebugSession session)
throws ExecutionException {
Expand All @@ -218,16 +240,11 @@ public CidrDebugProcess createDebugProcess(CommandLineState state, XDebugSession
EventLoggingService.getInstance().logEvent(getClass(), "debugging-cpp");

WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
File workspaceRootDirectory = workspaceRoot.directory();

if (!BlazeGDBServerProvider.shouldUseGdbserver()) {

File workingDir =
new File(runner.executableToDebug + ".runfiles", workspaceRootDirectory.getName());

if (!workingDir.exists()) {
workingDir = workspaceRootDirectory;
}
Optional<Path> runConfigWorkingDir = handlerState.getWorkingDirState().getWorkingDirectory();
File workingDir = selectWorkingDir(runConfigWorkingDir, workspaceRoot.directory());

GeneralCommandLine commandLine =
new GeneralCommandLine(runner.executableToDebug.getPath()).withWorkDirectory(workingDir);
Expand All @@ -245,11 +262,13 @@ public CidrDebugProcess createDebugProcess(CommandLineState state, XDebugSession
}

TrivialInstaller installer = new TrivialInstaller(commandLine);
ImmutableList<String> startupCommands = getGdbStartupCommands(workspaceRootDirectory);
ImmutableList<String> startupCommands = getGdbStartupCommands(workspaceRoot.directory());
TrivialRunParameters parameters =
new TrivialRunParameters(
ToolchainUtils.getToolchain().getDebuggerKind() == Kind.BUNDLED_LLDB
? new BlazeLLDBDriverConfiguration(project, workspaceRoot.directory().toPath())
// Note that these have to be set to the workspace root (as opposed to the working dir),
// since it's where we'll start the actual debugger.
? new BlazeLLDBDriverConfiguration(project, workspaceRoot)
: new BlazeGDBDriverConfiguration(project, startupCommands, workspaceRoot),
installer);

Expand All @@ -273,7 +292,7 @@ public CidrDebugProcess createDebugProcess(CommandLineState state, XDebugSession
runner.executableToDebug.getPath(),
"target:",
ImmutableList.of(
new CidrRemotePathMapping("/proc/self/cwd", workspaceRootDirectory.getParent())));
new CidrRemotePathMapping("/proc/self/cwd", workspaceRoot.directory().getParent())));

BlazeCLionGDBDriverConfiguration debuggerDriverConfiguration =
new BlazeCLionGDBDriverConfiguration(project);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@
import com.google.idea.blaze.base.run.state.DebugPortState;
import com.google.idea.blaze.base.run.state.EnvironmentVariablesState;
import com.google.idea.blaze.base.run.state.RunConfigurationState;
import com.google.idea.blaze.base.run.state.WorkingDirectoryState;
import com.google.idea.blaze.base.settings.BuildSystemName;

/** A version of the common state allowing environment variables to be set when debugging. */
final class BlazeCidrRunConfigState extends BlazeCommandRunConfigurationCommonState {
private static final int DEFAULT_DEBUG_PORT = 5006;

private final EnvironmentVariablesState envVars = new EnvironmentVariablesState();

private final WorkingDirectoryState workingDir = new WorkingDirectoryState();
private final DebugPortState debugPortState = new DebugPortState(DEFAULT_DEBUG_PORT);

BlazeCidrRunConfigState(BuildSystemName buildSystemName) {
Expand All @@ -35,13 +38,17 @@ final class BlazeCidrRunConfigState extends BlazeCommandRunConfigurationCommonSt

@Override
protected ImmutableList<RunConfigurationState> initializeStates() {
return ImmutableList.of(command, blazeFlags, exeFlags, envVars, debugPortState, blazeBinary);
return ImmutableList.of(command, blazeFlags, exeFlags, envVars, workingDir, debugPortState, blazeBinary);
}

EnvironmentVariablesState getEnvVarsState() {
return envVars;
}

public WorkingDirectoryState getWorkingDirState() {
return workingDir;
}

DebugPortState getDebugPortState() {
return debugPortState;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.google.idea.blaze.clwb.run;

import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.clwb.ToolchainUtils;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
Expand All @@ -9,21 +10,19 @@
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriver;
import org.jetbrains.annotations.NotNull;

import java.nio.file.Path;

public class BlazeLLDBDriverConfiguration extends CLionLLDBDriverConfiguration {
private final Path workingDirectory;
private final WorkspaceRoot workspaceRoot;

public BlazeLLDBDriverConfiguration(@NotNull Project project, Path workingDirectory) {
public BlazeLLDBDriverConfiguration(@NotNull Project project, WorkspaceRoot workspaceRoot) {
super(project, ToolchainUtils.getToolchain());
this.workingDirectory = workingDirectory;
this.workspaceRoot = workspaceRoot;
}

@NotNull
@Override
public GeneralCommandLine createDriverCommandLine(@NotNull DebuggerDriver driver, @NotNull ArchitectureType architectureType) throws ExecutionException {
GeneralCommandLine commandLine = super.createDriverCommandLine(driver, architectureType);
commandLine.setWorkDirectory(this.workingDirectory.toFile());
commandLine.setWorkDirectory(this.workspaceRoot.directory());
return commandLine;
}
}

0 comments on commit f9c0391

Please sign in to comment.