environmentService.ts 10.1 KB
Newer Older
J
Joao Moreno 已提交
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

6
import { IEnvironmentService, ParsedArgs, IDebugParams, IExtensionHostDebugParams } from 'vs/platform/environment/common/environment';
7
import * as crypto from 'crypto';
J
Joao Moreno 已提交
8 9
import * as paths from 'vs/base/node/paths';
import * as os from 'os';
10
import * as path from 'vs/base/common/path';
S
Sandeep Somavarapu 已提交
11
import * as resources from 'vs/base/common/resources';
12
import { memoize } from 'vs/base/common/decorators';
13 14
import pkg from 'vs/platform/product/node/package';
import product from 'vs/platform/product/node/product';
15
import { toLocalISOString } from 'vs/base/common/date';
16
import { isWindows, isLinux } from 'vs/base/common/platform';
17
import { getPathFromAmdModule } from 'vs/base/common/amd';
18
import { URI } from 'vs/base/common/uri';
J
Joao Moreno 已提交
19

J
Joao Moreno 已提交
20 21 22 23
// Read this before there's any chance it is overwritten
// Related to https://github.com/Microsoft/vscode/issues/30624
const xdgRuntimeDir = process.env['XDG_RUNTIME_DIR'];

J
Joao Moreno 已提交
24
function getNixIPCHandle(userDataPath: string, type: string): string {
J
Joao Moreno 已提交
25 26 27
	const vscodePortable = process.env['VSCODE_PORTABLE'];

	if (xdgRuntimeDir && !vscodePortable) {
J
Joao Moreno 已提交
28 29
		const scope = crypto.createHash('md5').update(userDataPath).digest('hex').substr(0, 8);
		return path.join(xdgRuntimeDir, `vscode-${scope}-${pkg.version}-${type}.sock`);
J
Joao Moreno 已提交
30 31
	}

J
Joao Moreno 已提交
32 33
	return path.join(userDataPath, `${pkg.version}-${type}.sock`);
}
34

35 36
function getWin32IPCHandle(userDataPath: string, type: string): string {
	const scope = crypto.createHash('md5').update(userDataPath).digest('hex');
37

38
	return `\\\\.\\pipe\\${scope}-${pkg.version}-${type}-sock`;
J
Joao Moreno 已提交
39
}
40

J
Joao Moreno 已提交
41
function getIPCHandle(userDataPath: string, type: string): string {
42
	if (isWindows) {
43
		return getWin32IPCHandle(userDataPath, type);
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

	return getNixIPCHandle(userDataPath, type);
}

function getCLIPath(execPath: string, appRoot: string, isBuilt: boolean): string {

	// Windows
	if (isWindows) {
		if (isBuilt) {
			return path.join(path.dirname(execPath), 'bin', `${product.applicationName}.cmd`);
		}

		return path.join(appRoot, 'scripts', 'code-cli.bat');
	}

	// Linux
	if (isLinux) {
		if (isBuilt) {
			return path.join(path.dirname(execPath), 'bin', `${product.applicationName}`);
		}

		return path.join(appRoot, 'scripts', 'code-cli.sh');
	}

	// macOS
	if (isBuilt) {
		return path.join(appRoot, 'bin', 'code');
	}

	return path.join(appRoot, 'scripts', 'code-cli.sh');
75 76
}

J
Joao Moreno 已提交
77 78
export class EnvironmentService implements IEnvironmentService {

79
	_serviceBrand: any;
J
Joao Moreno 已提交
80

J
Joao Moreno 已提交
81 82
	get args(): ParsedArgs { return this._args; }

83
	@memoize
84
	get appRoot(): string { return path.dirname(getPathFromAmdModule(require, '')); }
J
Joao Moreno 已提交
85 86

	get execPath(): string { return this._execPath; }
87

88 89 90
	@memoize
	get cliPath(): string { return getCLIPath(this.execPath, this.appRoot, this.isBuilt); }

J
Joao Moreno 已提交
91 92
	readonly logsPath: string;

93
	@memoize
94 95
	get userHome(): string { return os.homedir(); }

J
Joao Moreno 已提交
96 97
	@memoize
	get userDataPath(): string {
98
		const vscodePortable = process.env['VSCODE_PORTABLE'];
J
Joao Moreno 已提交
99

100 101
		if (vscodePortable) {
			return path.join(vscodePortable, 'user-data');
J
Joao Moreno 已提交
102 103 104 105
		}

		return parseUserDataDir(this._args, process);
	}
J
Joao Moreno 已提交
106

107 108 109
	@memoize
	get webUserDataHome(): URI { return URI.file(parsePathArg(this._args['web-user-data-dir'], process) || this.userDataPath); }

110 111
	get appNameLong(): string { return product.nameLong; }

112
	get appQuality(): string | undefined { return product.quality; }
113

114
	@memoize
S
Sandeep Somavarapu 已提交
115
	get appSettingsHome(): URI { return URI.file(path.join(this.userDataPath, 'User')); }
116

117
	@memoize
118
	get machineSettingsHome(): URI { return URI.file(path.join(this.userDataPath, 'Machine')); }
119 120

	@memoize
121
	get machineSettingsResource(): URI { return resources.joinPath(this.machineSettingsHome, 'settings.json'); }
122

123
	@memoize
S
Sandeep Somavarapu 已提交
124
	get globalStorageHome(): string { return path.join(this.appSettingsHome.fsPath, 'globalStorage'); }
125

126
	@memoize
S
Sandeep Somavarapu 已提交
127
	get workspaceStorageHome(): string { return path.join(this.appSettingsHome.fsPath, 'workspaceStorage'); }
128

129
	@memoize
130
	get settingsSearchBuildId(): number | undefined { return product.settingsSearchBuildId; }
131

132
	@memoize
133
	get settingsSearchUrl(): string | undefined { return product.settingsSearchUrl; }
134

135
	@memoize
136
	get keybindingsResource(): URI { return resources.joinPath(this.appSettingsHome, 'keybindings.json'); }
137

P
Peng Lyu 已提交
138 139 140
	@memoize
	get keyboardLayoutResource(): URI { return resources.joinPath(this.appSettingsHome, 'keyboardLayout.json'); }

141
	@memoize
142
	get isExtensionDevelopment(): boolean { return !!this._args.extensionDevelopmentPath; }
143

144 145 146 147 148 149
	@memoize
	get backupHome(): string { return path.join(this.userDataPath, 'Backups'); }

	@memoize
	get backupWorkspacesPath(): string { return path.join(this.backupHome, 'workspaces.json'); }

150
	@memoize
151
	get untitledWorkspacesHome(): URI { return URI.file(path.join(this.userDataPath, 'Workspaces')); }
152

153 154 155
	@memoize
	get installSourcePath(): string { return path.join(this.userDataPath, 'installSource'); }

156 157 158 159 160 161 162 163 164 165
	@memoize
	get builtinExtensionsPath(): string {
		const fromArgs = parsePathArg(this._args['builtin-extensions-dir'], process);
		if (fromArgs) {
			return fromArgs;
		} else {
			return path.normalize(path.join(getPathFromAmdModule(require, ''), '..', 'extensions'));
		}
	}

166
	@memoize
J
Joao Moreno 已提交
167 168 169 170 171 172
	get extensionsPath(): string {
		const fromArgs = parsePathArg(this._args['extensions-dir'], process);

		if (fromArgs) {
			return fromArgs;
		}
173 174 175 176 177 178 179

		const vscodeExtensions = process.env['VSCODE_EXTENSIONS'];
		if (vscodeExtensions) {
			return vscodeExtensions;
		}

		const vscodePortable = process.env['VSCODE_PORTABLE'];
J
Joao Moreno 已提交
180

181 182 183 184 185
		if (vscodePortable) {
			return path.join(vscodePortable, 'extensions');
		}

		return path.join(this.userHome, product.dataFolderName, 'extensions');
J
Joao Moreno 已提交
186
	}
J
Joao Moreno 已提交
187

188
	@memoize
189
	get extensionDevelopmentLocationURI(): URI[] | undefined {
190
		const s = this._args.extensionDevelopmentPath;
191 192 193 194 195 196 197 198
		if (Array.isArray(s)) {
			return s.map(p => {
				if (/^[^:/?#]+?:\/\//.test(p)) {
					return URI.parse(p);
				}
				return URI.file(path.normalize(p));
			});
		} else if (s) {
199
			if (/^[^:/?#]+?:\/\//.test(s)) {
200
				return [URI.parse(s)];
201
			}
202
			return [URI.file(path.normalize(s))];
203
		}
R
Rob Lourens 已提交
204
		return undefined;
205
	}
206 207

	@memoize
208 209 210 211 212 213 214 215 216 217
	get extensionTestsLocationURI(): URI | undefined {
		const s = this._args.extensionTestsPath;
		if (s) {
			if (/^[^:/?#]+?:\/\//.test(s)) {
				return URI.parse(s);
			}
			return URI.file(path.normalize(s));
		}
		return undefined;
	}
218

S
Sandeep Somavarapu 已提交
219 220 221 222
	get disableExtensions(): boolean | string[] {
		if (this._args['disable-extensions']) {
			return true;
		}
223
		const disableExtensions = this._args['disable-extension'];
S
Sandeep Somavarapu 已提交
224 225 226 227 228 229 230 231 232 233
		if (disableExtensions) {
			if (typeof disableExtensions === 'string') {
				return [disableExtensions];
			}
			if (Array.isArray(disableExtensions) && disableExtensions.length > 0) {
				return disableExtensions;
			}
		}
		return false;
	}
B
Benjamin Pasero 已提交
234

235
	get skipGettingStarted(): boolean { return !!this._args['skip-getting-started']; }
236

237
	get skipReleaseNotes(): boolean { return !!this._args['skip-release-notes']; }
238

239
	get skipAddToRecentlyOpened(): boolean { return !!this._args['skip-add-to-recently-opened']; }
240

241
	@memoize
242 243 244 245
	get debugExtensionHost(): IExtensionHostDebugParams { return parseExtensionHostPort(this._args, this.isBuilt); }

	@memoize
	get debugSearch(): IDebugParams { return parseSearchPort(this._args, this.isBuilt); }
246

247
	get isBuilt(): boolean { return !process.env['VSCODE_DEV']; }
248 249
	get verbose(): boolean { return !!this._args.verbose; }
	get log(): string | undefined { return this._args.log; }
250

251
	get wait(): boolean { return !!this._args.wait; }
B
Benjamin Pasero 已提交
252

253
	get logExtensionHostCommunication(): boolean { return !!this._args.logExtensionHostCommunication; }
254

255
	get status(): boolean { return !!this._args.status; }
256

257
	@memoize
J
Joao Moreno 已提交
258
	get mainIPCHandle(): string { return getIPCHandle(this.userDataPath, 'main'); }
259 260

	@memoize
J
Joao Moreno 已提交
261
	get sharedIPCHandle(): string { return getIPCHandle(this.userDataPath, 'shared'); }
262

263
	@memoize
264
	get nodeCachedDataDir(): string | undefined { return process.env['VSCODE_NODE_CACHED_DATA_DIR'] || undefined; }
265

J
Joao Moreno 已提交
266
	get disableUpdates(): boolean { return !!this._args['disable-updates']; }
267
	get disableCrashReporter(): boolean { return !!this._args['disable-crash-reporter']; }
J
Joao Moreno 已提交
268

269 270
	get driverHandle(): string | undefined { return this._args['driver']; }
	get driverVerbose(): boolean { return !!this._args['driver-verbose']; }
J
Joao Moreno 已提交
271

272 273 274 275
	get webviewResourceRoot(): string {
		return 'vscode-resource:';
	}

J
Joao 已提交
276
	constructor(private _args: ParsedArgs, private _execPath: string) {
J
Joao Moreno 已提交
277
		if (!process.env['VSCODE_LOGS']) {
278
			const key = toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '');
J
Joao Moreno 已提交
279 280 281
			process.env['VSCODE_LOGS'] = path.join(this.userDataPath, 'logs', key);
		}

282
		this.logsPath = process.env['VSCODE_LOGS']!;
J
Joao 已提交
283
	}
284 285
}

286
export function parseExtensionHostPort(args: ParsedArgs, isBuild: boolean): IExtensionHostDebugParams {
287
	return parseDebugPort(args['inspect-extensions'], args['inspect-brk-extensions'], 5870, isBuild, args.debugId);
288 289 290
}

export function parseSearchPort(args: ParsedArgs, isBuild: boolean): IDebugParams {
291
	return parseDebugPort(args['inspect-search'], args['inspect-brk-search'], 5876, isBuild);
292 293
}

294
export function parseDebugPort(debugArg: string | undefined, debugBrkArg: string | undefined, defaultBuildPort: number, isBuild: boolean, debugId?: string): IExtensionHostDebugParams {
295
	const portStr = debugBrkArg || debugArg;
296
	const port = Number(portStr) || (!isBuild ? defaultBuildPort : null);
297
	const brk = port ? Boolean(!!debugBrkArg) : false;
298

299
	return { port, break: brk, debugId };
300 301
}

302
function parsePathArg(arg: string | undefined, process: NodeJS.Process): string | undefined {
J
João Moreno 已提交
303
	if (!arg) {
M
Matt Bierner 已提交
304
		return undefined;
305
	}
J
João Moreno 已提交
306 307 308 309 310 311 312 313

	// Determine if the arg is relative or absolute, if relative use the original CWD
	// (VSCODE_CWD), not the potentially overridden one (process.cwd()).
	const resolved = path.resolve(arg);

	if (path.normalize(arg) === resolved) {
		return resolved;
	}
314 315

	return path.resolve(process.env['VSCODE_CWD'] || process.cwd(), arg);
J
João Moreno 已提交
316 317 318 319
}

export function parseUserDataDir(args: ParsedArgs, process: NodeJS.Process): string {
	return parsePathArg(args['user-data-dir'], process) || path.resolve(paths.getDefaultUserDataPath(process.platform));
320
}