-
Notifications
You must be signed in to change notification settings - Fork 236
/
adapter.ts
145 lines (129 loc) · 4.46 KB
/
adapter.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import * as cp from 'child_process';
import * as path from 'path';
import * as async from './async';
import * as os from 'os';
import { Dict, Environment } from './commonTypes';
import { mergedEnvironment } from './expand';
import { AdapterSettings } from './adapterMessages';
export interface AdapterStartOptions {
extensionRoot: string;
workDir: string;
extraEnv: Dict<string>; // Extra environment to be set for adapter
port: number;
connect: boolean; // Whether to connect or to listen on the port
authToken?: string; // Token to use for authentication when reverse-connecting
adapterSettings: AdapterSettings;
verboseLogging: boolean;
}
export interface ProcessSpawnParams {
command: string,
args: string[],
options: cp.SpawnOptions
}
export async function getSpawnParams(
liblldb: string,
options: AdapterStartOptions
): Promise<ProcessSpawnParams> {
let executable = path.join(options.extensionRoot, 'adapter', 'codelldb');
let portAction = options.connect ? '--connect' : '--port';
let args = ['--liblldb', liblldb, portAction, options.port.toString()];
if (options.authToken) {
args = args.concat(['--auth-token', options.authToken]);
}
if (options.adapterSettings) {
args = args.concat(['--settings', JSON.stringify(options.adapterSettings)]);
}
let env = getAdapterEnv(options.extraEnv);
env['RUST_TRACEBACK'] = '1';
if (options.verboseLogging) {
env['RUST_LOG'] = 'error,codelldb=debug';
}
// Check if workDir exists and is a directory, otherwise launch with default cwd.
let workDir = options.workDir;
if (workDir) {
let stat = await async.fs.stat(workDir).catch(_ => null);
if (!stat || !stat.isDirectory())
workDir = undefined;
}
// Make sure that adapter gets launched with the correct architecture preference setting if
// launched by translated x86 VSCode.
if (await isRosetta()) {
args = ['--arm64', executable].concat(args);
executable = 'arch';
}
return {
command: executable,
args: args,
options: {
env: env,
cwd: workDir
}
}
}
export async function start(
liblldb: string,
options: AdapterStartOptions
): Promise<cp.ChildProcess> {
let spawnParams = await getSpawnParams(liblldb, options);
spawnParams.options.stdio = ['ignore', 'pipe', 'pipe'];
return cp.spawn(spawnParams.command, spawnParams.args, spawnParams.options);
}
export async function findLibLLDB(pathHint: string): Promise<string | null> {
let stat = await async.fs.stat(pathHint);
if (stat.isFile())
return pathHint;
let libDir;
let pattern;
if (process.platform == 'linux') {
libDir = path.join(pathHint, 'lib');
pattern = /liblldb.*\.so.*/;
} else if (process.platform == 'darwin') {
libDir = path.join(pathHint, 'lib');
pattern = /liblldb\..*dylib|LLDB/;
} else if (process.platform == 'win32') {
libDir = path.join(pathHint, 'bin');
pattern = /liblldb\.dll/;
}
for (let dir of [pathHint, libDir]) {
let file = await findFileByPattern(dir, pattern);
if (file) {
return path.join(dir, file);
}
}
return null;
}
async function findFileByPattern(path: string, pattern: RegExp): Promise<string | null> {
try {
let files = await async.fs.readdir(path);
for (let file of files) {
if (pattern.test(file))
return file;
}
}
catch (err) {
// Ignore missing diractories and such...
}
return null;
}
export function getAdapterEnv(extraEnv: Dict<string>): Environment {
let env = mergedEnvironment(extraEnv);
// Scrub backlisted environment entries, unless they were added explicitly via extraEnv.
for (let name of ['PYTHONHOME', 'PYTHONPATH', 'CODELLDB_STARTUP']) {
if (extraEnv[name] === undefined)
delete env[name];
}
return env;
}
// Whether this is an x86 process running on Apple M1 CPU.
export async function isRosetta(): Promise<boolean> {
return await isRosettaAsync;
}
async function isRosettaImpl(): Promise<boolean> {
if (os.platform() == 'darwin' && os.arch() == 'x64') {
let sysctl = await async.cp.execFile('sysctl', ['-in', 'sysctl.proc_translated'], { encoding: 'utf8' });
return parseInt(sysctl.stdout) == 1;
} else {
return false;
}
}
let isRosettaAsync = isRosettaImpl();