Skip to content

Commit

Permalink
add ExtHostFileSystemInfo which knows what schemes are reserved and w…
Browse files Browse the repository at this point in the history
…hich are used, #91697
  • Loading branch information
jrieken committed Sep 10, 2020
1 parent 9a2a941 commit e38b9d0
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 31 deletions.
9 changes: 8 additions & 1 deletion src/vs/workbench/api/browser/mainThreadFileSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { Emitter, Event } from 'vs/base/common/event';
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat, FileOperationError, FileOperationResult, FileSystemProviderErrorCode, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileFolderCopyCapability } from 'vs/platform/files/common/files';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
Expand All @@ -16,15 +16,22 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {

private readonly _proxy: ExtHostFileSystemShape;
private readonly _fileProvider = new Map<number, RemoteFileSystemProvider>();
private readonly _disposables = new DisposableStore();

constructor(
extHostContext: IExtHostContext,
@IFileService private readonly _fileService: IFileService,
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystem);

const infoProxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystemInfo);

this._disposables.add(_fileService.onDidChangeFileSystemProviderRegistrations(e => infoProxy.$acceptProviderInfos(e.scheme, e.provider?.capabilities ?? null)));
this._disposables.add(_fileService.onDidChangeFileSystemProviderCapabilities(e => infoProxy.$acceptProviderInfos(e.scheme, e.provider.capabilities)));
}

dispose(): void {
this._disposables.dispose();
dispose(this._fileProvider.values());
this._fileProvider.clear();
}
Expand Down
5 changes: 4 additions & 1 deletion src/vs/workbench/api/common/extHost.api.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ import { ExtHostWebviewViews } from 'vs/workbench/api/common/extHostWebviewView'
import { ExtHostCustomEditors } from 'vs/workbench/api/common/extHostCustomEditors';
import { ExtHostWebviewPanels } from 'vs/workbench/api/common/extHostWebviewPanels';
import { ExtHostBulkEdits } from 'vs/workbench/api/common/extHostBulkEdits';
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';

export interface IExtensionApiFactory {
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
Expand All @@ -92,6 +93,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I

// services
const initData = accessor.get(IExtHostInitDataService);
const extHostFileSystemInfo = accessor.get(IExtHostFileSystemInfo);
const extHostConsumerFileSystem = accessor.get(IExtHostConsumerFileSystem);
const extensionService = accessor.get(IExtHostExtensionService);
const extHostWorkspace = accessor.get(IExtHostWorkspace);
Expand All @@ -106,6 +108,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostWindow = accessor.get(IExtHostWindow);

// register addressable instances
rpcProtocol.set(ExtHostContext.ExtHostFileSystemInfo, extHostFileSystemInfo);
rpcProtocol.set(ExtHostContext.ExtHostLogService, <ExtHostLogServiceShape><any>extHostLogService);
rpcProtocol.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace);
rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
Expand Down Expand Up @@ -135,7 +138,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData.environment));
const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol, extHostLogService));
const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, uriTransformer, extHostDocuments, extHostCommands, extHostDiagnostics, extHostLogService, extHostApiDeprecation));
const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures, extHostConsumerFileSystem));
const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures, extHostFileSystemInfo));
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostLogService, extHostDocumentsAndEditors));
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
Expand Down
4 changes: 3 additions & 1 deletion src/vs/workbench/api/common/extHost.common.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHost
import { IExtHostTunnelService, ExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
import { IExtHostApiDeprecationService, ExtHostApiDeprecationService, } from 'vs/workbench/api/common/extHostApiDeprecationService';
import { IExtHostWindow, ExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
import { ExtHostConsumerFileSystem, IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
import { IExtHostConsumerFileSystem, ExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
import { IExtHostFileSystemInfo, ExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';

registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths);
registerSingleton(IExtHostApiDeprecationService, ExtHostApiDeprecationService);
Expand All @@ -29,6 +30,7 @@ registerSingleton(IExtHostConsumerFileSystem, ExtHostConsumerFileSystem);
registerSingleton(IExtHostDebugService, WorkerExtHostDebugService);
registerSingleton(IExtHostDecorations, ExtHostDecorations);
registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors);
registerSingleton(IExtHostFileSystemInfo, ExtHostFileSystemInfo);
registerSingleton(IExtHostOutputService, ExtHostOutputService);
registerSingleton(IExtHostSearch, ExtHostSearch);
registerSingleton(IExtHostStorage, ExtHostStorage);
Expand Down
5 changes: 5 additions & 0 deletions src/vs/workbench/api/common/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,10 @@ export interface ExtHostWorkspaceShape {
$handleTextSearchResult(result: search.IRawFileMatch2, requestId: number): void;
}

export interface ExtHostFileSystemInfoShape {
$acceptProviderInfos(scheme: string, capabilities: number | null): void;
}

export interface ExtHostFileSystemShape {
$stat(handle: number, resource: UriComponents): Promise<files.IStat>;
$readdir(handle: number, resource: UriComponents): Promise<[string, files.FileType][]>;
Expand Down Expand Up @@ -1787,6 +1791,7 @@ export const ExtHostContext = {
ExtHostEditors: createExtId<ExtHostEditorsShape>('ExtHostEditors'),
ExtHostTreeViews: createExtId<ExtHostTreeViewsShape>('ExtHostTreeViews'),
ExtHostFileSystem: createExtId<ExtHostFileSystemShape>('ExtHostFileSystem'),
ExtHostFileSystemInfo: createExtId<ExtHostFileSystemInfoShape>('ExtHostFileSystemInfo'),
ExtHostFileSystemEventService: createExtId<ExtHostFileSystemEventServiceShape>('ExtHostFileSystemEventService'),
ExtHostLanguageFeatures: createExtId<ExtHostLanguageFeaturesShape>('ExtHostLanguageFeatures'),
ExtHostQuickOpen: createExtId<ExtHostQuickOpenShape>('ExtHostQuickOpen'),
Expand Down
19 changes: 6 additions & 13 deletions src/vs/workbench/api/common/extHostFileSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@ import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { FileChangeType } from 'vs/workbench/api/common/extHostTypes';
import * as typeConverter from 'vs/workbench/api/common/extHostTypeConverters';
import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures';
import { Schemas } from 'vs/base/common/network';
import { State, StateMachine, LinkComputer, Edge } from 'vs/editor/common/modes/linkComputer';
import { commonPrefixLength } from 'vs/base/common/strings';
import { CharCode } from 'vs/base/common/charCode';
import { VSBuffer } from 'vs/base/common/buffer';
import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';

class FsLinkProvider {

Expand Down Expand Up @@ -114,17 +113,14 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
private readonly _proxy: MainThreadFileSystemShape;
private readonly _linkProvider = new FsLinkProvider();
private readonly _fsProvider = new Map<number, vscode.FileSystemProvider>();
private readonly _usedSchemes = new Set<string>();
private readonly _registeredSchemes = new Set<string>();
private readonly _watches = new Map<number, IDisposable>();

private _linkProviderRegistration?: IDisposable;
private _handlePool: number = 0;

constructor(mainContext: IMainContext, private _extHostLanguageFeatures: ExtHostLanguageFeatures, private readonly _fileSystemConsumer: IExtHostConsumerFileSystem) {
constructor(mainContext: IMainContext, private _extHostLanguageFeatures: ExtHostLanguageFeatures, private _extHostFileSystemInfo: IExtHostFileSystemInfo) {
this._proxy = mainContext.getProxy(MainContext.MainThreadFileSystem);

// register used schemes
Object.keys(Schemas).forEach(scheme => this._usedSchemes.add(scheme));
}

dispose(): void {
Expand All @@ -139,18 +135,16 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {

registerFileSystemProvider(scheme: string, provider: vscode.FileSystemProvider, options: { isCaseSensitive?: boolean, isReadonly?: boolean } = {}) {

if (this._usedSchemes.has(scheme)) {
if (this._registeredSchemes.has(scheme) || !this._extHostFileSystemInfo.isFreeScheme(scheme)) {
throw new Error(`a provider for the scheme '${scheme}' is already registered`);
}

const schemeRegistration = this._fileSystemConsumer._registerScheme(scheme, options);

//
this._registerLinkProviderIfNotYetRegistered();

const handle = this._handlePool++;
this._linkProvider.add(scheme);
this._usedSchemes.add(scheme);
this._registeredSchemes.add(scheme);
this._fsProvider.set(handle, provider);

let capabilities = files.FileSystemProviderCapabilities.FileReadWrite;
Expand Down Expand Up @@ -200,9 +194,8 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {

return toDisposable(() => {
subscription.dispose();
schemeRegistration.dispose();
this._linkProvider.delete(scheme);
this._usedSchemes.delete(scheme);
this._registeredSchemes.delete(scheme);
this._fsProvider.delete(handle);
this._proxy.$unregisterProvider(handle);
});
Expand Down
23 changes: 8 additions & 15 deletions src/vs/workbench/api/common/extHostFileSystemConsumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ import { FileSystemError } from 'vs/workbench/api/common/extHostTypes';
import { VSBuffer } from 'vs/base/common/buffer';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';

export class ExtHostConsumerFileSystem implements vscode.FileSystem {

readonly _serviceBrand: undefined;

private readonly _proxy: MainThreadFileSystemShape;

private readonly _schemes = new Map<string, { readonly isReadonly?: boolean }>();

constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService) {
constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService,
@IExtHostFileSystemInfo private readonly _fileSystemInfo: IExtHostFileSystemInfo,
) {
this._proxy = extHostRpc.getProxy(MainContext.MainThreadFileSystem);
}

Expand Down Expand Up @@ -49,9 +50,9 @@ export class ExtHostConsumerFileSystem implements vscode.FileSystem {
return this._proxy.$copy(source, destination, { ...{ overwrite: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError);
}
isWritableFileSystem(scheme: string): boolean | undefined {
const entry = this._schemes.get(scheme);
if (entry) {
return !entry.isReadonly;
const capabilities = this._fileSystemInfo.getCapabilities(scheme);
if (typeof capabilities === 'number') {
return !(capabilities & files.FileSystemProviderCapabilities.Readonly);
}
return undefined;
}
Expand Down Expand Up @@ -79,14 +80,6 @@ export class ExtHostConsumerFileSystem implements vscode.FileSystem {
default: throw new FileSystemError(err.message, err.name as files.FileSystemProviderErrorCode);
}
}

/* internal */ _registerScheme(scheme: string, options: { readonly isReadonly?: boolean }): IDisposable {
this._schemes.set(scheme, options);

return toDisposable(() => {
return this._schemes.delete(scheme);
});
}
}

export interface IExtHostConsumerFileSystem extends ExtHostConsumerFileSystem { }
Expand Down
35 changes: 35 additions & 0 deletions src/vs/workbench/api/common/extHostFileSystemInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Schemas } from 'vs/base/common/network';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ExtHostFileSystemInfoShape } from 'vs/workbench/api/common/extHost.protocol';

export class ExtHostFileSystemInfo implements ExtHostFileSystemInfoShape {

declare readonly _serviceBrand: undefined;

private readonly _systemSchemes = new Set(Object.keys(Schemas));
private readonly _providerInfo = new Map<string, number>();

$acceptProviderInfos(scheme: string, capabilities: number | null): void {
if (capabilities === null) {
this._providerInfo.delete(scheme);
} else {
this._providerInfo.set(scheme, capabilities);
}
}

isFreeScheme(scheme: string): boolean {
return !this._providerInfo.has(scheme) && !this._systemSchemes.has(scheme);
}

getCapabilities(scheme: string): number | undefined {
return this._providerInfo.get(scheme);
}
}

export interface IExtHostFileSystemInfo extends ExtHostFileSystemInfo { }
export const IExtHostFileSystemInfo = createDecorator<IExtHostFileSystemInfo>('IExtHostFileSystemInfo');

0 comments on commit e38b9d0

Please sign in to comment.