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

import { spawn } from 'child_process';
J
Joao Moreno 已提交
7
import { TPromise } from 'vs/base/common/winjs.base';
J
Joao Moreno 已提交
8
import { assign } from 'vs/base/common/objects';
J
Joao Moreno 已提交
9 10
import { parseCLIProcessArgv, buildHelpMessage } from 'vs/platform/environment/node/argv';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
11 12
import product from 'vs/platform/node/product';
import pkg from 'vs/platform/node/package';
J
Joao Moreno 已提交
13

14 15 16
import * as fs from 'fs';
import * as paths from 'path';
import * as os from 'os';
B
Benjamin Pasero 已提交
17
import { whenDeleted } from 'vs/base/node/pfs';
18

J
Joao Moreno 已提交
19
function shouldSpawnCliProcess(argv: ParsedArgs): boolean {
20 21 22 23
	return !!argv['install-source']
		|| !!argv['list-extensions']
		|| !!argv['install-extension']
		|| !!argv['uninstall-extension'];
J
Joao Moreno 已提交
24 25 26 27 28 29
}

interface IMainCli {
	main: (argv: ParsedArgs) => TPromise<void>;
}

J
Joao Moreno 已提交
30 31
export function main(argv: string[]): TPromise<void> {
	let args: ParsedArgs;
J
Joao Moreno 已提交
32

J
Joao Moreno 已提交
33 34 35 36 37 38 39 40
	try {
		args = parseCLIProcessArgv(argv);
	} catch (err) {
		console.error(err.message);
		return TPromise.as(null);
	}

	if (args.help) {
J
Joao Moreno 已提交
41
		console.log(buildHelpMessage(product.nameLong, product.applicationName, pkg.version));
J
Joao Moreno 已提交
42
	} else if (args.version) {
43
		console.log(`${pkg.version}\n${product.commit}\n${process.arch}`);
J
Joao Moreno 已提交
44
	} else if (shouldSpawnCliProcess(args)) {
J
Joao Moreno 已提交
45
		const mainCli = new TPromise<IMainCli>(c => require(['vs/code/node/cliProcessMain'], c));
J
Joao Moreno 已提交
46
		return mainCli.then(cli => cli.main(args));
J
Joao Moreno 已提交
47
	} else {
48 49
		const env = assign({}, process.env, {
			// this will signal Code that it was spawned from this module
J
Joao Moreno 已提交
50 51
			'VSCODE_CLI': '1',
			'ELECTRON_NO_ATTACH_CONSOLE': '1'
52
		});
B
Benjamin Pasero 已提交
53

B
Benjamin Pasero 已提交
54
		delete env['ELECTRON_RUN_AS_NODE'];
J
Joao Moreno 已提交
55

B
Benjamin Pasero 已提交
56 57 58 59
		if (args.verbose) {
			env['ELECTRON_ENABLE_LOGGING'] = '1';
		}

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
		// If we are started with --wait create a random temporary file
		// and pass it over to the starting instance. We can use this file
		// to wait for it to be deleted to monitor that the edited file
		// is closed and then exit the waiting process.
		let waitMarkerFilePath: string;
		if (args.wait) {
			let waitMarkerError: Error;
			const randomTmpFile = paths.join(os.tmpdir(), Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10));
			try {
				fs.writeFileSync(randomTmpFile, '');
				waitMarkerFilePath = randomTmpFile;
				argv.push('--waitMarkerFilePath', waitMarkerFilePath);
			} catch (error) {
				waitMarkerError = error;
			}

			if (args.verbose) {
				if (waitMarkerError) {
					console.error(`Failed to create marker file for --wait: ${waitMarkerError.toString()}`);
				} else {
					console.log(`Marker file for --wait created: ${waitMarkerFilePath}`);
				}
			}
		}

B
Benjamin Pasero 已提交
85
		const options = {
D
Daniel Imms 已提交
86
			detached: true,
87
			env
88
		};
B
Benjamin Pasero 已提交
89

J
Joao Moreno 已提交
90
		if (!args.verbose) {
91 92 93
			options['stdio'] = 'ignore';
		}

J
Joao Moreno 已提交
94
		const child = spawn(process.execPath, argv.slice(2), options);
95

J
Joao Moreno 已提交
96
		if (args.verbose) {
J
Joao Moreno 已提交
97 98
			child.stdout.on('data', (data: Buffer) => console.log(data.toString('utf8').trim()));
			child.stderr.on('data', (data: Buffer) => console.log(data.toString('utf8').trim()));
99
		}
100

101
		if (args.verbose) {
102
			return new TPromise<void>(c => child.once('exit', () => c(null)));
103
		}
104 105 106 107 108 109 110 111

		if (args.wait && waitMarkerFilePath) {
			return new TPromise<void>(c => {

				// Complete when process exits
				child.once('exit', () => c(null));

				// Complete when wait marker file is deleted
B
Benjamin Pasero 已提交
112
				whenDeleted(waitMarkerFilePath).done(c, c);
113 114
			});
		}
J
Joao Moreno 已提交
115 116
	}

J
Joao Moreno 已提交
117
	return TPromise.as(null);
J
Joao Moreno 已提交
118 119
}

120 121 122 123
function eventuallyExit(code: number): void {
	setTimeout(() => process.exit(code), 0);
}

J
Joao Moreno 已提交
124
main(process.argv)
125
	.then(() => eventuallyExit(0))
J
Joao Moreno 已提交
126 127
	.then(null, err => {
		console.error(err.stack ? err.stack : err);
128
		eventuallyExit(1);
J
Joao Moreno 已提交
129
	});