mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-30 01:25:38 -05:00
Merge VS Code 1.21 source code (#1067)
* Initial VS Code 1.21 file copy with patches * A few more merges * Post npm install * Fix batch of build breaks * Fix more build breaks * Fix more build errors * Fix more build breaks * Runtime fixes 1 * Get connection dialog working with some todos * Fix a few packaging issues * Copy several node_modules to package build to fix loader issues * Fix breaks from master * A few more fixes * Make tests pass * First pass of license header updates * Second pass of license header updates * Fix restore dialog issues * Remove add additional themes menu items * fix select box issues where the list doesn't show up * formatting * Fix editor dispose issue * Copy over node modules to correct location on all platforms
This commit is contained in:
@@ -151,20 +151,16 @@ export class ConfigWatcher<T> implements IConfigWatcher<T>, IDisposable {
|
||||
return; // avoid watchers that will never get disposed by checking for being disposed
|
||||
}
|
||||
|
||||
try {
|
||||
const watcher = extfs.watch(path, (type, file) => this.onConfigFileChange(type, file, isParentFolder));
|
||||
watcher.on('error', (code: number, signal: string) => this.options.onError(`Error watching ${path} for configuration changes (${code}, ${signal})`));
|
||||
const watcher = extfs.watch(path,
|
||||
(type, file) => this.onConfigFileChange(type, file, isParentFolder),
|
||||
(error: string) => this.options.onError(error)
|
||||
);
|
||||
|
||||
if (watcher) {
|
||||
this.disposables.push(toDisposable(() => {
|
||||
watcher.removeAllListeners();
|
||||
watcher.close();
|
||||
}));
|
||||
} catch (error) {
|
||||
fs.exists(path, exists => {
|
||||
if (exists) {
|
||||
this.options.onError(`Failed to watch ${path} for configuration changes (${error.toString()})`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ export function getFirstFrame(arg0: IRemoteConsoleLog | string): IStackFrame {
|
||||
// at e.$executeContributedCommand(c:\Users\someone\Desktop\end-js\extension.js:19:17)
|
||||
const stack = arg0;
|
||||
if (stack) {
|
||||
const topFrame = stack.split('\n')[0];
|
||||
const topFrame = findFirstFrame(stack);
|
||||
|
||||
// at [^\/]* => line starts with "at" followed by any character except '/' (to not capture unix paths too late)
|
||||
// (?:(?:[a-zA-Z]+:)|(?:[\/])|(?:\\\\) => windows drive letter OR unix root OR unc root
|
||||
@@ -88,12 +88,25 @@ export function getFirstFrame(arg0: IRemoteConsoleLog | string): IStackFrame {
|
||||
return void 0;
|
||||
}
|
||||
|
||||
function findFirstFrame(stack: string): string {
|
||||
if (!stack) {
|
||||
return stack;
|
||||
}
|
||||
|
||||
const newlineIndex = stack.indexOf('\n');
|
||||
if (newlineIndex === -1) {
|
||||
return stack;
|
||||
}
|
||||
|
||||
return stack.substring(0, newlineIndex);
|
||||
}
|
||||
|
||||
export function log(entry: IRemoteConsoleLog, label: string): void {
|
||||
const { args, stack } = parse(entry);
|
||||
|
||||
const isOneStringArg = typeof args[0] === 'string' && args.length === 1;
|
||||
|
||||
let topFrame = stack && stack.split('\n')[0];
|
||||
let topFrame = findFirstFrame(stack);
|
||||
if (topFrame) {
|
||||
topFrame = `(${topFrame.trim()})`;
|
||||
}
|
||||
|
||||
@@ -28,11 +28,11 @@ export function bomLength(encoding: string): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function decode(buffer: NodeBuffer, encoding: string, options?: any): string {
|
||||
return iconv.decode(buffer, toNodeEncoding(encoding), options);
|
||||
export function decode(buffer: NodeBuffer, encoding: string): string {
|
||||
return iconv.decode(buffer, toNodeEncoding(encoding));
|
||||
}
|
||||
|
||||
export function encode(content: string, encoding: string, options?: any): NodeBuffer {
|
||||
export function encode(content: string | NodeBuffer, encoding: string, options?: { addBOM?: boolean }): NodeBuffer {
|
||||
return iconv.encode(content, toNodeEncoding(encoding), options);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,10 @@ export function decodeStream(encoding: string): NodeJS.ReadWriteStream {
|
||||
return iconv.decodeStream(toNodeEncoding(encoding));
|
||||
}
|
||||
|
||||
export function encodeStream(encoding: string, options?: { addBOM?: boolean }): NodeJS.ReadWriteStream {
|
||||
return iconv.encodeStream(toNodeEncoding(encoding), options);
|
||||
}
|
||||
|
||||
function toNodeEncoding(enc: string): string {
|
||||
if (enc === UTF8_with_bom) {
|
||||
return UTF8; // iconv does not distinguish UTF 8 with or without BOM, so we need to help it
|
||||
@@ -181,6 +185,7 @@ const windowsTerminalEncodings = {
|
||||
'865': 'cp865', // Nordic
|
||||
'866': 'cp866', // Russian
|
||||
'869': 'cp869', // Modern Greek
|
||||
'936': 'cp936', // Simplified Chinese
|
||||
'1252': 'cp1252' // West European Latin
|
||||
};
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@ import * as uuid from 'vs/base/common/uuid';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as flow from 'vs/base/node/flow';
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as paths from 'path';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { nfcall } from 'vs/base/common/async';
|
||||
import { encode, encodeStream } from 'vs/base/node/encoding';
|
||||
|
||||
const loop = flow.loop;
|
||||
|
||||
@@ -43,6 +43,27 @@ export function readdir(path: string, callback: (error: Error, files: string[])
|
||||
return fs.readdir(path, callback);
|
||||
}
|
||||
|
||||
export interface IStatAndLink {
|
||||
stat: fs.Stats;
|
||||
isSymbolicLink: boolean;
|
||||
}
|
||||
|
||||
export function statLink(path: string, callback: (error: Error, statAndIsLink: IStatAndLink) => void): void {
|
||||
fs.lstat(path, (error, lstat) => {
|
||||
if (error || lstat.isSymbolicLink()) {
|
||||
fs.stat(path, (error, stat) => {
|
||||
if (error) {
|
||||
return callback(error, null);
|
||||
}
|
||||
|
||||
callback(null, { stat, isSymbolicLink: lstat && lstat.isSymbolicLink() });
|
||||
});
|
||||
} else {
|
||||
callback(null, { stat: lstat, isSymbolicLink: false });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function copy(source: string, target: string, callback: (error: Error) => void, copiedSources?: { [path: string]: boolean }): void {
|
||||
if (!copiedSources) {
|
||||
copiedSources = Object.create(null);
|
||||
@@ -54,7 +75,7 @@ export function copy(source: string, target: string, callback: (error: Error) =>
|
||||
}
|
||||
|
||||
if (!stat.isDirectory()) {
|
||||
return pipeFs(source, target, stat.mode & 511, callback);
|
||||
return doCopyFile(source, target, stat.mode & 511, callback);
|
||||
}
|
||||
|
||||
if (copiedSources[source]) {
|
||||
@@ -75,6 +96,38 @@ export function copy(source: string, target: string, callback: (error: Error) =>
|
||||
});
|
||||
}
|
||||
|
||||
function doCopyFile(source: string, target: string, mode: number, callback: (error: Error) => void): void {
|
||||
const reader = fs.createReadStream(source);
|
||||
const writer = fs.createWriteStream(target, { mode });
|
||||
|
||||
let finished = false;
|
||||
const finish = (error?: Error) => {
|
||||
if (!finished) {
|
||||
finished = true;
|
||||
|
||||
// in error cases, pass to callback
|
||||
if (error) {
|
||||
callback(error);
|
||||
}
|
||||
|
||||
// we need to explicitly chmod because of https://github.com/nodejs/node/issues/1104
|
||||
else {
|
||||
fs.chmod(target, mode, callback);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// handle errors properly
|
||||
reader.once('error', error => finish(error));
|
||||
writer.once('error', error => finish(error));
|
||||
|
||||
// we are done (underlying fd has been closed)
|
||||
writer.once('close', () => finish());
|
||||
|
||||
// start piping
|
||||
reader.pipe(writer);
|
||||
}
|
||||
|
||||
export function mkdirp(path: string, mode?: number): TPromise<boolean> {
|
||||
const mkdir = () => nfcall(fs.mkdir, path, mode)
|
||||
.then(null, (err: NodeJS.ErrnoException) => {
|
||||
@@ -88,11 +141,12 @@ export function mkdirp(path: string, mode?: number): TPromise<boolean> {
|
||||
return TPromise.wrapError<boolean>(err);
|
||||
});
|
||||
|
||||
// is root?
|
||||
// stop at root
|
||||
if (path === paths.dirname(path)) {
|
||||
return TPromise.as(true);
|
||||
}
|
||||
|
||||
// recursively mkdir
|
||||
return mkdir().then(null, (err: NodeJS.ErrnoException) => {
|
||||
if (err.code === 'ENOENT') {
|
||||
return mkdirp(paths.dirname(path), mode).then(mkdir);
|
||||
@@ -102,40 +156,6 @@ export function mkdirp(path: string, mode?: number): TPromise<boolean> {
|
||||
});
|
||||
}
|
||||
|
||||
function pipeFs(source: string, target: string, mode: number, callback: (error: Error) => void): void {
|
||||
let callbackHandled = false;
|
||||
|
||||
const readStream = fs.createReadStream(source);
|
||||
const writeStream = fs.createWriteStream(target, { mode: mode });
|
||||
|
||||
const onError = (error: Error) => {
|
||||
if (!callbackHandled) {
|
||||
callbackHandled = true;
|
||||
callback(error);
|
||||
}
|
||||
};
|
||||
|
||||
readStream.on('error', onError);
|
||||
writeStream.on('error', onError);
|
||||
|
||||
readStream.on('end', () => {
|
||||
(<any>writeStream).end(() => { // In this case the write stream is known to have an end signature with callback
|
||||
if (!callbackHandled) {
|
||||
callbackHandled = true;
|
||||
|
||||
fs.chmod(target, mode, callback); // we need to explicitly chmod because of https://github.com/nodejs/node/issues/1104
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// In node 0.8 there is no easy way to find out when the pipe operation has finished. As such, we use the end property = false
|
||||
// so that we are in charge of calling end() on the write stream and we will be notified when the write stream is really done.
|
||||
// We can do this because file streams have an end() method that allows to pass in a callback.
|
||||
// In node 0.10 there is an event 'finish' emitted from the write stream that can be used. See
|
||||
// https://groups.google.com/forum/?fromgroups=#!topic/nodejs/YWQ1sRoXOdI
|
||||
readStream.pipe(writeStream, { end: false });
|
||||
}
|
||||
|
||||
// Deletes the given path by first moving it out of the workspace. This has two benefits. For one, the operation can return fast because
|
||||
// after the rename, the contents are out of the workspace although not yet deleted. The greater benefit however is that this operation
|
||||
// will fail in case any file is used by another process. fs.unlink() in node will not bail if a file unlinked is used by another process.
|
||||
@@ -320,19 +340,124 @@ export function mv(source: string, target: string, callback: (error: Error) => v
|
||||
});
|
||||
}
|
||||
|
||||
export interface IWriteFileOptions {
|
||||
mode?: number;
|
||||
flag?: string;
|
||||
encoding?: {
|
||||
charset: string;
|
||||
addBOM: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
let canFlush = true;
|
||||
export function writeFileAndFlush(path: string, data: string | NodeBuffer | NodeJS.ReadableStream, options: IWriteFileOptions, callback: (error?: Error) => void): void {
|
||||
options = ensureOptions(options);
|
||||
|
||||
if (typeof data === 'string' || Buffer.isBuffer(data)) {
|
||||
doWriteFileAndFlush(path, data, options, callback);
|
||||
} else {
|
||||
doWriteFileStreamAndFlush(path, data, options, callback);
|
||||
}
|
||||
}
|
||||
|
||||
function doWriteFileStreamAndFlush(path: string, reader: NodeJS.ReadableStream, options: IWriteFileOptions, callback: (error?: Error) => void): void {
|
||||
|
||||
// finish only once
|
||||
let finished = false;
|
||||
const finish = (error?: Error) => {
|
||||
if (!finished) {
|
||||
finished = true;
|
||||
|
||||
// in error cases we need to manually close streams
|
||||
// if the write stream was successfully opened
|
||||
if (error) {
|
||||
if (isOpen) {
|
||||
writer.once('close', () => callback(error));
|
||||
writer.close();
|
||||
} else {
|
||||
callback(error);
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise just return without error
|
||||
else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// create writer to target. we set autoClose: false because we want to use the streams
|
||||
// file descriptor to call fs.fdatasync to ensure the data is flushed to disk
|
||||
const writer = fs.createWriteStream(path, { mode: options.mode, flags: options.flag, autoClose: false });
|
||||
|
||||
// Event: 'open'
|
||||
// Purpose: save the fd for later use and start piping
|
||||
// Notes: will not be called when there is an error opening the file descriptor!
|
||||
let fd: number;
|
||||
let isOpen: boolean;
|
||||
writer.once('open', descriptor => {
|
||||
fd = descriptor;
|
||||
isOpen = true;
|
||||
|
||||
// if an encoding is provided, we need to pipe the stream through
|
||||
// an encoder stream and forward the encoding related options
|
||||
if (options.encoding) {
|
||||
reader = reader.pipe(encodeStream(options.encoding.charset, { addBOM: options.encoding.addBOM }));
|
||||
}
|
||||
|
||||
// start data piping only when we got a successful open. this ensures that we do
|
||||
// not consume the stream when an error happens and helps to fix this issue:
|
||||
// https://github.com/Microsoft/vscode/issues/42542
|
||||
reader.pipe(writer);
|
||||
});
|
||||
|
||||
// Event: 'error'
|
||||
// Purpose: to return the error to the outside and to close the write stream (does not happen automatically)
|
||||
reader.once('error', error => finish(error));
|
||||
writer.once('error', error => finish(error));
|
||||
|
||||
// Event: 'finish'
|
||||
// Purpose: use fs.fdatasync to flush the contents to disk
|
||||
// Notes: event is called when the writer has finished writing to the underlying resource. we must call writer.close()
|
||||
// because we have created the WriteStream with autoClose: false
|
||||
writer.once('finish', () => {
|
||||
|
||||
// flush to disk
|
||||
if (canFlush && isOpen) {
|
||||
fs.fdatasync(fd, (syncError: Error) => {
|
||||
|
||||
// In some exotic setups it is well possible that node fails to sync
|
||||
// In that case we disable flushing and warn to the console
|
||||
if (syncError) {
|
||||
console.warn('[node.js fs] fdatasync is now disabled for this session because it failed: ', syncError);
|
||||
canFlush = false;
|
||||
}
|
||||
|
||||
writer.close();
|
||||
});
|
||||
} else {
|
||||
writer.close();
|
||||
}
|
||||
});
|
||||
|
||||
// Event: 'close'
|
||||
// Purpose: signal we are done to the outside
|
||||
// Notes: event is called when the writer's filedescriptor is closed
|
||||
writer.once('close', () => finish());
|
||||
}
|
||||
|
||||
// Calls fs.writeFile() followed by a fs.sync() call to flush the changes to disk
|
||||
// We do this in cases where we want to make sure the data is really on disk and
|
||||
// not in some cache.
|
||||
//
|
||||
// See https://github.com/nodejs/node/blob/v5.10.0/lib/fs.js#L1194
|
||||
let canFlush = true;
|
||||
export function writeFileAndFlush(path: string, data: string | NodeBuffer, options: { mode?: number; flag?: string; }, callback: (error: Error) => void): void {
|
||||
if (!canFlush) {
|
||||
return fs.writeFile(path, data, options, callback);
|
||||
function doWriteFileAndFlush(path: string, data: string | NodeBuffer, options: IWriteFileOptions, callback: (error?: Error) => void): void {
|
||||
if (options.encoding) {
|
||||
data = encode(data, options.encoding.charset, { addBOM: options.encoding.addBOM });
|
||||
}
|
||||
|
||||
if (!options) {
|
||||
options = { mode: 0o666, flag: 'w' };
|
||||
if (!canFlush) {
|
||||
return fs.writeFile(path, data, { mode: options.mode, flag: options.flag }, callback);
|
||||
}
|
||||
|
||||
// Open the file with same flags and mode as fs.writeFile()
|
||||
@@ -363,13 +488,15 @@ export function writeFileAndFlush(path: string, data: string | NodeBuffer, optio
|
||||
});
|
||||
}
|
||||
|
||||
export function writeFileAndFlushSync(path: string, data: string | NodeBuffer, options?: { mode?: number; flag?: string; }): void {
|
||||
if (!canFlush) {
|
||||
return fs.writeFileSync(path, data, options);
|
||||
export function writeFileAndFlushSync(path: string, data: string | NodeBuffer, options?: IWriteFileOptions): void {
|
||||
options = ensureOptions(options);
|
||||
|
||||
if (options.encoding) {
|
||||
data = encode(data, options.encoding.charset, { addBOM: options.encoding.addBOM });
|
||||
}
|
||||
|
||||
if (!options) {
|
||||
options = { mode: 0o666, flag: 'w' };
|
||||
if (!canFlush) {
|
||||
return fs.writeFileSync(path, data, { mode: options.mode, flag: options.flag });
|
||||
}
|
||||
|
||||
// Open the file with same flags and mode as fs.writeFile()
|
||||
@@ -392,6 +519,24 @@ export function writeFileAndFlushSync(path: string, data: string | NodeBuffer, o
|
||||
}
|
||||
}
|
||||
|
||||
function ensureOptions(options?: IWriteFileOptions): IWriteFileOptions {
|
||||
if (!options) {
|
||||
return { mode: 0o666, flag: 'w' };
|
||||
}
|
||||
|
||||
const ensuredOptions: IWriteFileOptions = { mode: options.mode, flag: options.flag, encoding: options.encoding };
|
||||
|
||||
if (typeof ensuredOptions.mode !== 'number') {
|
||||
ensuredOptions.mode = 0o666;
|
||||
}
|
||||
|
||||
if (typeof ensuredOptions.flag !== 'string') {
|
||||
ensuredOptions.flag = 'w';
|
||||
}
|
||||
|
||||
return ensuredOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied from: https://github.com/Microsoft/vscode-node-debug/blob/master/src/node/pathUtilities.ts#L83
|
||||
*
|
||||
@@ -474,21 +619,34 @@ function normalizePath(path: string): string {
|
||||
return strings.rtrim(paths.normalize(path), paths.sep);
|
||||
}
|
||||
|
||||
export function watch(path: string, onChange: (type: string, path: string) => void): fs.FSWatcher {
|
||||
const watcher = fs.watch(path);
|
||||
watcher.on('change', (type, raw) => {
|
||||
let file: string = null;
|
||||
if (raw) { // https://github.com/Microsoft/vscode/issues/38191
|
||||
file = raw.toString();
|
||||
if (platform.isMacintosh) {
|
||||
// Mac: uses NFD unicode form on disk, but we want NFC
|
||||
// See also https://github.com/nodejs/node/issues/2165
|
||||
file = strings.normalizeNFC(file);
|
||||
export function watch(path: string, onChange: (type: string, path: string) => void, onError: (error: string) => void): fs.FSWatcher {
|
||||
try {
|
||||
const watcher = fs.watch(path);
|
||||
|
||||
watcher.on('change', (type, raw) => {
|
||||
let file: string = null;
|
||||
if (raw) { // https://github.com/Microsoft/vscode/issues/38191
|
||||
file = raw.toString();
|
||||
if (platform.isMacintosh) {
|
||||
// Mac: uses NFD unicode form on disk, but we want NFC
|
||||
// See also https://github.com/nodejs/node/issues/2165
|
||||
file = strings.normalizeNFC(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onChange(type, file);
|
||||
});
|
||||
onChange(type, file);
|
||||
});
|
||||
|
||||
return watcher;
|
||||
}
|
||||
watcher.on('error', (code: number, signal: string) => onError(`Failed to watch ${path} for changes (${code}, ${signal})`));
|
||||
|
||||
return watcher;
|
||||
} catch (error) {
|
||||
fs.exists(path, exists => {
|
||||
if (exists) {
|
||||
onError(`Failed to watch ${path} for changes (${error.toString()})`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return void 0;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export function readdir(path: string): TPromise<string[]> {
|
||||
}
|
||||
|
||||
export function exists(path: string): TPromise<boolean> {
|
||||
return new TPromise(c => fs.exists(path, c));
|
||||
return new TPromise(c => fs.exists(path, c), () => { });
|
||||
}
|
||||
|
||||
export function chmod(path: string, mode: number): TPromise<boolean> {
|
||||
@@ -54,6 +54,10 @@ export function stat(path: string): TPromise<fs.Stats> {
|
||||
return nfcall(fs.stat, path);
|
||||
}
|
||||
|
||||
export function statLink(path: string): TPromise<{ stat: fs.Stats, isSymbolicLink: boolean }> {
|
||||
return nfcall(extfs.statLink, path);
|
||||
}
|
||||
|
||||
export function lstat(path: string): TPromise<fs.Stats> {
|
||||
return nfcall(fs.lstat, path);
|
||||
}
|
||||
@@ -99,10 +103,11 @@ export function readFile(path: string, encoding?: string): TPromise<Buffer | str
|
||||
// Therefor we use a Queue on the path that is given to us to sequentialize calls to the same path properly.
|
||||
const writeFilePathQueue: { [path: string]: Queue<void> } = Object.create(null);
|
||||
|
||||
export function writeFile(path: string, data: string, options?: { mode?: number; flag?: string; }): TPromise<void>;
|
||||
export function writeFile(path: string, data: NodeBuffer, options?: { mode?: number; flag?: string; }): TPromise<void>;
|
||||
export function writeFile(path: string, data: any, options?: { mode?: number; flag?: string; }): TPromise<void> {
|
||||
let queueKey = toQueueKey(path);
|
||||
export function writeFile(path: string, data: string, options?: extfs.IWriteFileOptions): TPromise<void>;
|
||||
export function writeFile(path: string, data: NodeBuffer, options?: extfs.IWriteFileOptions): TPromise<void>;
|
||||
export function writeFile(path: string, data: NodeJS.ReadableStream, options?: extfs.IWriteFileOptions): TPromise<void>;
|
||||
export function writeFile(path: string, data: any, options?: extfs.IWriteFileOptions): TPromise<void> {
|
||||
const queueKey = toQueueKey(path);
|
||||
|
||||
return ensureWriteFileQueue(queueKey).queue(() => nfcall(extfs.writeFileAndFlush, path, data, options));
|
||||
}
|
||||
@@ -160,8 +165,14 @@ export function fileExists(path: string): TPromise<boolean> {
|
||||
/**
|
||||
* Deletes a path from disk.
|
||||
*/
|
||||
const tmpDir = os.tmpdir();
|
||||
export function del(path: string, tmp = tmpDir): TPromise<void> {
|
||||
let _tmpDir: string = null;
|
||||
function getTmpDir(): string {
|
||||
if (!_tmpDir) {
|
||||
_tmpDir = os.tmpdir();
|
||||
}
|
||||
return _tmpDir;
|
||||
}
|
||||
export function del(path: string, tmp = getTmpDir()): TPromise<void> {
|
||||
return nfcall(extfs.del, path, tmp);
|
||||
}
|
||||
|
||||
@@ -184,4 +195,4 @@ export function whenDeleted(path: string): TPromise<void> {
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,15 @@
|
||||
|
||||
import net = require('net');
|
||||
|
||||
/**
|
||||
* @returns Returns a random port between 1025 and 65535.
|
||||
*/
|
||||
export function randomPort(): number {
|
||||
let min = 1025;
|
||||
let max = 65535;
|
||||
return min + Math.floor((max - min) * Math.random());
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a start point and a max number of retries, will find a port that
|
||||
* is openable. Will return 0 in case no free port can be found.
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
|
||||
import path = require('path');
|
||||
import * as cp from 'child_process';
|
||||
import ChildProcess = cp.ChildProcess;
|
||||
import exec = cp.exec;
|
||||
import spawn = cp.spawn;
|
||||
import { fork } from 'vs/base/node/stdFork';
|
||||
import nls = require('vs/nls');
|
||||
import { PPromise, TPromise, TValueCallback, TProgressCallback, ErrorCallback } from 'vs/base/common/winjs.base';
|
||||
@@ -40,7 +37,7 @@ function getWindowsCode(status: number): TerminateResponseCode {
|
||||
}
|
||||
}
|
||||
|
||||
export function terminateProcess(process: ChildProcess, cwd?: string): TerminateResponse {
|
||||
export function terminateProcess(process: cp.ChildProcess, cwd?: string): TerminateResponse {
|
||||
if (Platform.isWindows) {
|
||||
try {
|
||||
let options: any = {
|
||||
@@ -80,8 +77,8 @@ export abstract class AbstractProcess<TProgressData> {
|
||||
private options: CommandOptions | ForkOptions;
|
||||
protected shell: boolean;
|
||||
|
||||
private childProcess: ChildProcess;
|
||||
protected childProcessPromise: TPromise<ChildProcess>;
|
||||
private childProcess: cp.ChildProcess;
|
||||
protected childProcessPromise: TPromise<cp.ChildProcess>;
|
||||
protected terminateRequested: boolean;
|
||||
|
||||
private static WellKnowCommands: IStringDictionary<boolean> = {
|
||||
@@ -173,7 +170,7 @@ export abstract class AbstractProcess<TProgressData> {
|
||||
if (this.args) {
|
||||
cmd = cmd + ' ' + this.args.join(' ');
|
||||
}
|
||||
this.childProcess = exec(cmd, this.options, (error, stdout, stderr) => {
|
||||
this.childProcess = cp.exec(cmd, this.options, (error, stdout, stderr) => {
|
||||
this.childProcess = null;
|
||||
let err: any = error;
|
||||
// This is tricky since executing a command shell reports error back in case the executed command return an
|
||||
@@ -186,7 +183,7 @@ export abstract class AbstractProcess<TProgressData> {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
let childProcess: ChildProcess = null;
|
||||
let childProcess: cp.ChildProcess = null;
|
||||
let closeHandler = (data: any) => {
|
||||
this.childProcess = null;
|
||||
this.childProcessPromise = null;
|
||||
@@ -231,13 +228,13 @@ export abstract class AbstractProcess<TProgressData> {
|
||||
} else {
|
||||
args.push(commandLine.join(' '));
|
||||
}
|
||||
childProcess = spawn(getWindowsShell(), args, options);
|
||||
childProcess = cp.spawn(getWindowsShell(), args, options);
|
||||
} else {
|
||||
if (this.cmd) {
|
||||
childProcess = spawn(this.cmd, this.args, this.options);
|
||||
childProcess = cp.spawn(this.cmd, this.args, this.options);
|
||||
} else if (this.module) {
|
||||
this.childProcessPromise = new TPromise<ChildProcess>((c, e, p) => {
|
||||
fork(this.module, this.args, <ForkOptions>this.options, (error: any, childProcess: ChildProcess) => {
|
||||
this.childProcessPromise = new TPromise<cp.ChildProcess>((c, e, p) => {
|
||||
fork(this.module, this.args, <ForkOptions>this.options, (error: any, childProcess: cp.ChildProcess) => {
|
||||
if (error) {
|
||||
e(error);
|
||||
ee({ terminated: this.terminateRequested, error: error });
|
||||
@@ -269,7 +266,7 @@ export abstract class AbstractProcess<TProgressData> {
|
||||
}
|
||||
|
||||
protected abstract handleExec(cc: TValueCallback<SuccessData>, pp: TProgressCallback<TProgressData>, error: Error, stdout: Buffer, stderr: Buffer): void;
|
||||
protected abstract handleSpawn(childProcess: ChildProcess, cc: TValueCallback<SuccessData>, pp: TProgressCallback<TProgressData>, ee: ErrorCallback, sync: boolean): void;
|
||||
protected abstract handleSpawn(childProcess: cp.ChildProcess, cc: TValueCallback<SuccessData>, pp: TProgressCallback<TProgressData>, ee: ErrorCallback, sync: boolean): void;
|
||||
|
||||
protected handleClose(data: any, cc: TValueCallback<SuccessData>, pp: TProgressCallback<TProgressData>, ee: ErrorCallback): void {
|
||||
// Default is to do nothing.
|
||||
@@ -315,7 +312,7 @@ export abstract class AbstractProcess<TProgressData> {
|
||||
if (!this.shell || !Platform.isWindows) {
|
||||
c(false);
|
||||
}
|
||||
let cmdShell = spawn(getWindowsShell(), ['/s', '/c']);
|
||||
let cmdShell = cp.spawn(getWindowsShell(), ['/s', '/c']);
|
||||
cmdShell.on('error', (error: Error) => {
|
||||
c(true);
|
||||
});
|
||||
@@ -353,7 +350,7 @@ export class LineProcess extends AbstractProcess<LineData> {
|
||||
cc({ terminated: this.terminateRequested, error: error });
|
||||
}
|
||||
|
||||
protected handleSpawn(childProcess: ChildProcess, cc: TValueCallback<SuccessData>, pp: TProgressCallback<LineData>, ee: ErrorCallback, sync: boolean): void {
|
||||
protected handleSpawn(childProcess: cp.ChildProcess, cc: TValueCallback<SuccessData>, pp: TProgressCallback<LineData>, ee: ErrorCallback, sync: boolean): void {
|
||||
this.stdoutLineDecoder = new LineDecoder();
|
||||
this.stderrLineDecoder = new LineDecoder();
|
||||
childProcess.stdout.on('data', (data: Buffer) => {
|
||||
@@ -384,7 +381,7 @@ export interface IQueuedSender {
|
||||
// queue is free again to consume messages.
|
||||
// On Windows we always wait for the send() method to return before sending the next message
|
||||
// to workaround https://github.com/nodejs/node/issues/7657 (IPC can freeze process)
|
||||
export function createQueuedSender(childProcess: ChildProcess | NodeJS.Process): IQueuedSender {
|
||||
export function createQueuedSender(childProcess: cp.ChildProcess | NodeJS.Process): IQueuedSender {
|
||||
let msgQueue: string[] = [];
|
||||
let useQueue = false;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import { spawn, exec } from 'child_process';
|
||||
import * as path from 'path';
|
||||
import * as nls from 'vs/nls';
|
||||
import URI from 'vs/base/common/uri';
|
||||
|
||||
export interface ProcessItem {
|
||||
@@ -61,12 +62,30 @@ export function listProcesses(rootPid: number): Promise<ProcessItem> {
|
||||
function findName(cmd: string): string {
|
||||
|
||||
const RENDERER_PROCESS_HINT = /--disable-blink-features=Auxclick/;
|
||||
const WINDOWS_WATCHER_HINT = /\\watcher\\win32\\CodeHelper.exe/;
|
||||
const WINDOWS_WATCHER_HINT = /\\watcher\\win32\\CodeHelper\.exe/;
|
||||
const WINDOWS_CRASH_REPORTER = /--crashes-directory/;
|
||||
const WINDOWS_PTY = /\\pipe\\winpty-control/;
|
||||
const WINDOWS_CONSOLE_HOST = /conhost\.exe/;
|
||||
const TYPE = /--type=([a-zA-Z-]+)/;
|
||||
|
||||
// find windows file watcher
|
||||
if (WINDOWS_WATCHER_HINT.exec(cmd)) {
|
||||
return 'watcherService';
|
||||
return 'watcherService ';
|
||||
}
|
||||
|
||||
// find windows crash reporter
|
||||
if (WINDOWS_CRASH_REPORTER.exec(cmd)) {
|
||||
return 'electron-crash-reporter';
|
||||
}
|
||||
|
||||
// find windows pty process
|
||||
if (WINDOWS_PTY.exec(cmd)) {
|
||||
return 'winpty-process';
|
||||
}
|
||||
|
||||
//find windows console host process
|
||||
if (WINDOWS_CONSOLE_HOST.exec(cmd)) {
|
||||
return 'console-window-host (Windows internal process)';
|
||||
}
|
||||
|
||||
// find "--type=xxxx"
|
||||
@@ -102,6 +121,8 @@ export function listProcesses(rootPid: number): Promise<ProcessItem> {
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
|
||||
console.log(nls.localize('collecting', 'Collecting CPU and memory information. This might take a couple of seconds.'));
|
||||
|
||||
interface ProcessInfo {
|
||||
type: 'processInfo';
|
||||
name: string;
|
||||
@@ -157,7 +178,8 @@ export function listProcesses(rootPid: number): Promise<ProcessItem> {
|
||||
|
||||
cmd.on('exit', () => {
|
||||
if (stderr.length > 0) {
|
||||
reject(stderr);
|
||||
reject(new Error(stderr));
|
||||
return;
|
||||
}
|
||||
let processItems: Map<number, ProcessItem> = new Map();
|
||||
try {
|
||||
@@ -205,12 +227,13 @@ export function listProcesses(rootPid: number): Promise<ProcessItem> {
|
||||
reject(new Error(`Root process ${rootPid} not found`));
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(stdout);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
} else { // OS X & Linux
|
||||
|
||||
const CMD = 'ps -ax -o pid=,ppid=,pcpu=,pmem=,command=';
|
||||
const CMD = '/bin/ps -ax -o pid=,ppid=,pcpu=,pmem=,command=';
|
||||
const PID_CMD = /^\s*([0-9]+)\s+([0-9]+)\s+([0-9]+\.[0-9]+)\s+([0-9]+\.[0-9]+)\s+(.+)$/;
|
||||
|
||||
exec(CMD, { maxBuffer: 1000 * 1024 }, (err, stdout, stderr) => {
|
||||
|
||||
@@ -28,7 +28,7 @@ export interface IRequestOptions {
|
||||
password?: string;
|
||||
headers?: any;
|
||||
timeout?: number;
|
||||
data?: any;
|
||||
data?: string | Stream;
|
||||
agent?: Agent;
|
||||
followRedirects?: number;
|
||||
strictSSL?: boolean;
|
||||
@@ -63,6 +63,7 @@ export function request(options: IRequestOptions): TPromise<IRequestContext> {
|
||||
: getNodeRequest(options);
|
||||
|
||||
return rawRequestPromise.then(rawRequest => {
|
||||
|
||||
return new TPromise<IRequestContext>((c, e) => {
|
||||
const endpoint = parseUrl(options.url);
|
||||
|
||||
@@ -83,7 +84,6 @@ export function request(options: IRequestOptions): TPromise<IRequestContext> {
|
||||
|
||||
req = rawRequest(opts, (res: http.ClientResponse) => {
|
||||
const followRedirects = isNumber(options.followRedirects) ? options.followRedirects : 3;
|
||||
|
||||
if (res.statusCode >= 300 && res.statusCode < 400 && followRedirects > 0 && res.headers['location']) {
|
||||
request(assign({}, options, {
|
||||
url: res.headers['location'],
|
||||
@@ -107,7 +107,12 @@ export function request(options: IRequestOptions): TPromise<IRequestContext> {
|
||||
}
|
||||
|
||||
if (options.data) {
|
||||
req.write(options.data);
|
||||
if (typeof options.data === 'string') {
|
||||
req.write(options.data);
|
||||
} else {
|
||||
options.data.pipe(req);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
req.end();
|
||||
@@ -167,7 +172,13 @@ export function asJson<T>(context: IRequestContext): TPromise<T> {
|
||||
|
||||
const buffer: string[] = [];
|
||||
context.stream.on('data', (d: string) => buffer.push(d));
|
||||
context.stream.on('end', () => c(JSON.parse(buffer.join(''))));
|
||||
context.stream.on('end', () => {
|
||||
try {
|
||||
c(JSON.parse(buffer.join('')));
|
||||
} catch (err) {
|
||||
e(err);
|
||||
}
|
||||
});
|
||||
context.stream.on('error', e);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -79,12 +79,12 @@ export function collectWorkspaceStats(folder: string, filter: string[]): Workspa
|
||||
const MAX_FILES = 20000;
|
||||
|
||||
let walkSync = (dir: string, acceptFile: (fileName: string) => void, filter: string[], token) => {
|
||||
if (token.maxReached) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
let files = readdirSync(dir);
|
||||
for (const file of files) {
|
||||
if (token.maxReached) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (statSync(join(dir, file)).isDirectory()) {
|
||||
if (filter.indexOf(file) === -1) {
|
||||
@@ -92,10 +92,11 @@ export function collectWorkspaceStats(folder: string, filter: string[]): Workspa
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (token.count++ >= MAX_FILES) {
|
||||
if (token.count >= MAX_FILES) {
|
||||
token.maxReached = true;
|
||||
return;
|
||||
}
|
||||
token.count++;
|
||||
acceptFile(file);
|
||||
}
|
||||
} catch {
|
||||
|
||||
@@ -50,7 +50,6 @@ function generatePatchedEnv(env: any, stdInPipeName: string, stdOutPipeName: str
|
||||
newEnv['STDOUT_PIPE_NAME'] = stdOutPipeName;
|
||||
newEnv['STDERR_PIPE_NAME'] = stdErrPipeName;
|
||||
newEnv['ELECTRON_RUN_AS_NODE'] = '1';
|
||||
newEnv['ELECTRON_NO_ASAR'] = '1';
|
||||
|
||||
return newEnv;
|
||||
}
|
||||
@@ -138,4 +137,4 @@ export function fork(modulePath: string, args: string[], options: IForkOpts, cal
|
||||
|
||||
// On vscode exit still close server #7758
|
||||
process.once('exit', closeServer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ log('ELECTRON_RUN_AS_NODE: ' + process.env['ELECTRON_RUN_AS_NODE']);
|
||||
|
||||
var fsWriteSyncString = function (fd, str, position, encoding) {
|
||||
// fs.writeSync(fd, string[, position[, encoding]]);
|
||||
var buf = new Buffer(str, encoding || 'utf8');
|
||||
var buf = Buffer.from(str, encoding || 'utf8');
|
||||
return fsWriteSyncBuffer(fd, buf, 0, buf.length);
|
||||
};
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ export function readExactlyByFile(file: string, totalBytes: number): TPromise<Re
|
||||
});
|
||||
}
|
||||
|
||||
const buffer = new Buffer(totalBytes);
|
||||
const buffer = Buffer.allocUnsafe(totalBytes);
|
||||
let offset = 0;
|
||||
|
||||
function readChunk(): void {
|
||||
@@ -96,7 +96,7 @@ export function readToMatchingString(file: string, matchingString: string, chunk
|
||||
});
|
||||
}
|
||||
|
||||
let buffer = new Buffer(maximumBytesToRead);
|
||||
let buffer = Buffer.allocUnsafe(maximumBytesToRead);
|
||||
let offset = 0;
|
||||
|
||||
function readChunk(): void {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Readable } from 'stream';
|
||||
import { nfcall, ninvoke, SimpleThrottler } from 'vs/base/common/async';
|
||||
import { mkdirp, rimraf } from 'vs/base/node/pfs';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { open as openZip, Entry, ZipFile } from 'yauzl';
|
||||
import { open as _openZip, Entry, ZipFile } from 'yauzl';
|
||||
|
||||
export interface IExtractOptions {
|
||||
overwrite?: boolean;
|
||||
@@ -26,6 +26,29 @@ interface IOptions {
|
||||
sourcePathRegex: RegExp;
|
||||
}
|
||||
|
||||
export enum ExtractErrorType {
|
||||
Undefined,
|
||||
CorruptZip
|
||||
}
|
||||
|
||||
export class ExtractError extends Error {
|
||||
|
||||
readonly type: ExtractErrorType;
|
||||
readonly cause: Error;
|
||||
|
||||
constructor(type: ExtractErrorType, cause: Error) {
|
||||
let message = cause.message;
|
||||
|
||||
switch (type) {
|
||||
case ExtractErrorType.CorruptZip: message = `Corrupt ZIP: ${message}`; break;
|
||||
}
|
||||
|
||||
super(message);
|
||||
this.type = type;
|
||||
this.cause = cause;
|
||||
}
|
||||
}
|
||||
|
||||
function modeFromEntry(entry: Entry) {
|
||||
let attr = entry.externalFileAttributes >> 16 || 33188;
|
||||
|
||||
@@ -34,6 +57,18 @@ function modeFromEntry(entry: Entry) {
|
||||
.reduce((a, b) => a + b, attr & 61440 /* S_IFMT */);
|
||||
}
|
||||
|
||||
function toExtractError(err: Error): ExtractError {
|
||||
let type = ExtractErrorType.CorruptZip;
|
||||
|
||||
console.log('WHAT');
|
||||
|
||||
if (/end of central directory record signature not found/.test(err.message)) {
|
||||
type = ExtractErrorType.CorruptZip;
|
||||
}
|
||||
|
||||
return new ExtractError(type, err);
|
||||
}
|
||||
|
||||
function extractEntry(stream: Readable, fileName: string, mode: number, targetPath: string, options: IOptions): TPromise<void> {
|
||||
const dirName = path.dirname(fileName);
|
||||
const targetDirName = path.join(targetPath, dirName);
|
||||
@@ -74,13 +109,18 @@ function extractZip(zipfile: ZipFile, targetPath: string, options: IOptions): TP
|
||||
|
||||
last = throttler.queue(() => stream.then(stream => extractEntry(stream, fileName, mode, targetPath, options)));
|
||||
});
|
||||
});
|
||||
}).then(null, err => TPromise.wrapError(toExtractError(err)));
|
||||
}
|
||||
|
||||
function openZip(zipFile: string): TPromise<ZipFile> {
|
||||
return nfcall<ZipFile>(_openZip, zipFile)
|
||||
.then(null, err => TPromise.wrapError(toExtractError(err)));
|
||||
}
|
||||
|
||||
export function extract(zipPath: string, targetPath: string, options: IExtractOptions = {}): TPromise<void> {
|
||||
const sourcePathRegex = new RegExp(options.sourcePath ? `^${options.sourcePath}` : '');
|
||||
|
||||
let promise = nfcall<ZipFile>(openZip, zipPath);
|
||||
let promise = openZip(zipPath);
|
||||
|
||||
if (options.overwrite) {
|
||||
promise = promise.then(zipfile => rimraf(targetPath).then(() => zipfile));
|
||||
@@ -90,7 +130,7 @@ export function extract(zipPath: string, targetPath: string, options: IExtractOp
|
||||
}
|
||||
|
||||
function read(zipPath: string, filePath: string): TPromise<Readable> {
|
||||
return nfcall(openZip, zipPath).then((zipfile: ZipFile) => {
|
||||
return openZip(zipPath).then(zipfile => {
|
||||
return new TPromise<Readable>((c, e) => {
|
||||
zipfile.on('entry', (entry: Entry) => {
|
||||
if (entry.fileName === filePath) {
|
||||
|
||||
Reference in New Issue
Block a user