mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-15 18:46:36 -05:00
Merge from master
This commit is contained in:
@@ -3,8 +3,6 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as paths from 'path';
|
||||
import { nfcall } from 'vs/base/common/async';
|
||||
@@ -12,9 +10,10 @@ import { normalizeNFC } from 'vs/base/common/normalization';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import * as uuid from 'vs/base/common/uuid';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { encode, encodeStream } from 'vs/base/node/encoding';
|
||||
import * as flow from 'vs/base/node/flow';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IDisposable, toDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
const loop = flow.loop;
|
||||
|
||||
@@ -28,13 +27,13 @@ export function readdirSync(path: string): string[] {
|
||||
return fs.readdirSync(path);
|
||||
}
|
||||
|
||||
export function readdir(path: string, callback: (error: Error, files: string[]) => void): void {
|
||||
export function readdir(path: string, callback: (error: Error | null, files: string[]) => void): void {
|
||||
// Mac: uses NFD unicode form on disk, but we want NFC
|
||||
// See also https://github.com/nodejs/node/issues/2165
|
||||
if (platform.isMacintosh) {
|
||||
return fs.readdir(path, (error, children) => {
|
||||
if (error) {
|
||||
return callback(error, null);
|
||||
return callback(error, []);
|
||||
}
|
||||
|
||||
return callback(null, children.map(c => normalizeNFC(c)));
|
||||
@@ -49,7 +48,7 @@ export interface IStatAndLink {
|
||||
isSymbolicLink: boolean;
|
||||
}
|
||||
|
||||
export function statLink(path: string, callback: (error: Error, statAndIsLink: IStatAndLink) => void): void {
|
||||
export function statLink(path: string, callback: (error: Error | null, statAndIsLink: IStatAndLink | null) => void): void {
|
||||
fs.lstat(path, (error, lstat) => {
|
||||
if (error || lstat.isSymbolicLink()) {
|
||||
fs.stat(path, (error, stat) => {
|
||||
@@ -65,10 +64,8 @@ export function statLink(path: string, callback: (error: Error, statAndIsLink: I
|
||||
});
|
||||
}
|
||||
|
||||
export function copy(source: string, target: string, callback: (error: Error) => void, copiedSources?: { [path: string]: boolean }): void {
|
||||
if (!copiedSources) {
|
||||
copiedSources = Object.create(null);
|
||||
}
|
||||
export function copy(source: string, target: string, callback: (error: Error | null) => void, copiedSourcesIn?: { [path: string]: boolean }): void {
|
||||
const copiedSources = copiedSourcesIn ? copiedSourcesIn : Object.create(null);
|
||||
|
||||
fs.stat(source, (error, stat) => {
|
||||
if (error) {
|
||||
@@ -87,13 +84,13 @@ export function copy(source: string, target: string, callback: (error: Error) =>
|
||||
|
||||
const proceed = function () {
|
||||
readdir(source, (err, files) => {
|
||||
loop(files, (file: string, clb: (error: Error, result: string[]) => void) => {
|
||||
copy(paths.join(source, file), paths.join(target, file), (error: Error) => clb(error, void 0), copiedSources);
|
||||
loop(files, (file: string, clb: (error: Error | null, result: string[]) => void) => {
|
||||
copy(paths.join(source, file), paths.join(target, file), (error: Error) => clb(error, []), copiedSources);
|
||||
}, callback);
|
||||
});
|
||||
};
|
||||
|
||||
mkdirp(target, stat.mode & 511).done(proceed, proceed);
|
||||
mkdirp(target, stat.mode & 511).then(proceed, proceed);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -129,37 +126,42 @@ function doCopyFile(source: string, target: string, mode: number, callback: (err
|
||||
reader.pipe(writer);
|
||||
}
|
||||
|
||||
export function mkdirp(path: string, mode?: number): TPromise<boolean> {
|
||||
const mkdir = () => {
|
||||
export function mkdirp(path: string, mode?: number, token?: CancellationToken): Promise<boolean> {
|
||||
const mkdir = (): Promise<null> => {
|
||||
return nfcall(fs.mkdir, path, mode).then(null, (mkdirErr: NodeJS.ErrnoException) => {
|
||||
|
||||
// ENOENT: a parent folder does not exist yet
|
||||
if (mkdirErr.code === 'ENOENT') {
|
||||
return TPromise.wrapError(mkdirErr);
|
||||
return Promise.reject(mkdirErr);
|
||||
}
|
||||
|
||||
// Any other error: check if folder exists and
|
||||
// return normally in that case if its a folder
|
||||
return nfcall(fs.stat, path).then((stat: fs.Stats) => {
|
||||
if (!stat.isDirectory()) {
|
||||
return TPromise.wrapError(new Error(`'${path}' exists and is not a directory.`));
|
||||
return Promise.reject(new Error(`'${path}' exists and is not a directory.`));
|
||||
}
|
||||
|
||||
return null;
|
||||
}, statErr => {
|
||||
return TPromise.wrapError(mkdirErr); // bubble up original mkdir error
|
||||
return Promise.reject(mkdirErr); // bubble up original mkdir error
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// stop at root
|
||||
if (path === paths.dirname(path)) {
|
||||
return TPromise.as(true);
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
// recursively mkdir
|
||||
return mkdir().then(null, (err: NodeJS.ErrnoException) => {
|
||||
|
||||
// Respect cancellation
|
||||
if (token && token.isCancellationRequested) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
// ENOENT: a parent folder does not exist yet, continue
|
||||
// to create the parent folder and then try again.
|
||||
if (err.code === 'ENOENT') {
|
||||
@@ -167,7 +169,7 @@ export function mkdirp(path: string, mode?: number): TPromise<boolean> {
|
||||
}
|
||||
|
||||
// Any other error
|
||||
return TPromise.wrapError<boolean>(err);
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -175,7 +177,7 @@ export function mkdirp(path: string, mode?: number): TPromise<boolean> {
|
||||
// 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.
|
||||
// However, the consequences are bad as outlined in all the related bugs from https://github.com/joyent/node/issues/7164
|
||||
export function del(path: string, tmpFolder: string, callback: (error: Error) => void, done?: (error: Error) => void): void {
|
||||
export function del(path: string, tmpFolder: string, callback: (error: Error | null) => void, done?: (error: Error | null) => void): void {
|
||||
fs.exists(path, exists => {
|
||||
if (!exists) {
|
||||
return callback(null);
|
||||
@@ -193,7 +195,7 @@ export function del(path: string, tmpFolder: string, callback: (error: Error) =>
|
||||
}
|
||||
|
||||
const pathInTemp = paths.join(tmpFolder, uuid.generateUuid());
|
||||
fs.rename(path, pathInTemp, (error: Error) => {
|
||||
fs.rename(path, pathInTemp, (error: Error | null) => {
|
||||
if (error) {
|
||||
return rmRecursive(path, callback); // if rename fails, delete without tmp dir
|
||||
}
|
||||
@@ -216,7 +218,7 @@ export function del(path: string, tmpFolder: string, callback: (error: Error) =>
|
||||
});
|
||||
}
|
||||
|
||||
function rmRecursive(path: string, callback: (error: Error) => void): void {
|
||||
function rmRecursive(path: string, callback: (error: Error | null) => void): void {
|
||||
if (path === '\\' || path === '/') {
|
||||
return callback(new Error('Will not delete root!'));
|
||||
}
|
||||
@@ -248,7 +250,7 @@ function rmRecursive(path: string, callback: (error: Error) => void): void {
|
||||
} else if (children.length === 0) {
|
||||
fs.rmdir(path, callback);
|
||||
} else {
|
||||
let firstError: Error = null;
|
||||
let firstError: Error | null = null;
|
||||
let childrenLeft = children.length;
|
||||
children.forEach(child => {
|
||||
rmRecursive(paths.join(path, child), (err: Error) => {
|
||||
@@ -292,12 +294,12 @@ export function delSync(path: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
export function mv(source: string, target: string, callback: (error: Error) => void): void {
|
||||
export function mv(source: string, target: string, callback: (error: Error | null) => void): void {
|
||||
if (source === target) {
|
||||
return callback(null);
|
||||
}
|
||||
|
||||
function updateMtime(err: Error): void {
|
||||
function updateMtime(err: Error | null): void {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
@@ -365,7 +367,7 @@ export interface IWriteFileOptions {
|
||||
}
|
||||
|
||||
let canFlush = true;
|
||||
export function writeFileAndFlush(path: string, data: string | NodeBuffer | NodeJS.ReadableStream, options: IWriteFileOptions, callback: (error?: Error) => void): void {
|
||||
export function writeFileAndFlush(path: string, data: string | Buffer | NodeJS.ReadableStream, options: IWriteFileOptions, callback: (error?: Error) => void): void {
|
||||
options = ensureOptions(options);
|
||||
|
||||
if (typeof data === 'string' || Buffer.isBuffer(data)) {
|
||||
@@ -466,7 +468,7 @@ function doWriteFileStreamAndFlush(path: string, reader: NodeJS.ReadableStream,
|
||||
// not in some cache.
|
||||
//
|
||||
// See https://github.com/nodejs/node/blob/v5.10.0/lib/fs.js#L1194
|
||||
function doWriteFileAndFlush(path: string, data: string | NodeBuffer, options: IWriteFileOptions, callback: (error?: Error) => void): void {
|
||||
function doWriteFileAndFlush(path: string, data: string | Buffer, options: IWriteFileOptions, callback: (error?: Error) => void): void {
|
||||
if (options.encoding) {
|
||||
data = encode(data, options.encoding.charset, { addBOM: options.encoding.addBOM });
|
||||
}
|
||||
@@ -476,7 +478,7 @@ function doWriteFileAndFlush(path: string, data: string | NodeBuffer, options: I
|
||||
}
|
||||
|
||||
// Open the file with same flags and mode as fs.writeFile()
|
||||
fs.open(path, options.flag, options.mode, (openError, fd) => {
|
||||
fs.open(path, typeof options.flag === 'string' ? options.flag : 'r', options.mode, (openError, fd) => {
|
||||
if (openError) {
|
||||
return callback(openError);
|
||||
}
|
||||
@@ -503,7 +505,7 @@ function doWriteFileAndFlush(path: string, data: string | NodeBuffer, options: I
|
||||
});
|
||||
}
|
||||
|
||||
export function writeFileAndFlushSync(path: string, data: string | NodeBuffer, options?: IWriteFileOptions): void {
|
||||
export function writeFileAndFlushSync(path: string, data: string | Buffer, options?: IWriteFileOptions): void {
|
||||
options = ensureOptions(options);
|
||||
|
||||
if (options.encoding) {
|
||||
@@ -515,7 +517,7 @@ export function writeFileAndFlushSync(path: string, data: string | NodeBuffer, o
|
||||
}
|
||||
|
||||
// Open the file with same flags and mode as fs.writeFile()
|
||||
const fd = fs.openSync(path, options.flag, options.mode);
|
||||
const fd = fs.openSync(path, typeof options.flag === 'string' ? options.flag : 'r', options.mode);
|
||||
|
||||
try {
|
||||
|
||||
@@ -561,7 +563,7 @@ function ensureOptions(options?: IWriteFileOptions): IWriteFileOptions {
|
||||
* In case of errors, null is returned. But you cannot use this function to verify that a path exists.
|
||||
* realcaseSync does not handle '..' or '.' path segments and it does not take the locale into account.
|
||||
*/
|
||||
export function realcaseSync(path: string): string {
|
||||
export function realcaseSync(path: string): string | null {
|
||||
const dir = paths.dirname(path);
|
||||
if (path === dir) { // end recursion
|
||||
return path;
|
||||
@@ -611,7 +613,7 @@ export function realpathSync(path: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
export function realpath(path: string, callback: (error: Error, realpath: string) => void): void {
|
||||
export function realpath(path: string, callback: (error: Error | null, realpath: string) => void): void {
|
||||
return fs.realpath(path, (error, realpath) => {
|
||||
if (!error) {
|
||||
return callback(null, realpath);
|
||||
@@ -634,12 +636,12 @@ function normalizePath(path: string): string {
|
||||
return strings.rtrim(paths.normalize(path), paths.sep);
|
||||
}
|
||||
|
||||
export function watch(path: string, onChange: (type: string, path?: string) => void, onError: (error: string) => void): fs.FSWatcher {
|
||||
export function watch(path: string, onChange: (type: string, path?: string) => void, onError: (error: string) => void): IDisposable {
|
||||
try {
|
||||
const watcher = fs.watch(path);
|
||||
|
||||
watcher.on('change', (type, raw) => {
|
||||
let file: string = null;
|
||||
let file: string | undefined;
|
||||
if (raw) { // https://github.com/Microsoft/vscode/issues/38191
|
||||
file = raw.toString();
|
||||
if (platform.isMacintosh) {
|
||||
@@ -654,7 +656,10 @@ export function watch(path: string, onChange: (type: string, path?: string) => v
|
||||
|
||||
watcher.on('error', (code: number, signal: string) => onError(`Failed to watch ${path} for changes (${code}, ${signal})`));
|
||||
|
||||
return watcher;
|
||||
return toDisposable(() => {
|
||||
watcher.removeAllListeners();
|
||||
watcher.close();
|
||||
});
|
||||
} catch (error) {
|
||||
fs.exists(path, exists => {
|
||||
if (exists) {
|
||||
@@ -663,5 +668,41 @@ export function watch(path: string, onChange: (type: string, path?: string) => v
|
||||
});
|
||||
}
|
||||
|
||||
return void 0;
|
||||
return Disposable.None;
|
||||
}
|
||||
|
||||
export function sanitizeFilePath(candidate: string, cwd: string): string {
|
||||
|
||||
// Special case: allow to open a drive letter without trailing backslash
|
||||
if (platform.isWindows && strings.endsWith(candidate, ':')) {
|
||||
candidate += paths.sep;
|
||||
}
|
||||
|
||||
// Ensure absolute
|
||||
if (!paths.isAbsolute(candidate)) {
|
||||
candidate = paths.join(cwd, candidate);
|
||||
}
|
||||
|
||||
// Ensure normalized
|
||||
candidate = paths.normalize(candidate);
|
||||
|
||||
// Ensure no trailing slash/backslash
|
||||
if (platform.isWindows) {
|
||||
candidate = strings.rtrim(candidate, paths.sep);
|
||||
|
||||
// Special case: allow to open drive root ('C:\')
|
||||
if (strings.endsWith(candidate, ':')) {
|
||||
candidate += paths.sep;
|
||||
}
|
||||
|
||||
} else {
|
||||
candidate = strings.rtrim(candidate, paths.sep);
|
||||
|
||||
// Special case: allow to open root ('/')
|
||||
if (!candidate) {
|
||||
candidate = paths.sep;
|
||||
}
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
Reference in New Issue
Block a user