src/debugAdapter2: remove thin adapter for dlv-dap
We now invoke dlv-dap directly and connect to it as a server,
so the thin adapter is no longer needed. Dlv-dap now directly
handles any requests.
Fixes golang/vscode-go#822
Fixes golang/vscode-go#844
Updates golang/vscode-go#1111
Change-Id: I9aeb8edd71966b7c1d0a5cc38dc157a267aad844
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/290449
Trust: Suzy Mueller <suzmue@golang.org>
Trust: Hyang-Ah Hana Kim <hyangah@gmail.com>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/.vscode/launch.json b/.vscode/launch.json
index e7e3d55..25075bc 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -39,22 +39,6 @@
"preLaunchTask": "npm: webpack"
},
{
- "name": "Launch as server (dlv dap)",
- "type": "node",
- "protocol": "inspector",
- "request": "launch",
- "program": "${workspaceFolder}/dist/debugAdapter2.js",
- "args": [
- "--server=4711"
- ],
- "sourceMaps": true,
- "smartStep": true,
- "outFiles": [
- "${workspaceFolder}/dist/**/*.js"
- ],
- "preLaunchTask": "npm: webpack"
- },
- {
"name": "Launch Extension Tests",
"type": "extensionHost",
"request": "launch",
diff --git a/package.json b/package.json
index 96d7f67..5fad5f5 100644
--- a/package.json
+++ b/package.json
@@ -891,7 +891,6 @@
{
"type": "godlvdap",
"label": "Go Dlv Dap (Experimental)",
- "runtime": "node",
"languages": [
"go"
],
diff --git a/src/debugAdapter2/README.md b/src/debugAdapter2/README.md
deleted file mode 100644
index f0ca4fb..0000000
--- a/src/debugAdapter2/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# Debug Adapter
-
-This debug adapter is experimental, in-development code. If you
-actually need to debug Go code, please use the default adapter ("type": "go").
-
-See the [contribution documentation](../../docs/contributing.md) to learn how to develop the debug adapter.
diff --git a/src/debugAdapter2/dapClient.ts b/src/debugAdapter2/dapClient.ts
deleted file mode 100644
index 14d38a0..0000000
--- a/src/debugAdapter2/dapClient.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-/*---------------------------------------------------------
- * Copyright 2020 The Go Authors. All rights reserved.
- * Licensed under the MIT License. See LICENSE in the project root for license information.
- *--------------------------------------------------------*/
-import { EventEmitter } from 'events';
-import stream = require('stream');
-
-import { DebugProtocol } from 'vscode-debugprotocol';
-
-// DapClient implements a simple client for the DAP protocol.
-// It's initialized with a pair of streams that the caller creats and enables
-// sending and receiving DAP messages over these streams.
-// After calling connect():
-//
-// - For sending messages call send().
-// - For receiving messages, subscibe to events this class emits.
-// - 'event', 'respones', 'request' - each carrying an appropriate
-// DebugProtocol type as an argument.
-export class DAPClient extends EventEmitter {
- private static readonly TWO_CRLF = '\r\n\r\n';
-
- private outputStream: stream.Writable;
-
- private rawData = Buffer.alloc(0);
- private contentLength: number = -1;
-
- constructor() {
- super();
- }
-
- public send(req: any): void {
- const json = JSON.stringify(req);
- this.outputStream.write(`Content-Length: ${Buffer.byteLength(json, 'utf8')}\r\n\r\n${json}`, 'utf8');
- }
-
- // Connect this client to a server, which is represented by read and write
- // streams. Before this method is called, send() won't work and no messages
- // from the server will be delivered.
- protected connect(readable: stream.Readable, writable: stream.Writable): void {
- this.outputStream = writable;
-
- readable.on('data', (data: Buffer) => {
- this.handleData(data);
- });
- }
-
- // Implements parsing of the DAP protocol. We cannot use ProtocolClient
- // from the vscode-debugadapter package, because it's not exported and
- // is not meant for external usage.
- // See https://github.com/microsoft/vscode-debugadapter-node/issues/232
- private handleData(data: Buffer): void {
- this.rawData = Buffer.concat([this.rawData, data]);
-
- while (true) {
- if (this.contentLength >= 0) {
- if (this.rawData.length >= this.contentLength) {
- const message = this.rawData.toString('utf8', 0, this.contentLength);
- this.rawData = this.rawData.slice(this.contentLength);
- this.contentLength = -1;
- if (message.length > 0) {
- this.dispatch(message);
- }
- continue; // there may be more complete messages to process
- }
- } else {
- const idx = this.rawData.indexOf(DAPClient.TWO_CRLF);
- if (idx !== -1) {
- const header = this.rawData.toString('utf8', 0, idx);
- const lines = header.split('\r\n');
- for (const line of lines) {
- const pair = line.split(/: +/);
- if (pair[0] === 'Content-Length') {
- this.contentLength = +pair[1];
- }
- }
- this.rawData = this.rawData.slice(idx + DAPClient.TWO_CRLF.length);
- continue;
- }
- }
- break;
- }
- }
-
- private dispatch(body: string): void {
- const rawData = JSON.parse(body);
-
- if (rawData.type === 'event') {
- const event = <DebugProtocol.Event>rawData;
- this.emit('event', event);
- } else if (rawData.type === 'response') {
- const response = <DebugProtocol.Response>rawData;
- this.emit('response', response);
- } else if (rawData.type === 'request') {
- const request = <DebugProtocol.Request>rawData;
- this.emit('request', request);
- } else {
- throw new Error(`unknown message ${JSON.stringify(rawData)}`);
- }
- }
-}
diff --git a/src/debugAdapter2/goDlvDebug.ts b/src/debugAdapter2/goDlvDebug.ts
deleted file mode 100644
index 0226492..0000000
--- a/src/debugAdapter2/goDlvDebug.ts
+++ /dev/null
@@ -1,791 +0,0 @@
-/*---------------------------------------------------------
- * Copyright 2020 The Go Authors. All rights reserved.
- * Licensed under the MIT License. See LICENSE in the project root for license information.
- *--------------------------------------------------------*/
-
-// NOTE: This debug adapter is experimental, in-development code. If you
-// actually need to debug Go code, please use the default adapter.
-
-import { ChildProcess, spawn } from 'child_process';
-import * as fs from 'fs';
-import net = require('net');
-import * as os from 'os';
-import * as path from 'path';
-import { DebugConfiguration } from 'vscode';
-
-import {
- logger,
- Logger,
- LoggingDebugSession,
- OutputEvent,
- TerminatedEvent
-} from 'vscode-debugadapter';
-import { DebugProtocol } from 'vscode-debugprotocol';
-import { envPath, expandFilePathInOutput, getBinPathWithPreferredGopathGoroot } from '../utils/pathUtils';
-import { killProcessTree } from '../utils/processUtils';
-
-import { DAPClient } from './dapClient';
-
-interface LoadConfig {
- // FollowPointers requests pointers to be automatically dereferenced.
- followPointers: boolean;
- // MaxVariableRecurse is how far to recurse when evaluating nested types.
- maxVariableRecurse: number;
- // MaxStringLen is the maximum number of bytes read from a string
- maxStringLen: number;
- // MaxArrayValues is the maximum number of elements read from an array, a slice or a map.
- maxArrayValues: number;
- // MaxStructFields is the maximum number of fields read from a struct, -1 will read all fields.
- maxStructFields: number;
-}
-
-// This interface should always match the schema found in `package.json`.
-export interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArguments {
- type: string;
- name: string;
- request: 'launch';
- [key: string]: any;
- program: string;
- stopOnEntry?: boolean;
- dlvFlags?: string[];
- args?: string[];
- showLog?: boolean;
- logOutput?: string;
- cwd?: string;
- env?: { [key: string]: string };
- mode?: 'auto' | 'debug' | 'remote' | 'test' | 'exec';
- remotePath?: string;
- port?: number;
- host?: string;
- buildFlags?: string;
- init?: string;
- trace?: 'verbose' | 'log' | 'error';
- backend?: string;
- output?: string;
- /** Delve LoadConfig parameters */
- dlvLoadConfig?: LoadConfig;
- dlvToolPath: string;
- /** Delve Version */
- apiVersion: number;
- /** Delve maximum stack trace depth */
- stackTraceDepth: number;
-
- showGlobalVariables?: boolean;
- packagePathToGoModPathMap: { [key: string]: string };
-}
-
-interface AttachRequestArguments extends DebugProtocol.AttachRequestArguments {
- request: 'attach';
- processId?: number;
- stopOnEntry?: boolean;
- showLog?: boolean;
- logOutput?: string;
- cwd?: string;
- mode?: 'local' | 'remote';
- remotePath?: string;
- port?: number;
- host?: string;
- trace?: 'verbose' | 'log' | 'error';
- backend?: string;
- /** Delve LoadConfig parameters */
- dlvLoadConfig?: LoadConfig;
- dlvToolPath: string;
- /** Delve Version */
- apiVersion: number;
- /** Delve maximum stack trace depth */
- stackTraceDepth: number;
-
- showGlobalVariables?: boolean;
-}
-
-function logArgsToString(args: any[]): string {
- return args
- .map((arg) => {
- return typeof arg === 'string' ? arg : JSON.stringify(arg);
- })
- .join(' ');
-}
-
-function log(...args: any[]) {
- logger.warn(logArgsToString(args));
-}
-
-function logError(...args: any[]) {
- logger.error(logArgsToString(args));
-}
-
-// GoDlvDapDebugSession implements a DAP debug adapter to talk to the editor.
-//
-// This adapter serves as a DAP proxy between the editor and the DAP server
-// inside Delve. It relies on functionality inherited from DebugSession to
-// implement the server side interfacing the editor, and on DapClient to
-// implement the client side interfacing Delve:
-//
-// Editor GoDlvDapDebugSession Delve
-// +------------+ +--------------+-----------+ +------------+
-// | DAP Client | <====> | DebugSession | DAPClient | <====> | DAP Server |
-// +------------+ +--------------+-----------+ +------------+
-export class GoDlvDapDebugSession extends LoggingDebugSession {
- private readonly DEFAULT_DELVE_HOST = '127.0.0.1';
- private readonly DEFAULT_DELVE_PORT = 42042;
-
- private logLevel: Logger.LogLevel = Logger.LogLevel.Error;
-
- private dlvClient: DelveClient = null;
-
- // Child process used to track debugee launched without debugging (noDebug
- // mode). Either debugProcess or dlvClient are null.
- private debugProcess: ChildProcess = null;
-
- public constructor() {
- super();
-
- // Invoke logger.init here because we want logging to work in 'inline'
- // DA mode. It's typically called in the start() method of our parent
- // class, but this method isn't called in 'inline' mode.
- logger.init((e) => this.sendEvent(e));
-
- // this debugger uses zero-based lines and columns
- this.setDebuggerLinesStartAt1(false);
- this.setDebuggerColumnsStartAt1(false);
- }
-
- protected initializeRequest(
- response: DebugProtocol.InitializeResponse,
- args: DebugProtocol.InitializeRequestArguments,
- request?: DebugProtocol.Request
- ): void {
- log('InitializeRequest');
- response.body.supportsConfigurationDoneRequest = true;
-
- // We respond to InitializeRequest here, because Delve hasn't been
- // launched yet. Delve will start responding to DAP requests after
- // LaunchRequest is received, which tell us how to start it.
-
- // TODO: we could send an InitializeRequest to Delve when
- // it launches, wait for its response and sanity check the capabilities
- // it reports. Once DAP support in Delve is complete, this can be part
- // of making sure that the "dlv" binary we find is sufficiently
- // up-to-date to talk DAP with us.
- this.sendResponse(response);
- log('InitializeResponse');
- }
-
- protected launchRequest(
- response: DebugProtocol.LaunchResponse,
- args: LaunchRequestArguments,
- request: DebugProtocol.Request
- ): void {
- // Setup logger now that we have the 'trace' level passed in from
- // LaunchRequestArguments.
- this.logLevel =
- args.trace === 'verbose'
- ? Logger.LogLevel.Verbose
- : args.trace === 'log'
- ? Logger.LogLevel.Log
- : Logger.LogLevel.Error;
- const logPath =
- this.logLevel !== Logger.LogLevel.Error ? path.join(os.tmpdir(), 'vscode-godlvdapdebug.txt') : undefined;
- logger.setup(this.logLevel, logPath);
- log('launchRequest');
-
- // In noDebug mode with the 'debug' launch mode, we don't launch Delve
- // but run the debugee directly.
- // For other launch modes we currently still defer to Delve, for
- // compatibility with the old debugAdapter.
- // See https://github.com/golang/vscode-go/issues/336
- if (args.noDebug && args.mode === 'debug') {
- try {
- this.launchNoDebug(args);
- } catch (e) {
- logError(`launchNoDebug failed: "${e}"`);
- // TODO: define error constants
- // https://github.com/golang/vscode-go/issues/305
- this.sendErrorResponse(
- response,
- 3000,
- `Failed to launch "${e}"`);
- }
- return;
- }
-
- if (!args.port) {
- args.port = this.DEFAULT_DELVE_PORT;
- }
- if (!args.host) {
- args.host = this.DEFAULT_DELVE_HOST;
- }
-
- this.dlvClient = new DelveClient(args);
-
- this.dlvClient.on('stdout', (str) => {
- log('dlv stdout:', str);
- });
-
- this.dlvClient.on('stderr', (str) => {
- log('dlv stderr:', str);
- });
-
- this.dlvClient.on('connected', () => {
- // Once the client is connected to Delve, forward it the launch
- // request to begin the actual debugging session.
- this.dlvClient.send(request);
- });
-
- this.dlvClient.on('close', (rc) => {
- if (rc !== 0) {
- // TODO: define error constants
- // https://github.com/golang/vscode-go/issues/305
- this.sendErrorResponse(
- response,
- 3000,
- 'Failed to continue: Check the debug console for details.');
- }
- log('Sending TerminatedEvent as delve is closed');
- this.sendEvent(new TerminatedEvent());
- });
-
- // Relay events and responses back to vscode. In the future we will
- // add middleware here to intercept specific kinds of responses/events
- // for special handling.
- this.dlvClient.on('event', (event) => {
- this.sendEvent(event);
- });
-
- this.dlvClient.on('response', (resp) => {
- this.sendResponse(resp);
- });
- }
-
- protected attachRequest(
- response: DebugProtocol.AttachResponse,
- args: AttachRequestArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected disconnectRequest(
- response: DebugProtocol.DisconnectResponse,
- args: DebugProtocol.DisconnectArguments,
- request?: DebugProtocol.Request
- ): void {
- log('DisconnectRequest');
- // How we handle DisconnectRequest depends on whether Delve was launched
- // at all.
- // * In noDebug node, the Go program was spawned directly without
- // debugging: this.debugProcess will be non-null, and this.dlvClient
- // will be null.
- // * Otherwise, Delve was spawned: this.debugProcess will be null, and
- // this.dlvClient will be non-null.
- if (this.debugProcess !== null) {
- log(`killing debugee (pid: ${this.debugProcess.pid})...`);
-
- // Kill the debugee and notify the client when the killing is
- // completed, to ensure a clean shutdown sequence.
- killProcessTree(this.debugProcess, log).then(() => {
- super.disconnectRequest(response, args);
- log('DisconnectResponse');
- });
- } else if (this.dlvClient !== null) {
- // Forward this DisconnectRequest to Delve.
- this.dlvClient.send(request);
- } else {
- logError(`both debug process and dlv client are null`);
- // TODO: define all error codes as constants
- // https://github.com/golang/vscode-go/issues/305
- this.sendErrorResponse(
- response,
- 3000,
- 'Failed to disconnect: Check the debug console for details.');
- }
- }
-
- protected terminateRequest(
- response: DebugProtocol.TerminateResponse,
- args: DebugProtocol.TerminateArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected restartRequest(
- response: DebugProtocol.RestartResponse,
- args: DebugProtocol.RestartArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected setBreakPointsRequest(
- response: DebugProtocol.SetBreakpointsResponse,
- args: DebugProtocol.SetBreakpointsArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected setFunctionBreakPointsRequest(
- response: DebugProtocol.SetFunctionBreakpointsResponse,
- args: DebugProtocol.SetFunctionBreakpointsArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected setExceptionBreakPointsRequest(
- response: DebugProtocol.SetExceptionBreakpointsResponse,
- args: DebugProtocol.SetExceptionBreakpointsArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected configurationDoneRequest(
- response: DebugProtocol.ConfigurationDoneResponse,
- args: DebugProtocol.ConfigurationDoneArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected continueRequest(
- response: DebugProtocol.ContinueResponse,
- args: DebugProtocol.ContinueArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected nextRequest(
- response: DebugProtocol.NextResponse,
- args: DebugProtocol.NextArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected stepInRequest(
- response: DebugProtocol.StepInResponse,
- args: DebugProtocol.StepInArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected stepOutRequest(
- response: DebugProtocol.StepOutResponse,
- args: DebugProtocol.StepOutArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected stepBackRequest(
- response: DebugProtocol.StepBackResponse,
- args: DebugProtocol.StepBackArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected reverseContinueRequest(
- response: DebugProtocol.ReverseContinueResponse,
- args: DebugProtocol.ReverseContinueArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected restartFrameRequest(
- response: DebugProtocol.RestartFrameResponse,
- args: DebugProtocol.RestartFrameArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected gotoRequest(
- response: DebugProtocol.GotoResponse,
- args: DebugProtocol.GotoArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected pauseRequest(
- response: DebugProtocol.PauseResponse,
- args: DebugProtocol.PauseArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected sourceRequest(
- response: DebugProtocol.SourceResponse,
- args: DebugProtocol.SourceArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected threadsRequest(
- response: DebugProtocol.ThreadsResponse,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected terminateThreadsRequest(
- response: DebugProtocol.TerminateThreadsResponse,
- args: DebugProtocol.TerminateThreadsArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected stackTraceRequest(
- response: DebugProtocol.StackTraceResponse,
- args: DebugProtocol.StackTraceArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected scopesRequest(
- response: DebugProtocol.ScopesResponse,
- args: DebugProtocol.ScopesArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected variablesRequest(
- response: DebugProtocol.VariablesResponse,
- args: DebugProtocol.VariablesArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected setVariableRequest(
- response: DebugProtocol.SetVariableResponse,
- args: DebugProtocol.SetVariableArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected setExpressionRequest(
- response: DebugProtocol.SetExpressionResponse,
- args: DebugProtocol.SetExpressionArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected evaluateRequest(
- response: DebugProtocol.EvaluateResponse,
- args: DebugProtocol.EvaluateArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected stepInTargetsRequest(
- response: DebugProtocol.StepInTargetsResponse,
- args: DebugProtocol.StepInTargetsArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected gotoTargetsRequest(
- response: DebugProtocol.GotoTargetsResponse,
- args: DebugProtocol.GotoTargetsArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected completionsRequest(
- response: DebugProtocol.CompletionsResponse,
- args: DebugProtocol.CompletionsArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected exceptionInfoRequest(
- response: DebugProtocol.ExceptionInfoResponse,
- args: DebugProtocol.ExceptionInfoArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected loadedSourcesRequest(
- response: DebugProtocol.LoadedSourcesResponse,
- args: DebugProtocol.LoadedSourcesArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected dataBreakpointInfoRequest(
- response: DebugProtocol.DataBreakpointInfoResponse,
- args: DebugProtocol.DataBreakpointInfoArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected setDataBreakpointsRequest(
- response: DebugProtocol.SetDataBreakpointsResponse,
- args: DebugProtocol.SetDataBreakpointsArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected readMemoryRequest(
- response: DebugProtocol.ReadMemoryResponse,
- args: DebugProtocol.ReadMemoryArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected disassembleRequest(
- response: DebugProtocol.DisassembleResponse,
- args: DebugProtocol.DisassembleArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected cancelRequest(
- response: DebugProtocol.CancelResponse,
- args: DebugProtocol.CancelArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected breakpointLocationsRequest(
- response: DebugProtocol.BreakpointLocationsResponse,
- args: DebugProtocol.BreakpointLocationsArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- protected setInstructionBreakpointsRequest(
- response: DebugProtocol.SetInstructionBreakpointsResponse,
- args: DebugProtocol.SetInstructionBreakpointsArguments,
- request?: DebugProtocol.Request
- ): void {
- this.dlvClient.send(request);
- }
-
- // Launch the debugee process without starting a debugger.
- // This implements the `Run > Run Without Debugger` functionality in vscode.
- // Note: this method currently assumes launchArgs.mode === 'debug'.
- private launchNoDebug(launchArgs: LaunchRequestArguments): void {
- if (launchArgs.mode !== 'debug') {
- throw new Error('launchNoDebug requires "debug" mode');
- }
- const {program, dirname, programIsDirectory} = parseProgramArgSync(launchArgs);
- const goRunArgs = ['run'];
- if (launchArgs.buildFlags) {
- goRunArgs.push(launchArgs.buildFlags);
- }
-
- if (programIsDirectory) {
- goRunArgs.push('.');
- } else {
- goRunArgs.push(program);
- }
-
- if (launchArgs.args) {
- goRunArgs.push(...launchArgs.args);
- }
-
- // launchArgs.env includes all the environment variables
- // including vscode-go's toolsExecutionEnvironment (PATH, GOPATH, ...),
- // and those read from .env files.
- const launchArgsEnv = launchArgs.env || {};
- const programEnv = Object.assign({}, process.env, launchArgsEnv);
-
- log(`Current working directory: ${dirname}`);
- const goExe = getBinPathWithPreferredGopathGoroot('go', []);
- log(`Running: ${goExe} ${goRunArgs.join(' ')}`);
-
- this.debugProcess = spawn(goExe, goRunArgs, {
- cwd: dirname,
- env: programEnv
- });
- this.debugProcess.stderr.on('data', (str) => {
- this.sendEvent(new OutputEvent(str.toString(), 'stderr'));
- });
- this.debugProcess.stdout.on('data', (str) => {
- this.sendEvent(new OutputEvent(str.toString(), 'stdout'));
- });
- this.debugProcess.on('close', (rc) => {
- this.sendEvent(new TerminatedEvent());
- });
- }
-}
-
-// DelveClient provides a DAP client to talk to a DAP server in Delve.
-//
-// After creation, it emits the following events:
-//
-// 'connected': client is connected to delve
-// 'request (request)': delve sent request
-// 'response (response)': delve sent response
-// 'event (event)': delve sent event
-// 'stdout' (str): delve emitted str to stdout
-// 'stderr' (str): delve emitted str to stderr
-// 'close' (rc): delve exited with return code rc
-class DelveClient extends DAPClient {
- private debugProcess: ChildProcess;
- private serverStarted: boolean = false;
-
- constructor(launchArgs: LaunchRequestArguments) {
- super();
-
- const dir = parseProgramArgSync(launchArgs).dirname;
- this.debugProcess = spawnDapServerProcess(launchArgs, log, logError);
-
- this.debugProcess.stderr.on('data', (chunk) => {
- let str = chunk.toString();
- str = expandFilePathInOutput(str, dir);
- this.emit('stderr', str);
- });
-
- this.debugProcess.stdout.on('data', (chunk) => {
- const str = chunk.toString();
- this.emit('stdout', str);
-
- if (!this.serverStarted) {
- this.serverStarted = true;
- this.connectSocketToServer(launchArgs.port, launchArgs.host);
- }
- });
-
- this.debugProcess.on('close', (rc) => {
- if (rc) {
- logError(`Process exiting with code: ${rc} signal: ${this.debugProcess.killed}`);
- } else {
- log(`Process exiting normally ${this.debugProcess.killed}`);
- }
- this.emit('close', rc);
- });
-
- this.debugProcess.on('error', (err) => {
- throw err;
- });
- }
-
- // Connect this client to the server. The server is expected to be listening
- // on host:port.
- private connectSocketToServer(port: number, host: string) {
- // Add a slight delay to ensure that Delve started up the server.
- setTimeout(() => {
- const socket = net.createConnection(
- port,
- host,
- () => {
- this.connect(socket, socket);
- this.emit('connected');
- });
-
- socket.on('error', (err) => {
- throw err;
- });
- }, 200);
- }
-}
-
-// Helper function to parse a program from LaunchRequestArguments. Returns:
-// {
-// program: the program arg,
-// dirname: the directory containing the program (or 'program' itself if
-// it's already a directory),
-// programIsDirectory: is the program a directory?
-// }
-//
-// The program argument is taken as-is from launchArgs. If the program path
-// is relative, dirname will also be relative. If the program path is absolute,
-// dirname will also be absolute.
-//
-// Throws an exception in case args.program is not a valid file or directory.
-// This function can block because it calls a blocking fs function.
-export function parseProgramArgSync(launchArgs: DebugConfiguration
-): { program: string, dirname: string, programIsDirectory: boolean } {
- const program = launchArgs.program;
- if (!program) {
- throw new Error('The program attribute is missing in the debug configuration in launch.json');
- }
- let programIsDirectory = false;
- try {
- programIsDirectory = fs.lstatSync(program).isDirectory();
- } catch (e) {
- throw new Error('The program attribute must point to valid directory, .go file or executable.');
- }
- if (!programIsDirectory && path.extname(program) !== '.go') {
- throw new Error('The program attribute must be a directory or .go file in debug mode');
- }
- const dirname = programIsDirectory ? program : path.dirname(program);
- return {program, dirname, programIsDirectory};
-}
-
-export function spawnDapServerProcess(
- launchArgs: DebugConfiguration,
- logFn: (...args: any[]) => void,
- logErrFn: (...args: any[]) => void
-) {
- const launchArgsEnv = launchArgs.env || {};
- const env = Object.assign({}, process.env, launchArgsEnv);
-
- // Let users override direct path to delve by setting it in the env
- // map in launch.json; if unspecified, fall back to dlvToolPath.
- let dlvPath = launchArgsEnv['dlvPath'];
- if (!dlvPath) {
- dlvPath = launchArgs.dlvToolPath;
- }
-
- if (!fs.existsSync(dlvPath)) {
- logErrFn(
- `Couldn't find dlv at the Go tools path, ${process.env['GOPATH']}${
- env['GOPATH'] ? ', ' + env['GOPATH'] : ''
- } or ${envPath}`
- );
- throw new Error(
- `Cannot find Delve debugger. Install from https://github.com/go-delve/delve/ & ensure it is in your Go tools path, "GOPATH/bin" or "PATH".`
- );
- }
-
- const dlvArgs = new Array<string>();
- dlvArgs.push('dap');
- // add user-specified dlv flags first. When duplicate flags are specified,
- // dlv doesn't mind but accepts the last flag value.
- if (launchArgs.dlvFlags && launchArgs.dlvFlags.length > 0) {
- dlvArgs.push(...launchArgs.dlvFlags);
- }
- dlvArgs.push(`--listen=${launchArgs.host}:${launchArgs.port}`);
- if (launchArgs.showLog) {
- dlvArgs.push('--log=' + launchArgs.showLog.toString());
- }
- if (launchArgs.logOutput) {
- dlvArgs.push('--log-output=' + launchArgs.logOutput);
- }
- logFn(`Running: ${dlvPath} ${dlvArgs.join(' ')}`);
-
- const dir = parseProgramArgSync(launchArgs).dirname;
- return spawn(dlvPath, dlvArgs, {
- cwd: dir,
- env
- });
-}
diff --git a/src/debugAdapter2/goDlvDebugMain.ts b/src/debugAdapter2/goDlvDebugMain.ts
deleted file mode 100644
index 8fc3073..0000000
--- a/src/debugAdapter2/goDlvDebugMain.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*---------------------------------------------------------
- * Copyright 2020 The Go Authors. All rights reserved.
- * Licensed under the MIT License. See LICENSE in the project root for license information.
- *--------------------------------------------------------*/
-
-// This file is for running the godlvdap debug adapter as a standalone program
-// in a separate process (e.g. when working in --server mode).
-//
-// NOTE: we must not include this file when we switch to the inline debug adapter
-// launch mode. This installs a process-wide uncaughtException handler
-// which can result in the extension host crash.
-
-import { logger } from 'vscode-debugadapter';
-import { GoDlvDapDebugSession } from './goDlvDebug';
-
-process.on('uncaughtException', (err: any) => {
- const errMessage = err && (err.stack || err.message);
- logger.error(`Unhandled error in debug adapter: ${errMessage}`);
- throw err;
-});
-
-GoDlvDapDebugSession.run(GoDlvDapDebugSession);
diff --git a/src/goDebugFactory.ts b/src/goDebugFactory.ts
index 9ada182..39eac56 100644
--- a/src/goDebugFactory.ts
+++ b/src/goDebugFactory.ts
@@ -3,12 +3,14 @@
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------*/
-import { ChildProcess } from 'child_process';
+import { ChildProcess, spawn } from 'child_process';
+import * as fs from 'fs';
import getPort = require('get-port');
+import path = require('path');
import { DebugConfiguration } from 'vscode';
import vscode = require('vscode');
-import { spawnDapServerProcess as spawnDlvDapServerProcess } from './debugAdapter2/goDlvDebug';
import { logError, logInfo } from './goLogging';
+import { envPath } from './utils/pathUtils';
import { killProcessTree } from './utils/processUtils';
export class GoDebugAdapterDescriptorFactory implements vscode.DebugAdapterDescriptorFactory {
@@ -60,5 +62,72 @@
resolve({port: configuration.port, host: configuration.host});
}, 500));
}
+}
+function spawnDlvDapServerProcess(
+ launchArgs: DebugConfiguration,
+ logFn: (...args: any[]) => void,
+ logErrFn: (...args: any[]) => void
+) {
+ const launchArgsEnv = launchArgs.env || {};
+ const env = Object.assign({}, process.env, launchArgsEnv);
+
+ // Let users override direct path to delve by setting it in the env
+ // map in launch.json; if unspecified, fall back to dlvToolPath.
+ let dlvPath = launchArgsEnv['dlvPath'];
+ if (!dlvPath) {
+ dlvPath = launchArgs.dlvToolPath;
+ }
+
+ if (!fs.existsSync(dlvPath)) {
+ logErrFn(
+ `Couldn't find dlv at the Go tools path, ${process.env['GOPATH']}${
+ env['GOPATH'] ? ', ' + env['GOPATH'] : ''
+ } or ${envPath}`
+ );
+ throw new Error(
+ `Cannot find Delve debugger. Install from https://github.com/go-delve/delve/ & ensure it is in your Go tools path, "GOPATH/bin" or "PATH".`
+ );
+ }
+
+ const dlvArgs = new Array<string>();
+ dlvArgs.push('dap');
+ // add user-specified dlv flags first. When duplicate flags are specified,
+ // dlv doesn't mind but accepts the last flag value.
+ if (launchArgs.dlvFlags && launchArgs.dlvFlags.length > 0) {
+ dlvArgs.push(...launchArgs.dlvFlags);
+ }
+ dlvArgs.push(`--listen=${launchArgs.host}:${launchArgs.port}`);
+ if (launchArgs.showLog) {
+ dlvArgs.push('--log=' + launchArgs.showLog.toString());
+ }
+ if (launchArgs.logOutput) {
+ dlvArgs.push('--log-output=' + launchArgs.logOutput);
+ }
+ logFn(`Running: ${dlvPath} ${dlvArgs.join(' ')}`);
+
+ const dir = parseProgramArgSync(launchArgs).dirname;
+ return spawn(dlvPath, dlvArgs, {
+ cwd: dir,
+ env
+ });
+}
+
+function parseProgramArgSync(launchArgs: DebugConfiguration
+): { program: string, dirname: string, programIsDirectory: boolean } {
+ const program = launchArgs.program;
+ if (!program) {
+ throw new Error('The program attribute is missing in the debug configuration in launch.json');
+ }
+ let programIsDirectory = false;
+ try {
+ programIsDirectory = fs.lstatSync(program).isDirectory();
+ } catch (e) {
+ throw new Error('The program attribute must point to valid directory, .go file or executable.');
+ }
+ if (!programIsDirectory && path.extname(program) !== '.go') {
+ throw new Error('The program attribute must be a directory or .go file in debug mode');
+ }
+ const dirname = programIsDirectory ? program : path.dirname(program);
+ return {program, dirname, programIsDirectory};
}
diff --git a/webpack.config.js b/webpack.config.js
index f360b4a..71fc23c 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -10,7 +10,6 @@
entry: {
goMain: './src/goMain.ts',
debugAdapter: './src/debugAdapter/goDebug.ts',
- debugAdapter2: './src/debugAdapter2/goDlvDebugMain.ts',
},
output: {
path: path.resolve(__dirname, 'dist'),