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

feat(clion): Add working directory to CLion Run configurations #6698

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}
}
36 changes: 26 additions & 10 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 @@ -99,6 +102,7 @@ public final class BlazeCidrLauncher extends CidrLauncher {
this.handlerState = (BlazeCidrRunConfigState) configuration.getHandler().getState();
this.runner = runner;
this.env = env;

this.project = configuration.getProject();
}

Expand Down Expand Up @@ -212,6 +216,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 @@ -225,17 +246,12 @@ public CidrDebugProcess createDebugProcess(CommandLineState state, XDebugSession
EventLoggingService.getInstance().logEvent(getClass(), "debugging-cpp");

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

final var debuggerKind = RunConfigurationUtils.getDebuggerKind(configuration);
if (debuggerKind != BlazeDebuggerKind.GDB_SERVER) {

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 @@ -249,9 +265,9 @@ public CidrDebugProcess createDebugProcess(CommandLineState state, XDebugSession

final DebuggerDriverConfiguration debuggerDriver;
if (debuggerKind == BlazeDebuggerKind.BUNDLED_LLDB) {
debuggerDriver = new BlazeLLDBDriverConfiguration(project, workspaceRoot.directory().toPath());
debuggerDriver = new BlazeLLDBDriverConfiguration(project, workspaceRoot);
} else {
final var startupCommands = getGdbStartupCommands(workspaceRootDirectory);
final var startupCommands = getGdbStartupCommands(workspaceRoot.directory());
debuggerDriver = new BlazeGDBDriverConfiguration(project, startupCommands, workspaceRoot);
}

Expand All @@ -277,7 +293,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;
}
}