mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-05 01:25:38 -05:00
253 lines
6.6 KiB
TypeScript
253 lines
6.6 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
'use strict';
|
|
|
|
import NLS = require('vs/nls');
|
|
|
|
import * as Objects from 'vs/base/common/objects';
|
|
import * as Platform from 'vs/base/common/platform';
|
|
import { IStringDictionary } from 'vs/base/common/collections';
|
|
import * as Types from 'vs/base/common/types';
|
|
|
|
import { ValidationState, IProblemReporter, Parser } from 'vs/base/common/parsers';
|
|
|
|
/**
|
|
* Options to be passed to the external program or shell.
|
|
*/
|
|
export interface CommandOptions {
|
|
/**
|
|
* The current working directory of the executed program or shell.
|
|
* If omitted VSCode's current workspace root is used.
|
|
*/
|
|
cwd?: string;
|
|
|
|
/**
|
|
* The environment of the executed program or shell. If omitted
|
|
* the parent process' environment is used.
|
|
*/
|
|
env?: { [key: string]: string; };
|
|
}
|
|
|
|
export interface Executable {
|
|
/**
|
|
* The command to be executed. Can be an external program or a shell
|
|
* command.
|
|
*/
|
|
command: string;
|
|
|
|
/**
|
|
* Specifies whether the command is a shell command and therefore must
|
|
* be executed in a shell interpreter (e.g. cmd.exe, bash, ...).
|
|
*/
|
|
isShellCommand: boolean;
|
|
|
|
/**
|
|
* The arguments passed to the command.
|
|
*/
|
|
args: string[];
|
|
|
|
/**
|
|
* The command options used when the command is executed. Can be omitted.
|
|
*/
|
|
options?: CommandOptions;
|
|
}
|
|
|
|
export interface ForkOptions extends CommandOptions {
|
|
execArgv?: string[];
|
|
}
|
|
|
|
export enum Source {
|
|
stdout,
|
|
stderr
|
|
}
|
|
|
|
/**
|
|
* The data send via a success callback
|
|
*/
|
|
export interface SuccessData {
|
|
error?: Error;
|
|
cmdCode?: number;
|
|
terminated?: boolean;
|
|
}
|
|
|
|
/**
|
|
* The data send via a error callback
|
|
*/
|
|
export interface ErrorData {
|
|
error?: Error;
|
|
terminated?: boolean;
|
|
stdout?: string;
|
|
stderr?: string;
|
|
}
|
|
|
|
export interface TerminateResponse {
|
|
success: boolean;
|
|
code?: TerminateResponseCode;
|
|
error?: any;
|
|
}
|
|
|
|
export enum TerminateResponseCode {
|
|
Success = 0,
|
|
Unknown = 1,
|
|
AccessDenied = 2,
|
|
ProcessNotFound = 3,
|
|
}
|
|
|
|
export namespace Config {
|
|
/**
|
|
* Options to be passed to the external program or shell
|
|
*/
|
|
export interface CommandOptions {
|
|
/**
|
|
* The current working directory of the executed program or shell.
|
|
* If omitted VSCode's current workspace root is used.
|
|
*/
|
|
cwd?: string;
|
|
|
|
/**
|
|
* The additional environment of the executed program or shell. If omitted
|
|
* the parent process' environment is used.
|
|
*/
|
|
env?: IStringDictionary<string>;
|
|
|
|
/**
|
|
* Index signature
|
|
*/
|
|
[key: string]: string | string[] | IStringDictionary<string>;
|
|
}
|
|
|
|
export interface BaseExecutable {
|
|
/**
|
|
* The command to be executed. Can be an external program or a shell
|
|
* command.
|
|
*/
|
|
command?: string;
|
|
|
|
/**
|
|
* Specifies whether the command is a shell command and therefore must
|
|
* be executed in a shell interpreter (e.g. cmd.exe, bash, ...).
|
|
*
|
|
* Defaults to false if omitted.
|
|
*/
|
|
isShellCommand?: boolean;
|
|
|
|
/**
|
|
* The arguments passed to the command. Can be omitted.
|
|
*/
|
|
args?: string[];
|
|
|
|
/**
|
|
* The command options used when the command is executed. Can be omitted.
|
|
*/
|
|
options?: CommandOptions;
|
|
}
|
|
|
|
export interface Executable extends BaseExecutable {
|
|
|
|
/**
|
|
* Windows specific executable configuration
|
|
*/
|
|
windows?: BaseExecutable;
|
|
|
|
/**
|
|
* Mac specific executable configuration
|
|
*/
|
|
osx?: BaseExecutable;
|
|
|
|
/**
|
|
* Linux specific executable configuration
|
|
*/
|
|
linux?: BaseExecutable;
|
|
|
|
}
|
|
}
|
|
|
|
export interface ParserOptions {
|
|
globals?: Executable;
|
|
emptyCommand?: boolean;
|
|
noDefaults?: boolean;
|
|
}
|
|
|
|
export class ExecutableParser extends Parser {
|
|
|
|
constructor(logger: IProblemReporter) {
|
|
super(logger);
|
|
}
|
|
|
|
public parse(json: Config.Executable, parserOptions: ParserOptions = { globals: null, emptyCommand: false, noDefaults: false }): Executable {
|
|
let result = this.parseExecutable(json, parserOptions.globals);
|
|
if (this.problemReporter.status.isFatal()) {
|
|
return result;
|
|
}
|
|
let osExecutable: Executable;
|
|
if (json.windows && Platform.platform === Platform.Platform.Windows) {
|
|
osExecutable = this.parseExecutable(json.windows);
|
|
} else if (json.osx && Platform.platform === Platform.Platform.Mac) {
|
|
osExecutable = this.parseExecutable(json.osx);
|
|
} else if (json.linux && Platform.platform === Platform.Platform.Linux) {
|
|
osExecutable = this.parseExecutable(json.linux);
|
|
}
|
|
if (osExecutable) {
|
|
result = ExecutableParser.mergeExecutable(result, osExecutable);
|
|
}
|
|
if ((!result || !result.command) && !parserOptions.emptyCommand) {
|
|
this.fatal(NLS.localize('ExecutableParser.commandMissing', 'Error: executable info must define a command of type string.'));
|
|
return null;
|
|
}
|
|
if (!parserOptions.noDefaults) {
|
|
Parser.merge(result, {
|
|
command: undefined,
|
|
isShellCommand: false,
|
|
args: [],
|
|
options: {}
|
|
}, false);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public parseExecutable(json: Config.BaseExecutable, globals?: Executable): Executable {
|
|
let command: string = undefined;
|
|
let isShellCommand: boolean = undefined;
|
|
let args: string[] = undefined;
|
|
let options: CommandOptions = undefined;
|
|
|
|
if (this.is(json.command, Types.isString)) {
|
|
command = json.command;
|
|
}
|
|
if (this.is(json.isShellCommand, Types.isBoolean, ValidationState.Warning, NLS.localize('ExecutableParser.isShellCommand', 'Warning: isShellCommand must be of type boolean. Ignoring value {0}.', json.isShellCommand))) {
|
|
isShellCommand = json.isShellCommand;
|
|
}
|
|
if (this.is(json.args, Types.isStringArray, ValidationState.Warning, NLS.localize('ExecutableParser.args', 'Warning: args must be of type string[]. Ignoring value {0}.', json.isShellCommand))) {
|
|
args = json.args.slice(0);
|
|
}
|
|
if (this.is(json.options, Types.isObject)) {
|
|
options = this.parseCommandOptions(json.options);
|
|
}
|
|
return { command, isShellCommand, args, options };
|
|
}
|
|
|
|
private parseCommandOptions(json: Config.CommandOptions): CommandOptions {
|
|
let result: CommandOptions = {};
|
|
if (!json) {
|
|
return result;
|
|
}
|
|
if (this.is(json.cwd, Types.isString, ValidationState.Warning, NLS.localize('ExecutableParser.invalidCWD', 'Warning: options.cwd must be of type string. Ignoring value {0}.', json.cwd))) {
|
|
result.cwd = json.cwd;
|
|
}
|
|
if (!Types.isUndefined(json.env)) {
|
|
result.env = Objects.clone(json.env);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static mergeExecutable(executable: Executable, other: Executable): Executable {
|
|
if (!executable) {
|
|
return other;
|
|
}
|
|
Parser.merge(executable, other, true);
|
|
return executable;
|
|
}
|
|
}
|