Author: Roy Shi Date: 2025-09-23T07:44:50-07:00 New Revision: 6007a4dbed2d8867c75bd571e1eb38e10ae14a27
URL: https://github.com/llvm/llvm-project/commit/6007a4dbed2d8867c75bd571e1eb38e10ae14a27 DIFF: https://github.com/llvm/llvm-project/commit/6007a4dbed2d8867c75bd571e1eb38e10ae14a27.diff LOG: [vscode-lldb] Restart server when lldb-dap binary has changed (#159797) # Motiviation This helps the development of the lldb-dap binary. For example, when testing a locally built lldb-dap binary, one probably wants to restart the server after each build in order to use the latest binary. Not doing so leads to confusion like "why the new lldb-dap isn't doing what I just changed?". This patch adds dependency to the `chokidar` package. The reason is that we need something to detect changes to the `lldb-dap` binary file and `chokidar` appears to be the most reliable package to do so. An alternative solution which doesn't require adding dependencies is discussed below (solution 1). # Two different solutions considered Solution 1: Restart server when lldb-dap binary's modification time changes. https://github.com/llvm/llvm-project/pull/159481 implements solution 1. Solution 2: Restart server when lldb-dap binary has changed (as detected by a file system watcher). This patch implements solution 2 (using `chokidar`). # This patch (solution 2) If the lldb-dap binary has changed, the next time the user start a debug session, a dialog box will show up and prompt the user to restart the server. Depend on what has changed, the dialog box will show different content (see below) * When both the lldb-dap binary and the arguments have changed: <img width="520" height="357" alt="diff_args_and_binary" src="https://github.com/user-attachments/assets/6580e05f-05c3-4d80-8c1a-9c3abf279218" /> * When only the lldb-dap binary has changed: <img width="260" height="384" alt="diff_binary" src="https://github.com/user-attachments/assets/933b8987-9c21-44f3-ad68-57b8eeb58525" /> * When only the arguments have changed (existing): <img width="520" height="343" alt="diff_args" src="https://github.com/user-attachments/assets/c0e6771c-ad32-4fb8-b5df-b34cce48ed1a" /> Added: Modified: lldb/tools/lldb-dap/package-lock.json lldb/tools/lldb-dap/package.json lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/package-lock.json b/lldb/tools/lldb-dap/package-lock.json index f3ae6b76be6d0..826f29f70106c 100644 --- a/lldb/tools/lldb-dap/package-lock.json +++ b/lldb/tools/lldb-dap/package-lock.json @@ -8,6 +8,9 @@ "name": "lldb-dap", "version": "0.2.16", "license": "Apache 2.0 License with LLVM exceptions", + "dependencies": { + "chokidar": "^4.0.3" + }, "devDependencies": { "@types/node": "^18.19.41", "@types/tabulator-tables": "^6.2.10", @@ -1301,6 +1304,21 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", @@ -2746,6 +2764,19 @@ "node": ">= 6" } }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index 6566ba3bdee13..3892535853f56 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -27,6 +27,9 @@ "categories": [ "Debuggers" ], + "dependencies": { + "chokidar": "^4.0.3" + }, "devDependencies": { "@types/node": "^18.19.41", "@types/tabulator-tables": "^6.2.10", diff --git a/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts b/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts index 280a11d807f6a..4e348965930d9 100644 --- a/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts +++ b/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts @@ -1,4 +1,6 @@ +import { FSWatcher, watch as chokidarWatch } from 'chokidar'; import * as child_process from "node:child_process"; +import * as path from "path"; import { isDeepStrictEqual } from "util"; import * as vscode from "vscode"; @@ -12,6 +14,10 @@ export class LLDBDapServer implements vscode.Disposable { private serverProcess?: child_process.ChildProcessWithoutNullStreams; private serverInfo?: Promise<{ host: string; port: number }>; private serverSpawnInfo?: string[]; + // Detects changes to the lldb-dap executable file since the server's startup. + private serverFileWatcher?: FSWatcher; + // Indicates whether the lldb-dap executable file has changed since the server's startup. + private serverFileChanged?: boolean; constructor() { vscode.commands.registerCommand( @@ -83,6 +89,11 @@ export class LLDBDapServer implements vscode.Disposable { }); this.serverProcess = process; this.serverSpawnInfo = this.getSpawnInfo(dapPath, dapArgs, options?.env); + this.serverFileChanged = false; + this.serverFileWatcher = chokidarWatch(dapPath); + this.serverFileWatcher + .on('change', () => this.serverFileChanged = true) + .on('unlink', () => this.serverFileChanged = true); }); return this.serverInfo; } @@ -100,21 +111,27 @@ export class LLDBDapServer implements vscode.Disposable { args: string[], env: NodeJS.ProcessEnv | { [key: string]: string } | undefined, ): Promise<boolean> { - if (!this.serverProcess || !this.serverInfo || !this.serverSpawnInfo) { + if ( + !this.serverProcess || + !this.serverInfo || + !this.serverSpawnInfo || + !this.serverFileWatcher || + this.serverFileChanged === undefined + ) { return true; } - const newSpawnInfo = this.getSpawnInfo(dapPath, args, env); - if (isDeepStrictEqual(this.serverSpawnInfo, newSpawnInfo)) { - return true; - } + const changeTLDR = []; + const changeDetails = []; - const userInput = await vscode.window.showInformationMessage( - "The arguments to lldb-dap have changed. Would you like to restart the server?", - { - modal: true, - detail: `An existing lldb-dap server (${this.serverProcess.pid}) is running with diff erent arguments. + if (this.serverFileChanged) { + changeTLDR.push("an old binary"); + } + const newSpawnInfo = this.getSpawnInfo(dapPath, args, env); + if (!isDeepStrictEqual(this.serverSpawnInfo, newSpawnInfo)) { + changeTLDR.push(" diff erent arguments"); + changeDetails.push(` The previous lldb-dap server was started with: ${this.serverSpawnInfo.join(" ")} @@ -122,7 +139,22 @@ ${this.serverSpawnInfo.join(" ")} The new lldb-dap server will be started with: ${newSpawnInfo.join(" ")} +` + ); + } + + // If the server hasn't changed, continue startup without killing it. + if (changeTLDR.length === 0) { + return true; + } + // The server has changed. Prompt the user to restart it. + const userInput = await vscode.window.showInformationMessage( + "The lldb-dap server has changed. Would you like to restart the server?", + { + modal: true, + detail: `An existing lldb-dap server (${this.serverProcess.pid}) is running with ${changeTLDR.map(s => `*${s}*`).join(" and ")}. +${changeDetails.join("\n")} Restarting the server will interrupt any existing debug sessions and start a new server.`, }, "Restart", @@ -130,9 +162,7 @@ Restarting the server will interrupt any existing debug sessions and start a new ); switch (userInput) { case "Restart": - this.serverProcess.kill(); - this.serverProcess = undefined; - this.serverInfo = undefined; + this.dispose(); return true; case "Use Existing": return true; @@ -156,6 +186,10 @@ Restarting the server will interrupt any existing debug sessions and start a new if (this.serverProcess === process) { this.serverProcess = undefined; this.serverInfo = undefined; + this.serverSpawnInfo = undefined; + this.serverFileWatcher?.close(); + this.serverFileWatcher = undefined; + this.serverFileChanged = undefined; } } _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits