Merge from vscode a5cf1da01d5db3d2557132be8d30f89c38019f6c (#8525)

* Merge from vscode a5cf1da01d5db3d2557132be8d30f89c38019f6c

* remove files we don't want

* fix hygiene

* update distro

* update distro

* fix hygiene

* fix strict nulls

* distro

* distro

* fix tests

* fix tests

* add another edit

* fix viewlet icon

* fix azure dialog

* fix some padding

* fix more padding issues
This commit is contained in:
Anthony Dresser
2019-12-04 19:28:22 -08:00
committed by GitHub
parent a8818ab0df
commit f5ce7fb2a5
1507 changed files with 42813 additions and 27370 deletions

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Disposable, IDisposable, toDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent, ETAG_DISABLED } from 'vs/platform/files/common/files';
import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent, ETAG_DISABLED, hasFileReadStreamCapability, IFileSystemProviderWithFileReadStreamCapability, ensureFileSystemProviderError } from 'vs/platform/files/common/files';
import { URI } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event';
import { isAbsolutePath, dirname, basename, joinPath, isEqual, isEqualOrParent } from 'vs/base/common/resources';
@@ -13,10 +13,13 @@ import { TernarySearchTree } from 'vs/base/common/map';
import { isNonEmptyArray, coalesce } from 'vs/base/common/arrays';
import { getBaseLabel } from 'vs/base/common/labels';
import { ILogService } from 'vs/platform/log/common/log';
import { VSBuffer, VSBufferReadable, readableToBuffer, bufferToReadable, streamToBuffer, bufferToStream, VSBufferReadableStream, writeableBufferStream, VSBufferWriteableStream, isVSBufferReadableStream } from 'vs/base/common/buffer';
import { VSBuffer, VSBufferReadable, readableToBuffer, bufferToReadable, streamToBuffer, bufferToStream, VSBufferReadableStream } from 'vs/base/common/buffer';
import { isReadableStream, transform, ReadableStreamEvents, consumeReadableWithLimit, consumeStreamWithLimit } from 'vs/base/common/stream';
import { Queue } from 'vs/base/common/async';
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
import { Schemas } from 'vs/base/common/network';
import { assign } from 'vs/base/common/objects';
import { createReadStream } from 'vs/platform/files/common/io';
export class FileService extends Disposable implements IFileService {
@@ -118,14 +121,24 @@ export class FileService extends Disposable implements IFileService {
return provider;
}
private async withReadWriteProvider(resource: URI): Promise<IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability> {
private async withReadProvider(resource: URI): Promise<IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability | IFileSystemProviderWithFileReadStreamCapability> {
const provider = await this.withProvider(resource);
if (hasOpenReadWriteCloseCapability(provider) || hasReadWriteCapability(provider) || hasFileReadStreamCapability(provider)) {
return provider;
}
throw new Error('Provider neither has FileReadWrite, FileReadStream nor FileOpenReadWriteClose capability which is needed for the read operation.');
}
private async withWriteProvider(resource: URI): Promise<IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability> {
const provider = await this.withProvider(resource);
if (hasOpenReadWriteCloseCapability(provider) || hasReadWriteCapability(provider)) {
return provider;
}
throw new Error('Provider neither has FileReadWrite nor FileOpenReadWriteClose capability which is needed for the operation.');
throw new Error('Provider neither has FileReadWrite nor FileOpenReadWriteClose capability which is needed for the write operation.');
}
//#endregion
@@ -154,7 +167,7 @@ export class FileService extends Disposable implements IFileService {
}
// Bubble up any other error as is
throw this.ensureError(error);
throw ensureFileSystemProviderError(error);
}
}
@@ -196,16 +209,19 @@ export class FileService extends Disposable implements IFileService {
});
}
private async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat | { type: FileType } & Partial<IStat>, siblings: number | undefined, resolveMetadata: boolean, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise<IFileStat>;
private async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat, siblings: number | undefined, resolveMetadata: true, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise<IFileStatWithMetadata>;
private async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat | { type: FileType } & Partial<IStat>, siblings: number | undefined, resolveMetadata: boolean, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise<IFileStat> {
// convert to file stat
const fileStat: IFileStat = {
resource,
name: getBaseLabel(resource),
isFile: (stat.type & FileType.File) !== 0,
isDirectory: (stat.type & FileType.Directory) !== 0,
isSymbolicLink: (stat.type & FileType.SymbolicLink) !== 0,
isReadonly: !!(provider.capabilities & FileSystemProviderCapabilities.Readonly),
mtime: stat.mtime,
ctime: stat.ctime,
size: stat.size,
etag: etag({ mtime: stat.mtime, size: stat.size })
};
@@ -288,7 +304,7 @@ export class FileService extends Disposable implements IFileService {
}
async writeFile(resource: URI, bufferOrReadableOrStream: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: IWriteFileOptions): Promise<IFileStatWithMetadata> {
const provider = this.throwIfFileSystemIsReadonly(await this.withReadWriteProvider(resource));
const provider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(resource));
try {
@@ -300,17 +316,29 @@ export class FileService extends Disposable implements IFileService {
await this.mkdirp(provider, dirname(resource));
}
// write file: buffered
if (hasOpenReadWriteCloseCapability(provider)) {
await this.doWriteBuffered(provider, resource, bufferOrReadableOrStream instanceof VSBuffer ? bufferToReadable(bufferOrReadableOrStream) : bufferOrReadableOrStream);
// optimization: if the provider has unbuffered write capability and the data
// to write is a Readable, we consume up to 3 chunks and try to write the data
// unbuffered to reduce the overhead. If the Readable has more data to provide
// we continue to write buffered.
if (hasReadWriteCapability(provider) && !(bufferOrReadableOrStream instanceof VSBuffer)) {
if (isReadableStream(bufferOrReadableOrStream)) {
bufferOrReadableOrStream = await consumeStreamWithLimit(bufferOrReadableOrStream, data => VSBuffer.concat(data), 3);
} else {
bufferOrReadableOrStream = consumeReadableWithLimit(bufferOrReadableOrStream, data => VSBuffer.concat(data), 3);
}
}
// write file: unbuffered
else {
// write file: unbuffered (only if data to write is a buffer, or the provider has no buffered write capability)
if (!hasOpenReadWriteCloseCapability(provider) || (hasReadWriteCapability(provider) && bufferOrReadableOrStream instanceof VSBuffer)) {
await this.doWriteUnbuffered(provider, resource, bufferOrReadableOrStream);
}
// write file: buffered
else {
await this.doWriteBuffered(provider, resource, bufferOrReadableOrStream instanceof VSBuffer ? bufferToReadable(bufferOrReadableOrStream) : bufferOrReadableOrStream);
}
} catch (error) {
throw new FileOperationError(localize('err.write', "Unable to write file ({0})", this.ensureError(error).toString()), toFileOperationResult(error), options);
throw new FileOperationError(localize('err.write', "Unable to write file ({0})", ensureFileSystemProviderError(error).toString()), toFileOperationResult(error), options);
}
return this.resolve(resource, { resolveMetadata: true });
@@ -333,7 +361,7 @@ export class FileService extends Disposable implements IFileService {
// mtime and etag, we bail out to prevent dirty writing.
//
// First, we check for a mtime that is in the future before we do more checks. The assumption is
// that only the mtime is an indicator for a file that has changd on disk.
// that only the mtime is an indicator for a file that has changed on disk.
//
// Second, if the mtime has advanced, we compare the size of the file on disk with our previous
// one using the etag() function. Relying only on the mtime check has prooven to produce false
@@ -353,7 +381,16 @@ export class FileService extends Disposable implements IFileService {
}
async readFile(resource: URI, options?: IReadFileOptions): Promise<IFileContent> {
const stream = await this.readFileStream(resource, options);
const provider = await this.withReadProvider(resource);
const stream = await this.doReadAsFileStream(provider, resource, assign({
// optimization: since we know that the caller does not
// care about buffering, we indicate this to the reader.
// this reduces all the overhead the buffered reading
// has (open, read, close) if the provider supports
// unbuffered reading.
preferUnbuffered: true
}, options || Object.create(null)));
return {
...stream,
@@ -362,7 +399,12 @@ export class FileService extends Disposable implements IFileService {
}
async readFileStream(resource: URI, options?: IReadFileOptions): Promise<IFileStreamContent> {
const provider = await this.withReadWriteProvider(resource);
const provider = await this.withReadProvider(resource);
return this.doReadAsFileStream(provider, resource, options);
}
private async doReadAsFileStream(provider: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability | IFileSystemProviderWithFileReadStreamCapability, resource: URI, options?: IReadFileOptions & { preferUnbuffered?: boolean }): Promise<IFileStreamContent> {
// install a cancellation token that gets cancelled
// when any error occurs. this allows us to resolve
@@ -389,14 +431,19 @@ export class FileService extends Disposable implements IFileService {
let fileStreamPromise: Promise<VSBufferReadableStream>;
// read buffered
if (hasOpenReadWriteCloseCapability(provider)) {
fileStreamPromise = Promise.resolve(this.readFileBuffered(provider, resource, cancellableSource.token, options));
// read unbuffered (only if either preferred, or the provider has no buffered read capability)
if (!(hasOpenReadWriteCloseCapability(provider) || hasFileReadStreamCapability(provider)) || (hasReadWriteCapability(provider) && options?.preferUnbuffered)) {
fileStreamPromise = this.readFileUnbuffered(provider, resource, options);
}
// read unbuffered
// read streamed (always prefer over primitive buffered read)
else if (hasFileReadStreamCapability(provider)) {
fileStreamPromise = Promise.resolve(this.readFileStreamed(provider, resource, cancellableSource.token, options));
}
// read buffered
else {
fileStreamPromise = this.readFileUnbuffered(provider, resource, options);
fileStreamPromise = Promise.resolve(this.readFileBuffered(provider, resource, cancellableSource.token, options));
}
const [fileStat, fileStream] = await Promise.all([statPromise, fileStreamPromise]);
@@ -406,74 +453,30 @@ export class FileService extends Disposable implements IFileService {
value: fileStream
};
} catch (error) {
throw new FileOperationError(localize('err.read', "Unable to read file ({0})", this.ensureError(error).toString()), toFileOperationResult(error), options);
throw new FileOperationError(localize('err.read', "Unable to read file ({0})", ensureFileSystemProviderError(error).toString()), toFileOperationResult(error), options);
}
}
private readFileBuffered(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, resource: URI, token: CancellationToken, options?: IReadFileOptions): VSBufferReadableStream {
const stream = writeableBufferStream();
private readFileStreamed(provider: IFileSystemProviderWithFileReadStreamCapability, resource: URI, token: CancellationToken, options: IReadFileOptions = Object.create(null)): VSBufferReadableStream {
const fileStream = provider.readFileStream(resource, options, token);
// do not await reading but simply return
// the stream directly since it operates
// via events. finally end the stream and
// send through the possible error
let error: Error | undefined = undefined;
this.doReadFileBuffered(provider, resource, stream, token, options).then(undefined, err => error = err).finally(() => stream.end(error));
return stream;
return this.transformFileReadStream(fileStream, options);
}
private async doReadFileBuffered(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, resource: URI, stream: VSBufferWriteableStream, token: CancellationToken, options?: IReadFileOptions): Promise<void> {
private readFileBuffered(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, resource: URI, token: CancellationToken, options: IReadFileOptions = Object.create(null)): VSBufferReadableStream {
const fileStream = createReadStream(provider, resource, {
...options,
bufferSize: this.BUFFER_SIZE
}, token);
// open handle through provider
const handle = await provider.open(resource, { create: false });
return this.transformFileReadStream(fileStream, options);
}
try {
let totalBytesRead = 0;
let bytesRead = 0;
let allowedRemainingBytes = (options && typeof options.length === 'number') ? options.length : undefined;
let buffer = VSBuffer.alloc(Math.min(this.BUFFER_SIZE, typeof allowedRemainingBytes === 'number' ? allowedRemainingBytes : this.BUFFER_SIZE));
let posInFile = options && typeof options.position === 'number' ? options.position : 0;
let posInBuffer = 0;
do {
// read from source (handle) at current position (pos) into buffer (buffer) at
// buffer position (posInBuffer) up to the size of the buffer (buffer.byteLength).
bytesRead = await provider.read(handle, posInFile, buffer.buffer, posInBuffer, buffer.byteLength - posInBuffer);
posInFile += bytesRead;
posInBuffer += bytesRead;
totalBytesRead += bytesRead;
if (typeof allowedRemainingBytes === 'number') {
allowedRemainingBytes -= bytesRead;
}
// when buffer full, create a new one and emit it through stream
if (posInBuffer === buffer.byteLength) {
stream.write(buffer);
buffer = VSBuffer.alloc(Math.min(this.BUFFER_SIZE, typeof allowedRemainingBytes === 'number' ? allowedRemainingBytes : this.BUFFER_SIZE));
posInBuffer = 0;
}
} while (bytesRead > 0 && (typeof allowedRemainingBytes !== 'number' || allowedRemainingBytes > 0) && this.throwIfCancelled(token) && this.throwIfTooLarge(totalBytesRead, options));
// wrap up with last buffer (also respect maxBytes if provided)
if (posInBuffer > 0) {
let lastChunkLength = posInBuffer;
if (typeof allowedRemainingBytes === 'number') {
lastChunkLength = Math.min(posInBuffer, allowedRemainingBytes);
}
stream.write(buffer.slice(0, lastChunkLength));
}
} catch (error) {
throw this.ensureError(error);
} finally {
await provider.close(handle);
}
private transformFileReadStream(stream: ReadableStreamEvents<Uint8Array | VSBuffer>, options: IReadFileOptions): VSBufferReadableStream {
return transform(stream, {
data: data => data instanceof VSBuffer ? data : VSBuffer.wrap(data),
error: error => new FileOperationError(localize('err.read', "Unable to read file ({0})", ensureFileSystemProviderError(error).toString()), toFileOperationResult(error), options)
}, data => VSBuffer.concat(data));
}
private async readFileUnbuffered(provider: IFileSystemProviderWithFileReadWriteCapability, resource: URI, options?: IReadFileOptions): Promise<VSBufferReadableStream> {
@@ -489,43 +492,56 @@ export class FileService extends Disposable implements IFileService {
buffer = buffer.slice(0, options.length);
}
// Throw if file is too large to load
this.validateReadFileLimits(buffer.byteLength, options);
return bufferToStream(VSBuffer.wrap(buffer));
}
private async validateReadFile(resource: URI, options?: IReadFileOptions): Promise<IFileStatWithMetadata> {
const stat = await this.resolve(resource, { resolveMetadata: true });
// Return early if resource is a directory
// Throw if resource is a directory
if (stat.isDirectory) {
throw new FileOperationError(localize('fileIsDirectoryError', "Expected file {0} is actually a directory", this.resourceForError(resource)), FileOperationResult.FILE_IS_DIRECTORY, options);
}
// Return early if file not modified since (unless disabled)
// Throw if file not modified since (unless disabled)
if (options && typeof options.etag === 'string' && options.etag !== ETAG_DISABLED && options.etag === stat.etag) {
throw new FileOperationError(localize('fileNotModifiedError', "File not modified since"), FileOperationResult.FILE_NOT_MODIFIED_SINCE, options);
}
// Return early if file is too large to load
if (options?.limits) {
if (typeof options.limits.memory === 'number' && stat.size > options.limits.memory) {
throw new FileOperationError(localize('fileTooLargeForHeapError', "To open a file of this size, you need to restart and allow it to use more memory"), FileOperationResult.FILE_EXCEED_MEMORY_LIMIT);
}
if (typeof options.limits.size === 'number' && stat.size > options.limits.size) {
throw new FileOperationError(localize('fileTooLargeError', "File is too large to open"), FileOperationResult.FILE_TOO_LARGE);
}
}
// Throw if file is too large to load
this.validateReadFileLimits(stat.size, options);
return stat;
}
private validateReadFileLimits(size: number, options?: IReadFileOptions): void {
if (options?.limits) {
let tooLargeErrorResult: FileOperationResult | undefined = undefined;
if (typeof options.limits.memory === 'number' && size > options.limits.memory) {
tooLargeErrorResult = FileOperationResult.FILE_EXCEEDS_MEMORY_LIMIT;
}
if (typeof options.limits.size === 'number' && size > options.limits.size) {
tooLargeErrorResult = FileOperationResult.FILE_TOO_LARGE;
}
if (typeof tooLargeErrorResult === 'number') {
throw new FileOperationError(localize('fileTooLargeError', "File is too large to open"), tooLargeErrorResult);
}
}
}
//#endregion
//#region Move/Copy/Delete/Create Folder
async move(source: URI, target: URI, overwrite?: boolean): Promise<IFileStatWithMetadata> {
const sourceProvider = this.throwIfFileSystemIsReadonly(await this.withReadWriteProvider(source));
const targetProvider = this.throwIfFileSystemIsReadonly(await this.withReadWriteProvider(target));
const sourceProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(source));
const targetProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(target));
// move
const mode = await this.doMoveCopy(sourceProvider, source, targetProvider, target, 'move', !!overwrite);
@@ -538,8 +554,8 @@ export class FileService extends Disposable implements IFileService {
}
async copy(source: URI, target: URI, overwrite?: boolean): Promise<IFileStatWithMetadata> {
const sourceProvider = await this.withReadWriteProvider(source);
const targetProvider = this.throwIfFileSystemIsReadonly(await this.withReadWriteProvider(target));
const sourceProvider = await this.withReadProvider(source);
const targetProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(target));
// copy
const mode = await this.doMoveCopy(sourceProvider, source, targetProvider, target, 'copy', !!overwrite);
@@ -551,7 +567,7 @@ export class FileService extends Disposable implements IFileService {
return fileStat;
}
private async doMoveCopy(sourceProvider: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability, source: URI, targetProvider: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability, target: URI, mode: 'move' | 'copy', overwrite: boolean): Promise<'move' | 'copy'> {
private async doMoveCopy(sourceProvider: IFileSystemProvider, source: URI, targetProvider: IFileSystemProvider, target: URI, mode: 'move' | 'copy', overwrite: boolean): Promise<'move' | 'copy'> {
if (source.toString() === target.toString()) {
return mode; // simulate node.js behaviour here and do a no-op if paths match
}
@@ -666,7 +682,7 @@ export class FileService extends Disposable implements IFileService {
}
if (!isSameResourceWithDifferentPathCase && isEqualOrParent(target, source, !isPathCaseSensitive)) {
throw new Error(localize('unableToMoveCopyError2', "Unable to move/copy when source is parent of target"));
throw new Error(localize('unableToMoveCopyError2', "Unable to move/copy when source is parent of target."));
}
}
@@ -676,7 +692,7 @@ export class FileService extends Disposable implements IFileService {
// Bail out if target exists and we are not about to overwrite
if (!overwrite) {
throw new FileOperationError(localize('unableToMoveCopyError3', "Unable to move/copy. File already exists at destination."), FileOperationResult.FILE_MOVE_CONFLICT);
throw new FileOperationError(localize('unableToMoveCopyError3', "Unable to move/copy since a file already exists at destination."), FileOperationResult.FILE_MOVE_CONFLICT);
}
// Special case: if the target is a parent of the source, we cannot delete
@@ -684,7 +700,7 @@ export class FileService extends Disposable implements IFileService {
if (sourceProvider === targetProvider) {
const isPathCaseSensitive = !!(sourceProvider.capabilities & FileSystemProviderCapabilities.PathCaseSensitive);
if (isEqualOrParent(source, target, !isPathCaseSensitive)) {
throw new Error(localize('unableToMoveCopyError4', "Unable to move/copy. File would replace folder it is contained in."));
throw new Error(localize('unableToMoveCopyError4', "Unable to move/copy since a file would replace the folder it is contained in."));
}
}
}
@@ -871,13 +887,13 @@ export class FileService extends Disposable implements IFileService {
// write into handle until all bytes from buffer have been written
try {
if (isVSBufferReadableStream(readableOrStream)) {
if (isReadableStream(readableOrStream)) {
await this.doWriteStreamBufferedQueued(provider, handle, readableOrStream);
} else {
await this.doWriteReadableBufferedQueued(provider, handle, readableOrStream);
}
} catch (error) {
throw this.ensureError(error);
throw ensureFileSystemProviderError(error);
} finally {
// close handle always
@@ -919,7 +935,7 @@ export class FileService extends Disposable implements IFileService {
let posInFile = 0;
let chunk: VSBuffer | null;
while (chunk = readable.read()) {
while ((chunk = readable.read()) !== null) {
await this.doWriteBuffer(provider, handle, chunk, chunk.byteLength, posInFile, 0);
posInFile += chunk.byteLength;
@@ -942,7 +958,7 @@ export class FileService extends Disposable implements IFileService {
let buffer: VSBuffer;
if (bufferOrReadableOrStream instanceof VSBuffer) {
buffer = bufferOrReadableOrStream;
} else if (isVSBufferReadableStream(bufferOrReadableOrStream)) {
} else if (isReadableStream(bufferOrReadableOrStream)) {
buffer = await streamToBuffer(bufferOrReadableOrStream);
} else {
buffer = readableToBuffer(bufferOrReadableOrStream);
@@ -988,7 +1004,7 @@ export class FileService extends Disposable implements IFileService {
}
} while (bytesRead > 0);
} catch (error) {
throw this.ensureError(error);
throw ensureFileSystemProviderError(error);
} finally {
await Promise.all([
typeof sourceHandle === 'number' ? sourceProvider.close(sourceHandle) : Promise.resolve(),
@@ -1019,7 +1035,7 @@ export class FileService extends Disposable implements IFileService {
const buffer = await sourceProvider.readFile(source);
await this.doWriteBuffer(targetProvider, targetHandle, VSBuffer.wrap(buffer), buffer.byteLength, 0, 0);
} catch (error) {
throw this.ensureError(error);
throw ensureFileSystemProviderError(error);
} finally {
await targetProvider.close(targetHandle);
}
@@ -1042,38 +1058,6 @@ export class FileService extends Disposable implements IFileService {
return provider;
}
private throwIfCancelled(token: CancellationToken): boolean {
if (token.isCancellationRequested) {
throw new Error('cancelled');
}
return true;
}
private ensureError(error?: Error): Error {
if (!error) {
return new Error(localize('unknownError', "Unknown Error")); // https://github.com/Microsoft/vscode/issues/72798
}
return error;
}
private throwIfTooLarge(totalBytesRead: number, options?: IReadFileOptions): boolean {
// Return early if file is too large to load
if (options?.limits) {
if (typeof options.limits.memory === 'number' && totalBytesRead > options.limits.memory) {
throw new FileOperationError(localize('fileTooLargeForHeapError', "To open a file of this size, you need to restart and allow it to use more memory"), FileOperationResult.FILE_EXCEED_MEMORY_LIMIT);
}
if (typeof options.limits.size === 'number' && totalBytesRead > options.limits.size) {
throw new FileOperationError(localize('fileTooLargeError', "File is too large to open"), FileOperationResult.FILE_TOO_LARGE);
}
}
return true;
}
private resourceForError(resource: URI): string {
if (resource.scheme === Schemas.file) {
return resource.fsPath;