mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-23 01:58:53 +01:00
add storageUri and globalStorageUri to ExtensionContext, https://github.com/microsoft/vscode/issues/101857
This commit is contained in:
@@ -75,6 +75,7 @@ import { ExtHostAuthentication } from 'vs/workbench/api/common/extHostAuthentica
|
||||
import { ExtHostTimeline } from 'vs/workbench/api/common/extHostTimeline';
|
||||
import { ExtHostNotebookConcatDocument } from 'vs/workbench/api/common/extHostNotebookConcatDocument';
|
||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||
import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
|
||||
|
||||
export interface IExtensionApiFactory {
|
||||
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
|
||||
@@ -87,6 +88,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
|
||||
// services
|
||||
const initData = accessor.get(IExtHostInitDataService);
|
||||
const extHostConsumerFileSystem = accessor.get(IExtHostConsumerFileSystem);
|
||||
const extensionService = accessor.get(IExtHostExtensionService);
|
||||
const extHostWorkspace = accessor.get(IExtHostWorkspace);
|
||||
const extHostConfiguration = accessor.get(IExtHostConfiguration);
|
||||
@@ -746,7 +748,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
return extHostFileSystem.registerFileSystemProvider(scheme, provider, options);
|
||||
},
|
||||
get fs() {
|
||||
return extHostFileSystem.fileSystem;
|
||||
return extHostConsumerFileSystem;
|
||||
},
|
||||
registerFileSearchProvider: (scheme: string, provider: vscode.FileSearchProvider) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
|
||||
@@ -386,14 +386,22 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
||||
subscriptions: [],
|
||||
get extensionUri() { return extensionDescription.extensionLocation; },
|
||||
get extensionPath() { return extensionDescription.extensionLocation.fsPath; },
|
||||
get storagePath() { return that._storagePath.workspaceValue(extensionDescription); },
|
||||
get globalStoragePath() { return that._storagePath.globalValue(extensionDescription); },
|
||||
asAbsolutePath(relativePath: string) { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); },
|
||||
get storagePath() { return that._storagePath.workspaceValue(extensionDescription)?.fsPath; },
|
||||
get globalStoragePath() { return that._storagePath.globalValue(extensionDescription).fsPath; },
|
||||
get logPath() { return path.join(that._initData.logsLocation.fsPath, extensionDescription.identifier.value); },
|
||||
get logUri() {
|
||||
checkProposedApiEnabled(extensionDescription);
|
||||
return URI.joinPath(that._initData.logsLocation, extensionDescription.identifier.value);
|
||||
},
|
||||
get logPath() { return path.join(that._initData.logsLocation.fsPath, extensionDescription.identifier.value); },
|
||||
get storageUri() {
|
||||
checkProposedApiEnabled(extensionDescription);
|
||||
return that._storagePath.workspaceValue(extensionDescription);
|
||||
},
|
||||
get globalStorageUri() {
|
||||
checkProposedApiEnabled(extensionDescription);
|
||||
return that._storagePath.globalValue(extensionDescription);
|
||||
},
|
||||
get extensionMode() { return extensionMode; },
|
||||
get environmentVariableCollection() { return that._extHostTerminalService.getEnvironmentVariableCollection(extensionDescription); }
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ import { MainContext, IMainContext, ExtHostFileSystemShape, MainThreadFileSystem
|
||||
import type * as vscode from 'vscode';
|
||||
import * as files from 'vs/platform/files/common/files';
|
||||
import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { FileChangeType, FileSystemError } from 'vs/workbench/api/common/extHostTypes';
|
||||
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';
|
||||
@@ -108,59 +108,6 @@ class FsLinkProvider {
|
||||
}
|
||||
}
|
||||
|
||||
class ConsumerFileSystem implements vscode.FileSystem {
|
||||
|
||||
constructor(private _proxy: MainThreadFileSystemShape) { }
|
||||
|
||||
stat(uri: vscode.Uri): Promise<vscode.FileStat> {
|
||||
return this._proxy.$stat(uri).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> {
|
||||
return this._proxy.$readdir(uri).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
createDirectory(uri: vscode.Uri): Promise<void> {
|
||||
return this._proxy.$mkdir(uri).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
async readFile(uri: vscode.Uri): Promise<Uint8Array> {
|
||||
return this._proxy.$readFile(uri).then(buff => buff.buffer).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
writeFile(uri: vscode.Uri, content: Uint8Array): Promise<void> {
|
||||
return this._proxy.$writeFile(uri, VSBuffer.wrap(content)).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
delete(uri: vscode.Uri, options?: { recursive?: boolean; useTrash?: boolean; }): Promise<void> {
|
||||
return this._proxy.$delete(uri, { ...{ recursive: false, useTrash: false }, ...options }).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options?: { overwrite?: boolean; }): Promise<void> {
|
||||
return this._proxy.$rename(oldUri, newUri, { ...{ overwrite: false }, ...options }).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
copy(source: vscode.Uri, destination: vscode.Uri, options?: { overwrite?: boolean }): Promise<void> {
|
||||
return this._proxy.$copy(source, destination, { ...{ overwrite: false }, ...options }).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
private static _handleError(err: any): never {
|
||||
// generic error
|
||||
if (!(err instanceof Error)) {
|
||||
throw new FileSystemError(String(err));
|
||||
}
|
||||
|
||||
// no provider (unknown scheme) error
|
||||
if (err.name === 'ENOPRO') {
|
||||
throw FileSystemError.Unavailable(err.message);
|
||||
}
|
||||
|
||||
// file system error
|
||||
switch (err.name) {
|
||||
case files.FileSystemProviderErrorCode.FileExists: throw FileSystemError.FileExists(err.message);
|
||||
case files.FileSystemProviderErrorCode.FileNotFound: throw FileSystemError.FileNotFound(err.message);
|
||||
case files.FileSystemProviderErrorCode.FileNotADirectory: throw FileSystemError.FileNotADirectory(err.message);
|
||||
case files.FileSystemProviderErrorCode.FileIsADirectory: throw FileSystemError.FileIsADirectory(err.message);
|
||||
case files.FileSystemProviderErrorCode.NoPermissions: throw FileSystemError.NoPermissions(err.message);
|
||||
case files.FileSystemProviderErrorCode.Unavailable: throw FileSystemError.Unavailable(err.message);
|
||||
|
||||
default: throw new FileSystemError(err.message, err.name as files.FileSystemProviderErrorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
|
||||
private readonly _proxy: MainThreadFileSystemShape;
|
||||
@@ -172,11 +119,8 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
private _linkProviderRegistration?: IDisposable;
|
||||
private _handlePool: number = 0;
|
||||
|
||||
readonly fileSystem: vscode.FileSystem;
|
||||
|
||||
constructor(mainContext: IMainContext, private _extHostLanguageFeatures: ExtHostLanguageFeatures) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadFileSystem);
|
||||
this.fileSystem = new ConsumerFileSystem(this._proxy);
|
||||
|
||||
// register used schemes
|
||||
Object.keys(Schemas).forEach(scheme => this._usedSchemes.add(scheme));
|
||||
|
||||
74
src/vs/workbench/api/common/extHostFileSystemConsumer.ts
Normal file
74
src/vs/workbench/api/common/extHostFileSystemConsumer.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { MainThreadFileSystemShape, MainContext } from './extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
import * as files from 'vs/platform/files/common/files';
|
||||
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';
|
||||
|
||||
export class ExtHostConsumerFileSystem implements vscode.FileSystem {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly _proxy: MainThreadFileSystemShape;
|
||||
|
||||
constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService) {
|
||||
this._proxy = extHostRpc.getProxy(MainContext.MainThreadFileSystem);
|
||||
}
|
||||
|
||||
stat(uri: vscode.Uri): Promise<vscode.FileStat> {
|
||||
return this._proxy.$stat(uri).catch(ExtHostConsumerFileSystem._handleError);
|
||||
}
|
||||
readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> {
|
||||
return this._proxy.$readdir(uri).catch(ExtHostConsumerFileSystem._handleError);
|
||||
}
|
||||
createDirectory(uri: vscode.Uri): Promise<void> {
|
||||
return this._proxy.$mkdir(uri).catch(ExtHostConsumerFileSystem._handleError);
|
||||
}
|
||||
async readFile(uri: vscode.Uri): Promise<Uint8Array> {
|
||||
return this._proxy.$readFile(uri).then(buff => buff.buffer).catch(ExtHostConsumerFileSystem._handleError);
|
||||
}
|
||||
writeFile(uri: vscode.Uri, content: Uint8Array): Promise<void> {
|
||||
return this._proxy.$writeFile(uri, VSBuffer.wrap(content)).catch(ExtHostConsumerFileSystem._handleError);
|
||||
}
|
||||
delete(uri: vscode.Uri, options?: { recursive?: boolean; useTrash?: boolean; }): Promise<void> {
|
||||
return this._proxy.$delete(uri, { ...{ recursive: false, useTrash: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError);
|
||||
}
|
||||
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options?: { overwrite?: boolean; }): Promise<void> {
|
||||
return this._proxy.$rename(oldUri, newUri, { ...{ overwrite: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError);
|
||||
}
|
||||
copy(source: vscode.Uri, destination: vscode.Uri, options?: { overwrite?: boolean; }): Promise<void> {
|
||||
return this._proxy.$copy(source, destination, { ...{ overwrite: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError);
|
||||
}
|
||||
private static _handleError(err: any): never {
|
||||
// generic error
|
||||
if (!(err instanceof Error)) {
|
||||
throw new FileSystemError(String(err));
|
||||
}
|
||||
|
||||
// no provider (unknown scheme) error
|
||||
if (err.name === 'ENOPRO') {
|
||||
throw FileSystemError.Unavailable(err.message);
|
||||
}
|
||||
|
||||
// file system error
|
||||
switch (err.name) {
|
||||
case files.FileSystemProviderErrorCode.FileExists: throw FileSystemError.FileExists(err.message);
|
||||
case files.FileSystemProviderErrorCode.FileNotFound: throw FileSystemError.FileNotFound(err.message);
|
||||
case files.FileSystemProviderErrorCode.FileNotADirectory: throw FileSystemError.FileNotADirectory(err.message);
|
||||
case files.FileSystemProviderErrorCode.FileIsADirectory: throw FileSystemError.FileIsADirectory(err.message);
|
||||
case files.FileSystemProviderErrorCode.NoPermissions: throw FileSystemError.NoPermissions(err.message);
|
||||
case files.FileSystemProviderErrorCode.Unavailable: throw FileSystemError.Unavailable(err.message);
|
||||
|
||||
default: throw new FileSystemError(err.message, err.name as files.FileSystemProviderErrorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface IExtHostConsumerFileSystem extends ExtHostConsumerFileSystem { }
|
||||
export const IExtHostConsumerFileSystem = createDecorator<IExtHostConsumerFileSystem>('IExtHostConsumerFileSystem');
|
||||
@@ -1020,7 +1020,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
if (provider) {
|
||||
let storageRoot: URI | undefined;
|
||||
if (this._extensionStoragePaths) {
|
||||
storageRoot = URI.file(this._extensionStoragePaths.workspaceValue(provider.extension) ?? this._extensionStoragePaths.globalValue(provider.extension));
|
||||
storageRoot = this._extensionStoragePaths.workspaceValue(provider.extension) ?? this._extensionStoragePaths.globalValue(provider.extension);
|
||||
}
|
||||
|
||||
let document = this._documents.get(URI.revive(uri).toString());
|
||||
@@ -1330,7 +1330,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
const entry = this._notebookContentProviders.get(viewType);
|
||||
let storageRoot: URI | undefined;
|
||||
if (entry && this._extensionStoragePaths) {
|
||||
storageRoot = URI.file(this._extensionStoragePaths.workspaceValue(entry.extension) ?? this._extensionStoragePaths.globalValue(entry.extension));
|
||||
storageRoot = this._extensionStoragePaths.workspaceValue(entry.extension) ?? this._extensionStoragePaths.globalValue(entry.extension);
|
||||
}
|
||||
|
||||
if (!this._documents.has(revivedUriStr)) {
|
||||
|
||||
@@ -5,12 +5,83 @@
|
||||
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IEnvironment, IStaticWorkspaceData } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export const IExtensionStoragePaths = createDecorator<IExtensionStoragePaths>('IExtensionStoragePaths');
|
||||
|
||||
export interface IExtensionStoragePaths {
|
||||
readonly _serviceBrand: undefined;
|
||||
whenReady: Promise<any>;
|
||||
workspaceValue(extension: IExtensionDescription): string | undefined;
|
||||
globalValue(extension: IExtensionDescription): string;
|
||||
workspaceValue(extension: IExtensionDescription): URI | undefined;
|
||||
globalValue(extension: IExtensionDescription): URI;
|
||||
}
|
||||
|
||||
export class ExtensionStoragePaths implements IExtensionStoragePaths {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly _workspace?: IStaticWorkspaceData;
|
||||
private readonly _environment: IEnvironment;
|
||||
|
||||
readonly whenReady: Promise<URI | undefined>;
|
||||
private _value?: URI;
|
||||
|
||||
constructor(
|
||||
@IExtHostInitDataService initData: IExtHostInitDataService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
@IExtHostConsumerFileSystem private readonly _extHostFileSystem: IExtHostConsumerFileSystem
|
||||
) {
|
||||
this._workspace = initData.workspace ?? undefined;
|
||||
this._environment = initData.environment;
|
||||
this.whenReady = this._getOrCreateWorkspaceStoragePath().then(value => this._value = value);
|
||||
}
|
||||
|
||||
private async _getOrCreateWorkspaceStoragePath(): Promise<URI | undefined> {
|
||||
if (!this._workspace) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
const storageName = this._workspace.id;
|
||||
const storageUri = URI.joinPath(this._environment.workspaceStorageHome, storageName);
|
||||
|
||||
try {
|
||||
await this._extHostFileSystem.stat(storageUri);
|
||||
this._logService.trace('[ExtHostStorage] storage dir already exists', storageUri);
|
||||
return storageUri;
|
||||
} catch {
|
||||
// doesn't exist, that's OK
|
||||
}
|
||||
|
||||
try {
|
||||
this._logService.trace('[ExtHostStorage] creating dir and metadata-file', storageUri);
|
||||
await this._extHostFileSystem.createDirectory(storageUri);
|
||||
await this._extHostFileSystem.writeFile(
|
||||
URI.joinPath(storageUri, 'meta.json'),
|
||||
new TextEncoder().encode(JSON.stringify({
|
||||
id: this._workspace.id,
|
||||
configuration: URI.revive(this._workspace.configuration)?.toString(),
|
||||
name: this._workspace.name
|
||||
}, undefined, 2))
|
||||
);
|
||||
return storageUri;
|
||||
|
||||
} catch (e) {
|
||||
this._logService.error('[ExtHostStorage]', e);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
workspaceValue(extension: IExtensionDescription): URI | undefined {
|
||||
if (this._value) {
|
||||
return URI.joinPath(this._value, extension.identifier.value);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
globalValue(extension: IExtensionDescription): URI {
|
||||
return URI.joinPath(this._environment.globalStorageHome, extension.identifier.value.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,7 +598,7 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
|
||||
let storageRoot: URI | undefined;
|
||||
if (this.supportEditing(entry.provider) && this._extensionStoragePaths) {
|
||||
storageRoot = URI.file(this._extensionStoragePaths.workspaceValue(entry.extension) ?? this._extensionStoragePaths.globalValue(entry.extension));
|
||||
storageRoot = this._extensionStoragePaths.workspaceValue(entry.extension) ?? this._extensionStoragePaths.globalValue(entry.extension);
|
||||
}
|
||||
this._documents.add(viewType, document, storageRoot);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user