1
+ import * as path from "path" ;
2
+ import * as util from "util" ;
1
3
import * as vscode from "vscode" ;
2
- import { LLDBDapOptions } from "./types" ;
4
+ import * as child_process from "child_process" ;
5
+ import * as fs from "node:fs/promises" ;
3
6
4
- /**
5
- * This class defines a factory used to find the lldb-dap binary to use
6
- * depending on the session configuration.
7
- */
8
- export class LLDBDapDescriptorFactory
9
- implements vscode . DebugAdapterDescriptorFactory
10
- {
11
- private lldbDapOptions : LLDBDapOptions ;
12
-
13
- constructor ( lldbDapOptions : LLDBDapOptions ) {
14
- this . lldbDapOptions = lldbDapOptions ;
7
+ export async function isExecutable ( path : string ) : Promise < Boolean > {
8
+ try {
9
+ await fs . access ( path , fs . constants . X_OK ) ;
10
+ } catch {
11
+ return false ;
15
12
}
13
+ return true ;
14
+ }
16
15
17
- static async isValidDebugAdapterPath (
18
- pathUri : vscode . Uri ,
19
- ) : Promise < Boolean > {
16
+ async function findWithXcrun ( executable : string ) : Promise < string | undefined > {
17
+ if ( process . platform === "darwin" ) {
20
18
try {
21
- const fileStats = await vscode . workspace . fs . stat ( pathUri ) ;
22
- if ( ! ( fileStats . type & vscode . FileType . File ) ) {
23
- return false ;
19
+ const exec = util . promisify ( child_process . execFile ) ;
20
+ let { stdout, stderr } = await exec ( "/usr/bin/xcrun" , [
21
+ "-find" ,
22
+ executable ,
23
+ ] ) ;
24
+ if ( stdout ) {
25
+ return stdout . toString ( ) . trimEnd ( ) ;
24
26
}
25
- } catch ( err ) {
26
- return false ;
27
+ } catch ( error ) { }
28
+ }
29
+ return undefined ;
30
+ }
31
+
32
+ async function findInPath ( executable : string ) : Promise < string | undefined > {
33
+ const env_path =
34
+ process . platform === "win32" ? process . env [ "Path" ] : process . env [ "PATH" ] ;
35
+ if ( ! env_path ) {
36
+ return undefined ;
37
+ }
38
+
39
+ const paths = env_path . split ( path . delimiter ) ;
40
+ for ( const p of paths ) {
41
+ const exe_path = path . join ( p , executable ) ;
42
+ if ( await isExecutable ( exe_path ) ) {
43
+ return exe_path ;
27
44
}
28
- return true ;
45
+ }
46
+ return undefined ;
47
+ }
48
+
49
+ async function findDAPExecutable ( ) : Promise < string | undefined > {
50
+ const executable = process . platform === "win32" ? "lldb-dap.exe" : "lldb-dap" ;
51
+
52
+ // Prefer lldb-dap from Xcode on Darwin.
53
+ const xcrun_dap = findWithXcrun ( executable ) ;
54
+ if ( xcrun_dap ) {
55
+ return xcrun_dap ;
56
+ }
57
+
58
+ // Find lldb-dap in the user's path.
59
+ const path_dap = findInPath ( executable ) ;
60
+ if ( path_dap ) {
61
+ return path_dap ;
29
62
}
30
63
64
+ return undefined ;
65
+ }
66
+
67
+ async function getDAPExecutable (
68
+ session : vscode . DebugSession ,
69
+ ) : Promise < string | undefined > {
70
+ const config = vscode . workspace . getConfiguration (
71
+ "lldb-dap" ,
72
+ session . workspaceFolder ,
73
+ ) ;
74
+
75
+ // Prefer the explicitly specified path in the extension's configuration.
76
+ const configPath = config . get < string > ( "executable-path" ) ;
77
+ if ( configPath && configPath . length !== 0 ) {
78
+ return configPath ;
79
+ }
80
+
81
+ // Try finding the lldb-dap binary.
82
+ const foundPath = await findDAPExecutable ( ) ;
83
+ if ( foundPath ) {
84
+ return foundPath ;
85
+ }
86
+
87
+ return undefined ;
88
+ }
89
+
90
+ /**
91
+ * This class defines a factory used to find the lldb-dap binary to use
92
+ * depending on the session configuration.
93
+ */
94
+ export class LLDBDapDescriptorFactory
95
+ implements vscode . DebugAdapterDescriptorFactory
96
+ {
31
97
async createDebugAdapterDescriptor (
32
98
session : vscode . DebugSession ,
33
99
executable : vscode . DebugAdapterExecutable | undefined ,
@@ -36,14 +102,40 @@ export class LLDBDapDescriptorFactory
36
102
"lldb-dap" ,
37
103
session . workspaceFolder ,
38
104
) ;
39
- const customPath = config . get < string > ( "executable-path" ) ;
40
- const path : string = customPath || executable ! ! . command ;
41
105
42
- const fileUri = vscode . Uri . file ( path ) ;
43
- if ( ! ( await LLDBDapDescriptorFactory . isValidDebugAdapterPath ( fileUri ) ) ) {
44
- LLDBDapDescriptorFactory . showLLDBDapNotFoundMessage ( fileUri . path ) ;
106
+ const log_path = config . get < string > ( "log-path" ) ;
107
+ let env : { [ key : string ] : string } = { } ;
108
+ if ( log_path ) {
109
+ env [ "LLDBDAP_LOG" ] = log_path ;
110
+ }
111
+ const configEnvironment =
112
+ config . get < { [ key : string ] : string } > ( "environment" ) || { } ;
113
+ const dapPath = await getDAPExecutable ( session ) ;
114
+ const dbgOptions = {
115
+ env : {
116
+ ...executable ?. options ?. env ,
117
+ ...configEnvironment ,
118
+ ...env ,
119
+ } ,
120
+ } ;
121
+ if ( dapPath ) {
122
+ if ( ! ( await isExecutable ( dapPath ) ) ) {
123
+ LLDBDapDescriptorFactory . showLLDBDapNotFoundMessage ( dapPath ) ;
124
+ return undefined ;
125
+ }
126
+ return new vscode . DebugAdapterExecutable ( dapPath , [ ] , dbgOptions ) ;
127
+ } else if ( executable ) {
128
+ if ( ! ( await isExecutable ( executable . command ) ) ) {
129
+ LLDBDapDescriptorFactory . showLLDBDapNotFoundMessage ( executable . command ) ;
130
+ return undefined ;
131
+ }
132
+ return new vscode . DebugAdapterExecutable (
133
+ executable . command ,
134
+ executable . args ,
135
+ dbgOptions ,
136
+ ) ;
45
137
}
46
- return this . lldbDapOptions . createDapExecutableCommand ( session , executable ) ;
138
+ return undefined ;
47
139
}
48
140
49
141
/**
0 commit comments