Skip to content
This repository has been archived by the owner on May 30, 2024. It is now read-only.

Stage rl/standard debug sockets #876

Merged
merged 21 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
86d3aa7
Standard debugging sockets initial implementation
stage-rl Oct 21, 2023
475a912
Unused imports cleanup
stage-rl Oct 21, 2023
2a4cc9c
Pick testing debuggee from rdbg output
stage-rl Oct 22, 2023
1b0c649
Run rdbg with bundle exec and format
stage-rl Nov 4, 2023
a481500
Update readme file to include rails debugging info
stage-rl Nov 4, 2023
2ef206d
Update readme file to include rails debugging info
stage-rl Nov 4, 2023
1cf5c89
Fixes based on PR review
stage-rl Nov 12, 2023
e13522a
Fixes and refactors based on PR review
stage-rl Nov 12, 2023
17c381b
Merge branch 'stage-rl/standard_debug_sockets' of https://github.com/…
stage-rl Nov 12, 2023
5da1664
Another readme.md correction (revert MD editor change)
stage-rl Nov 12, 2023
b557aee
README update for live processes debugging
stage-rl Nov 26, 2023
0a9bcf1
Merge remote-tracking branch 'upstream/main' into stage-rl/standard_d…
stage-rl Dec 10, 2023
3bcefe1
Migrate socket standardization changes to workspace branch
stage-rl Dec 10, 2023
32e7628
Fix formatting
stage-rl Dec 10, 2023
fdd44fd
Fix TS error
stage-rl Dec 12, 2023
b393f21
Merge remote-tracking branch 'upstream/main' into stage-rl/standard_d…
stage-rl Jan 17, 2024
f9be28e
Debugger merge manual
stage-rl Jan 17, 2024
1a24f1f
Merge remote-tracking branch 'upstream/main' into stage-rl/standard_d…
stage-rl Jan 17, 2024
d7a0d58
Revert readme list order to 1s only
stage-rl Jan 19, 2024
4f98bc0
Merge remote-tracking branch 'upstream/main' into stage-rl/standard_d…
stage-rl Jan 19, 2024
f22b8b3
Merge remote-tracking branch 'upstream/main' into stage-rl/standard_d…
stage-rl Jan 21, 2024
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
35 changes: 23 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,13 @@ documentation](https://shopify.github.io/ruby-lsp/RubyLsp/Requests.html).
Available commands are listed below and can always be found by searching for the `Ruby LSP` prefix in the command
palette (Default hotkey: CMD + SHIFT + P).

| Command | Description |
| ------------------------------------ | ------------------------------------------------------- |
| Ruby LSP: Start | Start the Ruby LSP server |
| Ruby LSP: Restart | Restart the Ruby LSP server |
| Ruby LSP: Stop | Stop the Ruby LSP server |
| Ruby LSP: Update language server gem | Updates the `ruby-lsp` server gem to the latest version |

| Command | Description |
| -------------------------------------- | -------------------------------------------------------- |
| Ruby LSP: Start | Start the Ruby LSP server |
| Ruby LSP: Restart | Restart the Ruby LSP server |
| Ruby LSP: Stop | Stop the Ruby LSP server |
| Ruby LSP: Update language server gem | Updates the`ruby-lsp` server gem to the latest version |
vinistock marked this conversation as resolved.
Show resolved Hide resolved

### Snippets

Expand Down Expand Up @@ -203,6 +204,16 @@ This command would generate the following configuration:
}
```

### Debugging rails applications
vinistock marked this conversation as resolved.
Show resolved Hide resolved

Install `debug` gem. Verify by running `bundle exec rdbg -v`
vinistock marked this conversation as resolved.
Show resolved Hide resolved

Make sure you're running your application with rdbg, e.g. `bundle exec rdbg -O -n -c -- bin/rails server -p 3000`
vinistock marked this conversation as resolved.
Show resolved Hide resolved

You should be able to use vscode debugger attach configuration to connect to your running app
vinistock marked this conversation as resolved.
Show resolved Hide resolved

For better integrated rails tests support also install `ruby-lsp-rails` gem
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
For better integrated rails tests support also install `ruby-lsp-rails` gem
For better integrated rails tests support also install `ruby-lsp-rails` gem.


#### VS Code configurations

In addition to the Ruby LSP's own configuration, there are some VS Code settings that may need to be changed to get the
Expand Down Expand Up @@ -340,12 +351,12 @@ Possible values are:
The `launch.json` contains a 'Minitest - current file' configuration for the debugger.

1. Add a breakpoint using the VS Code UI.
1. Open the relevant test file.
1. Open the **Run and Debug** panel on the sidebar.
1. Ensure `Minitest - current file` is selected in the top dropdown.
1. Press `F5` OR click the green triangle next to the top dropdown. VS Code will then run the test file with debugger activated.
1. When the breakpoint is triggered, the process will pause and VS Code will connect to the debugger and activate the debugger UI.
1. Open the Debug Console view to use the debugger's REPL.
2. Open the relevant test file.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) Leaving them all at 1. in the source makes it easier to add or remove steps, without having to renumber the others.

3. Open the **Run and Debug** panel on the sidebar.
4. Ensure `Minitest - current file` is selected in the top dropdown.
5. Press `F5` OR click the green triangle next to the top dropdown. VS Code will then run the test file with debugger activated.
6. When the breakpoint is triggered, the process will pause and VS Code will connect to the debugger and activate the debugger UI.
7. Open the Debug Console view to use the debugger's REPL.

## License

Expand Down
98 changes: 40 additions & 58 deletions src/debugger.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from "path";
import fs from "fs";
import { ChildProcessWithoutNullStreams, spawn } from "child_process";
import { ChildProcessWithoutNullStreams, spawn, execSync } from "child_process";

import * as vscode from "vscode";

Expand Down Expand Up @@ -121,41 +121,44 @@ export class Debugger
this.subscriptions.forEach((subscription) => subscription.dispose());
}

private getSockets(): string[] {
Copy link
Member

@st0012 st0012 Dec 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When getting sockets, we should take users' launch.json configuration into account, especially the env. When users specifying things like RUBY_DEBUG_SOCK_DIR when starting the debuggee process, the rdbg --util=list-socks call needs to have the same value or it wouldn't find anything.

The vscode-rdbg extension takes the configuration into account so it supports the above use case.

(*The current implementation doesn't need this because it doesn't invoke the rdbg executable)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notice that this information has to be read from the Ruby object for the current workspace as we do here, which contains the activated environment.

const cmd = "bundle exec rdbg --util=list-socks";
let sockets: string[] = [];
try {
sockets = execSync(cmd)
.toString()
.split("\n")
.filter((socket) => socket.length > 0);
} catch (error: any) {
this.console.append(error.message);
}
return sockets;
vinistock marked this conversation as resolved.
Show resolved Hide resolved
}

private attachDebuggee(): Promise<vscode.DebugAdapterDescriptor | undefined> {
// When using attach, a process will be launched using Ruby debug and it will create a socket automatically. We have
// to find the available sockets and ask the user which one they want to attach to
const socketsDir = path.join("/", "tmp", "ruby-lsp-debug-sockets");
const sockets = fs
.readdirSync(socketsDir)
.map((file) => file)
.filter((file) => file.endsWith(".sock"));

// eslint-disable-next-line @typescript-eslint/no-misused-promises
return new Promise((resolve, reject) => {
const sockets = this.getSockets();
if (sockets.length === 0) {
reject(
new Error(
`No debuggee processes found. Was a socket created in ${socketsDir}?`,
),
);
}

return vscode.window
.showQuickPick(sockets, {
placeHolder: "Select a debuggee",
ignoreFocusOut: true,
})
.then((selectedSocket) => {
if (selectedSocket === undefined) {
reject(new Error("No debuggee selected"));
} else {
resolve(
new vscode.DebugAdapterNamedPipeServer(
path.join(socketsDir, selectedSocket),
),
);
}
});
reject(new Error(`No debuggee processes found.`));
} else if (sockets.length === 1)
resolve(new vscode.DebugAdapterNamedPipeServer(sockets[0]));
else
vinistock marked this conversation as resolved.
Show resolved Hide resolved
return vscode.window
.showQuickPick(sockets, {
placeHolder: "Select a debuggee",
ignoreFocusOut: true,
})
.then((selectedSocket) => {
if (selectedSocket === undefined) {
reject(new Error("No debuggee selected"));
} else {
resolve(new vscode.DebugAdapterNamedPipeServer(selectedSocket));
}
});
});
}

Expand All @@ -164,7 +167,6 @@ export class Debugger
): Promise<vscode.DebugAdapterDescriptor | undefined> {
let initialMessage = "";
let initialized = false;
const sockPath = this.socketPath();
const configuration = session.configuration;

return new Promise((resolve, reject) => {
Expand All @@ -173,7 +175,6 @@ export class Debugger
"rdbg",
"--open",
"--command",
`--sock-path=${sockPath}`,
st0012 marked this conversation as resolved.
Show resolved Hide resolved
"--",
configuration.program,
];
Expand Down Expand Up @@ -209,7 +210,14 @@ export class Debugger
initialMessage.includes("DEBUGGER: wait for debugger connection...")
) {
initialized = true;
resolve(new vscode.DebugAdapterNamedPipeServer(sockPath));
const regex =
/DEBUGGER: Debugger can attach via UNIX domain socket \((.*)\)/;
const sockPath = RegExp(regex).exec(initialMessage);
if (sockPath && sockPath.length === 2) {
resolve(new vscode.DebugAdapterNamedPipeServer(sockPath[1]));
} else {
reject(new Error("Debugger not found on UNIX socket"));
}
Comment on lines +231 to +238
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is not necessary if we keep our standard socket path for launch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the previous one.

The point is that we maybe don't want to hardcode those sockets and want to let rdbg decide. We then extract them from debugger output. The implementation provided handles both ends, see your other comment.

}
});

Expand Down Expand Up @@ -237,30 +245,4 @@ export class Debugger
});
});
}

// Generate a socket path so that Ruby debug doesn't have to create one for us. This makes coordination easier since
// we always know the path to the socket
private socketPath() {
const socketsDir = path.join("/", "tmp", "ruby-lsp-debug-sockets");
if (!fs.existsSync(socketsDir)) {
fs.mkdirSync(socketsDir);
}

let socketIndex = 0;
const prefix = `ruby-debug-${path.basename(this.workingFolder)}`;
const existingSockets = fs
.readdirSync(socketsDir)
.map((file) => file)
.filter((file) => file.startsWith(prefix))
.sort();

if (existingSockets.length > 0) {
socketIndex =
Number(
/-(\d+).sock$/.exec(existingSockets[existingSockets.length - 1])![1],
) + 1;
}

return `${socketsDir}/${prefix}-${socketIndex}.sock`;
}
}
Loading