提交 9de08e28 编写于 作者: J João Moreno

Merge pull request #5754 from joaomoreno/cli

Use minimist for argv handling
{ {
"name": "Code", "name": "Code",
"version": "1.0.0", "version": "1.0.1",
"dependencies": { "dependencies": {
"agent-base": { "agent-base": {
"version": "1.0.2", "version": "1.0.2",
...@@ -278,6 +278,11 @@ ...@@ -278,6 +278,11 @@
"from": "minimatch@>=0.2.12 <0.3.0", "from": "minimatch@>=0.2.12 <0.3.0",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz" "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz"
}, },
"minimist": {
"version": "1.2.0",
"from": "minimist@latest",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
},
"ms": { "ms": {
"version": "0.7.1", "version": "0.7.1",
"from": "ms@0.7.1", "from": "ms@0.7.1",
......
#!/usr/bin/env bash
if [[ "$OSTYPE" == "darwin"* ]]; then
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
ROOT=$(dirname $(dirname $(realpath "$0")))
else
ROOT=$(dirname $(dirname $(readlink -f $0)))
fi
function code() {
cd $ROOT
# Node modules
test -d node_modules || ./scripts/npm.sh install
# Get electron
./node_modules/.bin/gulp electron
# Build
test -d out || ./node_modules/.bin/gulp compile
# Launch Code
[[ "$OSTYPE" == "darwin"* ]] \
&& ELECTRON=.build/electron/Electron.app/Contents/MacOS/Electron \
|| ELECTRON=.build/electron/electron
CLI="$ROOT/out/cli.js"
ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 \
NODE_ENV=development \
VSCODE_DEV=1 \
ELECTRON_ENABLE_LOGGING=1 \
ELECTRON_ENABLE_STACK_DUMPING=1 \
"$ELECTRON" "$CLI" . $@
}
code "$@"
...@@ -6,5 +6,4 @@ ...@@ -6,5 +6,4 @@
"repositoryURL": "https://github.com/DefinitelyTyped/DefinitelyTyped", "repositoryURL": "https://github.com/DefinitelyTyped/DefinitelyTyped",
"license": "MIT", "license": "MIT",
"isDev": true "isDev": true
} }]
] \ No newline at end of file
\ No newline at end of file
// Type definitions for minimist 1.1.3
// Project: https://github.com/substack/minimist
// Definitions by: Bart van der Schoor <https://github.com/Bartvds>, Necroskillz <https://github.com/Necroskillz>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
declare module 'minimist' {
function minimist(args?: string[], opts?: minimist.Opts): minimist.ParsedArgs;
namespace minimist {
export interface Opts {
// a string or array of strings argument names to always treat as strings
string?: string|string[];
// a string or array of strings to always treat as booleans
boolean?: boolean|string|string[];
// an object mapping string names to strings or arrays of string argument names to use
alias?: {[key:string]: string|string[]};
// an object mapping string argument names to default values
default?: {[key:string]: any};
// when true, populate argv._ with everything after the first non-option
stopEarly?: boolean;
// a function which is invoked with a command line parameter not defined in the opts configuration object.
// If the function returns false, the unknown option is not added to argv
unknown?: (arg: string) => boolean;
// when true, populate argv._ with everything before the -- and argv['--'] with everything after the --
'--'?: boolean;
}
export interface ParsedArgs {
[arg: string]: any;
_: string[];
}
}
export = minimist;
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as os from 'os';
import * as minimist from 'minimist';
import pkg from './package';
export interface ParsedArgs extends minimist.ParsedArgs {
help: boolean;
version: boolean;
wait: boolean;
diff: boolean;
goto: boolean;
'new-window': boolean;
'reuse-window': boolean;
locale: string;
'user-data-dir': string;
performance: boolean;
verbose: boolean;
logExtensionHostCommunication: boolean;
'disable-extensions': boolean;
extensionHomePath: string;
extensionDevelopmentPath: string;
extensionTestsPath: string;
timestamp: string;
debugBrkPluginHost: string;
debugPluginHost: string;
}
const options: minimist.Opts = {
string: [
'locale',
'user-data-dir',
'extensionHomePath',
'extensionDevelopmentPath',
'extensionTestsPath',
'timestamp'
],
boolean: [
'help',
'version',
'wait',
'diff',
'goto',
'new-window',
'reuse-window',
'performance',
'verbose',
'logExtensionHostCommunication',
'disable-extensions'
],
alias: {
help: 'h',
version: 'v',
wait: 'w',
diff: 'd',
goto: 'g',
'new-window': 'n',
'reuse-window': 'r',
performance: 'p',
'disable-extensions': 'disableExtensions'
}
};
export function parseArgs(args: string[]) {
return minimist(args, options) as ParsedArgs;
}
const executable = 'code' + (os.platform() === 'win32' ? '.exe' : '');
const indent = ' ';
export const helpMessage = `Visual Studio Code v${ pkg.version }
Usage: ${ executable } [arguments] [paths...]
Options:
${ indent }-d, --diff Open a diff editor. Requires to pass two file paths
${ indent } as arguments.
${ indent }--disable-extensions Disable all installed extensions.
${ indent }-g, --goto Open the file at path at the line and column (add
${ indent } :line[:column] to path).
${ indent }-h, --help Print usage.
${ indent }--locale <locale> The locale to use (e.g. en-US or zh-TW).
${ indent }-n, --new-window Force a new instance of Code.
${ indent }-r, --reuse-window Force opening a file or folder in the last active
${ indent } window.
${ indent }--user-data-dir <dir> Specifies the directory that user data is kept in,
${ indent } useful when running as root.
${ indent }-v, --version Print version.
${ indent }-w, --wait Wait for the window to be closed before returning.`;
...@@ -3,73 +3,35 @@ ...@@ -3,73 +3,35 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as path from 'path';
import * as fs from 'fs';
import * as os from 'os';
import { spawn } from 'child_process'; import { spawn } from 'child_process';
import uri from 'vs/base/common/uri'; import { assign } from 'vs/base/common/objects';
import { parseArgs, helpMessage } from './argv';
import pkg from './package';
const rootPath = path.dirname(uri.parse(require.toUrl('')).fsPath); export function main(args: string[]) {
const packageJsonPath = path.join(rootPath, 'package.json'); const argv = parseArgs(args);
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
class ArgParser { if (argv.help) {
console.log(helpMessage);
constructor(private argv: string[]) {} } else if (argv.version) {
console.log(pkg.version);
hasFlag(flag, alias): boolean {
return (flag && this.argv.indexOf('--' + flag) >= 0)
|| (alias && this.argv.indexOf('-' + alias) >= 0);
}
help(): string {
const executable = 'code' + (os.platform() === 'win32' ? '.exe' : '');
const indent = ' ';
return `Visual Studio Code v${ packageJson.version }
Usage: ${ executable } [arguments] [paths...]
Options:
${ indent }-d, --diff Open a diff editor. Requires to pass two file paths
${ indent } as arguments.
${ indent }--disable-extensions Disable all installed extensions.
${ indent }-g, --goto Open the file at path at the line and column (add
${ indent } :line[:column] to path).
${ indent }-h, --help Print usage.
${ indent }--locale=LOCALE The locale to use (e.g. en-US or zh-TW).
${ indent }-n, --new-window Force a new instance of Code.
${ indent }-r, --reuse-window Force opening a file or folder in the last active
${ indent } window.
${ indent }--user-data-dir=DIR Specifies the directory that user data is kept in,
${ indent } useful when running as root.
${ indent }-v, --version Print version.
${ indent }-w, --wait Wait for the window to be closed before returning.`;
}
}
export function main(argv: string[]) {
const argParser = new ArgParser(argv);
let exit = true;
if (argParser.hasFlag('help', 'h')) {
console.log(argParser.help());
} else if (argParser.hasFlag('version', 'v')) {
console.log(packageJson.version);
} else { } else {
delete process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']; const env = assign({}, process.env);
if (argParser.hasFlag('wait', 'w')) { delete env['ATOM_SHELL_INTERNAL_RUN_AS_NODE'];
exit = false;
const child = spawn(process.execPath, args, {
detached: true,
stdio: 'ignore',
env
});
let child = spawn(process.execPath, process.argv.slice(2), { detached: true, stdio: 'ignore' }); if (argv.wait) {
child.on('exit', process.exit); child.on('exit', process.exit);
} else { return;
spawn(process.execPath, process.argv.slice(2), { detached: true, stdio: 'ignore' });
} }
} }
if (exit) { process.exit(0);
process.exit(0);
}
} }
main(process.argv.slice(2)); main(process.argv.slice(2));
...@@ -15,47 +15,10 @@ import strings = require('vs/base/common/strings'); ...@@ -15,47 +15,10 @@ import strings = require('vs/base/common/strings');
import paths = require('vs/base/common/paths'); import paths = require('vs/base/common/paths');
import platform = require('vs/base/common/platform'); import platform = require('vs/base/common/platform');
import uri from 'vs/base/common/uri'; import uri from 'vs/base/common/uri';
import { assign } from 'vs/base/common/objects';
import types = require('vs/base/common/types'); import types = require('vs/base/common/types');
import {ServiceIdentifier, createDecorator} from 'vs/platform/instantiation/common/instantiation'; import {ServiceIdentifier, createDecorator} from 'vs/platform/instantiation/common/instantiation';
import product, {IProductConfiguration} from './product';
export interface IProductConfiguration { import { parseArgs } from './argv';
nameShort: string;
nameLong: string;
applicationName: string;
win32AppUserModelId: string;
win32MutexName: string;
darwinBundleIdentifier: string;
dataFolderName: string;
downloadUrl: string;
updateUrl?: string;
quality?: string;
commit: string;
date: string;
extensionsGallery: {
serviceUrl: string;
itemUrl: string;
};
extensionTips: { [id: string]: string; };
crashReporter: Electron.CrashReporterStartOptions;
welcomePage: string;
enableTelemetry: boolean;
aiConfig: {
key: string;
asimovKey: string;
};
sendASmile: {
reportIssueUrl: string,
requestFeatureUrl: string
};
documentationUrl: string;
releaseNotesUrl: string;
twitterUrl: string;
requestFeatureUrl: string;
reportIssueUrl: string;
licenseUrl: string;
privacyStatementUrl: string;
}
export interface IProcessEnvironment { export interface IProcessEnvironment {
[key: string]: string; [key: string]: string;
...@@ -104,6 +67,20 @@ export interface IEnvironmentService { ...@@ -104,6 +67,20 @@ export interface IEnvironmentService {
sharedIPCHandle: string; sharedIPCHandle: string;
} }
function getNumericValue(value: string, defaultValue: number, fallback: number = void 0) {
const numericValue = parseInt(value);
if (types.isNumber(numericValue)) {
return numericValue;
}
if (value) {
return defaultValue;
}
return fallback;
}
export class EnvService implements IEnvironmentService { export class EnvService implements IEnvironmentService {
serviceId = IEnvironmentService; serviceId = IEnvironmentService;
...@@ -119,11 +96,9 @@ export class EnvService implements IEnvironmentService { ...@@ -119,11 +96,9 @@ export class EnvService implements IEnvironmentService {
get isBuilt(): boolean { return !process.env['VSCODE_DEV']; } get isBuilt(): boolean { return !process.env['VSCODE_DEV']; }
private _product: IProductConfiguration; get product(): IProductConfiguration { return product; }
get product(): IProductConfiguration { return this._product; } get updateUrl(): string { return product.updateUrl; }
get quality(): string { return product.quality; }
get updateUrl(): string { return this.product.updateUrl; }
get quality(): string { return this.product.quality; }
private _userHome: string; private _userHome: string;
get userHome(): string { return this._userHome; } get userHome(): string { return this._userHome; }
...@@ -184,58 +159,36 @@ export class EnvService implements IEnvironmentService { ...@@ -184,58 +159,36 @@ export class EnvService implements IEnvironmentService {
args = [...extraargs, ...args]; args = [...extraargs, ...args];
} }
const debugBrkExtensionHostPort = parseNumber(args, '--debugBrkPluginHost', 5870); const argv = parseArgs(args);
let debugExtensionHostPort: number;
let debugBrkExtensionHost: boolean;
if (debugBrkExtensionHostPort) { const debugBrkExtensionHostPort = getNumericValue(argv.debugBrkPluginHost, 5870);
debugExtensionHostPort = debugBrkExtensionHostPort; const debugExtensionHostPort = getNumericValue(argv.debugPluginHost, 5870, this.isBuilt ? void 0 : 5870);
debugBrkExtensionHost = true; const pathArguments = parsePathArguments(this._currentWorkingDirectory, argv._, argv.goto);
} else { const timestamp = parseInt(argv.timestamp);
debugExtensionHostPort = parseNumber(args, '--debugPluginHost', 5870, this.isBuilt ? void 0 : 5870);
}
const opts = parseOpts(args);
const gotoLineMode = !!opts['g'] || !!opts['goto'];
const pathArguments = parsePathArguments(this._currentWorkingDirectory, args, gotoLineMode);
this._cliArgs = Object.freeze({ this._cliArgs = Object.freeze({
pathArguments: pathArguments, pathArguments: pathArguments,
programStart: parseNumber(args, '--timestamp', 0, 0), programStart: types.isNumber(timestamp) ? timestamp : 0,
enablePerformance: !!opts['p'], enablePerformance: argv.performance,
verboseLogging: !!opts['verbose'], verboseLogging: argv.verbose,
debugExtensionHostPort: debugExtensionHostPort, debugExtensionHostPort: debugBrkExtensionHostPort || debugExtensionHostPort,
debugBrkExtensionHost: debugBrkExtensionHost, debugBrkExtensionHost: !!debugBrkExtensionHostPort,
logExtensionHostCommunication: !!opts['logExtensionHostCommunication'], logExtensionHostCommunication: argv.logExtensionHostCommunication,
openNewWindow: !!opts['n'] || !!opts['new-window'], openNewWindow: argv['new-window'],
openInSameWindow: !!opts['r'] || !!opts['reuse-window'], openInSameWindow: argv['reuse-window'],
gotoLineMode: gotoLineMode, gotoLineMode: argv.goto,
diffMode: (!!opts['d'] || !!opts['diff']) && pathArguments.length === 2, diffMode: argv.diff && pathArguments.length === 2,
extensionsHomePath: normalizePath(parseString(args, '--extensionHomePath')), extensionsHomePath: normalizePath(argv.extensionHomePath),
extensionDevelopmentPath: normalizePath(parseString(args, '--extensionDevelopmentPath')), extensionDevelopmentPath: normalizePath(argv.extensionDevelopmentPath),
extensionTestsPath: normalizePath(parseString(args, '--extensionTestsPath')), extensionTestsPath: normalizePath(argv.extensionTestsPath),
disableExtensions: !!opts['disableExtensions'] || !!opts['disable-extensions'], disableExtensions: argv['disable-extensions'],
locale: parseString(args, '--locale'), locale: argv.locale,
waitForWindowClose: !!opts['w'] || !!opts['wait'] waitForWindowClose: argv.wait
}); });
this._isTestingFromCli = this.cliArgs.extensionTestsPath && !this.cliArgs.debugBrkExtensionHost; this._isTestingFromCli = this.cliArgs.extensionTestsPath && !this.cliArgs.debugBrkExtensionHost;
try { this._userHome = path.join(app.getPath('home'), product.dataFolderName);
this._product = JSON.parse(fs.readFileSync(path.join(this._appRoot, 'product.json'), 'utf8'));
} catch (error) {
this._product = Object.create(null);
}
if (!this.isBuilt) {
const nameShort = `${ this._product.nameShort } Dev`;
const nameLong = `${ this._product.nameLong } Dev`;
const dataFolderName = `${ this._product.dataFolderName }-dev`;
this._product = assign(this._product, { nameShort, nameLong, dataFolderName });
}
this._userHome = path.join(app.getPath('home'), this._product.dataFolderName);
// TODO move out of here! // TODO move out of here!
if (!fs.existsSync(this._userHome)) { if (!fs.existsSync(this._userHome)) {
...@@ -299,57 +252,45 @@ export class EnvService implements IEnvironmentService { ...@@ -299,57 +252,45 @@ export class EnvService implements IEnvironmentService {
} }
} }
type OptionBag = { [opt: string]: boolean; }; function parsePathArguments(cwd: string, args: string[], gotoLineMode?: boolean): string[] {
const result = args.map(arg => {
let pathCandidate = arg;
function parseOpts(argv: string[]): OptionBag { let parsedPath: IParsedPath;
return argv if (gotoLineMode) {
.filter(a => /^-/.test(a)) parsedPath = parseLineAndColumnAware(arg);
.map(a => a.replace(/^-*/, '')) pathCandidate = parsedPath.path;
.reduce((r, a) => { r[a] = true; return r; }, <OptionBag>{}); }
}
function parsePathArguments(cwd: string, argv: string[], gotoLineMode?: boolean): string[] { if (pathCandidate) {
return arrays.coalesce( // no invalid paths pathCandidate = preparePath(cwd, pathCandidate);
arrays.distinct( // no duplicates }
argv.filter(a => !(/^-/.test(a))) // arguments without leading "-"
.map((arg) => { let realPath: string;
let pathCandidate = arg; try {
realPath = fs.realpathSync(pathCandidate);
let parsedPath: IParsedPath; } catch (error) {
if (gotoLineMode) { // in case of an error, assume the user wants to create this file
parsedPath = parseLineAndColumnAware(arg); // if the path is relative, we join it to the cwd
pathCandidate = parsedPath.path; realPath = path.normalize(path.isAbsolute(pathCandidate) ? pathCandidate : path.join(cwd, pathCandidate));
} }
if (pathCandidate) { if (!paths.isValidBasename(path.basename(realPath))) {
pathCandidate = preparePath(cwd, pathCandidate); return null; // do not allow invalid file names
} }
let realPath: string; if (gotoLineMode) {
try { parsedPath.path = realPath;
realPath = fs.realpathSync(pathCandidate); return toLineAndColumnPath(parsedPath);
} catch (error) { }
// in case of an error, assume the user wants to create this file
// if the path is relative, we join it to the cwd return realPath;
realPath = path.normalize(path.isAbsolute(pathCandidate) ? pathCandidate : path.join(cwd, pathCandidate)); });
}
const caseInsensitive = platform.isWindows || platform.isMacintosh;
if (!paths.isValidBasename(path.basename(realPath))) { const distinct = arrays.distinct(result, e => e && caseInsensitive ? e.toLowerCase() : e);
return null; // do not allow invalid file names
} return arrays.coalesce(distinct);
if (gotoLineMode) {
parsedPath.path = realPath;
return toLineAndColumnPath(parsedPath);
}
return realPath;
}),
(element) => {
return element && (platform.isWindows || platform.isMacintosh) ? element.toLowerCase() : element; // only linux is case sensitive on the fs
}
)
);
} }
function preparePath(cwd: string, p: string): string { function preparePath(cwd: string, p: string): string {
...@@ -378,34 +319,6 @@ function normalizePath(p?: string): string { ...@@ -378,34 +319,6 @@ function normalizePath(p?: string): string {
return p ? path.normalize(p) : p; return p ? path.normalize(p) : p;
} }
function parseNumber(argv: string[], key: string, defaultValue?: number, fallbackValue?: number): number {
let value: number;
for (let i = 0; i < argv.length; i++) {
let segments = argv[i].split('=');
if (segments[0] === key) {
value = Number(segments[1]) || defaultValue;
break;
}
}
return types.isNumber(value) ? value : fallbackValue;
}
function parseString(argv: string[], key: string, defaultValue?: string, fallbackValue?: string): string {
let value: string;
for (let i = 0; i < argv.length; i++) {
let segments = argv[i].split('=');
if (segments[0] === key) {
value = String(segments[1]) || defaultValue;
break;
}
}
return types.isString(value) ? strings.trim(value, '"') : fallbackValue;
}
export function getPlatformIdentifier(): string { export function getPlatformIdentifier(): string {
if (process.platform === 'linux') { if (process.platform === 'linux') {
return `linux-${process.arch}`; return `linux-${process.arch}`;
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as path from 'path';
import uri from 'vs/base/common/uri';
export interface IPackageConfiguration {
version: string;
}
const rootPath = path.dirname(uri.parse(require.toUrl('')).fsPath);
const packageJsonPath = path.join(rootPath, 'package.json');
export default require.__$__nodeRequire(packageJsonPath) as IPackageConfiguration;
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as path from 'path';
import uri from 'vs/base/common/uri';
export interface IProductConfiguration {
nameShort: string;
nameLong: string;
applicationName: string;
win32AppUserModelId: string;
win32MutexName: string;
darwinBundleIdentifier: string;
dataFolderName: string;
downloadUrl: string;
updateUrl?: string;
quality?: string;
commit: string;
date: string;
extensionsGallery: {
serviceUrl: string;
itemUrl: string;
};
extensionTips: { [id: string]: string; };
crashReporter: Electron.CrashReporterStartOptions;
welcomePage: string;
enableTelemetry: boolean;
aiConfig: {
key: string;
asimovKey: string;
};
sendASmile: {
reportIssueUrl: string,
requestFeatureUrl: string
};
documentationUrl: string;
releaseNotesUrl: string;
twitterUrl: string;
requestFeatureUrl: string;
reportIssueUrl: string;
licenseUrl: string;
privacyStatementUrl: string;
}
const rootPath = path.dirname(uri.parse(require.toUrl('')).fsPath);
const productJsonPath = path.join(rootPath, 'product.json');
const product = require.__$__nodeRequire(productJsonPath) as IProductConfiguration;
if (process.env['VSCODE_DEV']) {
product.nameShort += ' Dev';
product.nameLong += ' Dev';
product.dataFolderName += '-dev';
}
export default product;
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册