提交 cabd8ad3 编写于 作者: J Johannes Rieken

no more sync-fs when creating storage dir, #16388

上级 156b4d25
......@@ -6,6 +6,7 @@
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import * as paths from 'vs/base/common/paths';
import { mkdirp, dirExists } from 'vs/base/node/pfs';
import Severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';
import { AbstractExtensionService, ActivatedExtension } from 'vs/platform/extensions/common/abstractExtensionService';
......@@ -13,7 +14,9 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
import { ExtHostStorage } from 'vs/workbench/api/node/extHostStorage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { MainContext, MainProcessExtensionServiceShape } from './extHost.protocol';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { MainContext, MainProcessExtensionServiceShape, IEnvironment } from './extHost.protocol';
import { createHash } from 'crypto';
const hasOwnProperty = Object.hasOwnProperty;
......@@ -97,6 +100,57 @@ class ExtensionMemento implements IExtensionMemento {
}
}
class ExtensionStoragePath {
private readonly _contextService: IWorkspaceContextService;
private readonly _environment: IEnvironment;
private readonly _ready: TPromise<string>;
private _value: string;
constructor(contextService: IWorkspaceContextService, environment: IEnvironment) {
this._contextService = contextService;
this._environment = environment;
this._ready = this._getOrCreateWorkspaceStoragePath().then(value => this._value = value);
}
get whenReady(): TPromise<any> {
return this._ready;
}
get value(): string {
return this._value;
}
private _getOrCreateWorkspaceStoragePath(): TPromise<string> {
const workspace = this._contextService.getWorkspace();
if (!workspace) {
return TPromise.as(undefined);
}
const storageName = createHash('md5')
.update(workspace.resource.fsPath)
.update(workspace.uid ? workspace.uid.toString() : '')
.digest('hex');
const storagePath = paths.join(this._environment.appSettingsHome, 'workspaceStorage', storageName);
return dirExists(storagePath).then(exists => {
if (exists) {
return storagePath;
}
mkdirp(storagePath).then(success => {
return storagePath;
}, err => {
return undefined;
});
});
}
}
export interface IExtensionContext {
subscriptions: IDisposable[];
workspaceState: IExtensionMemento;
......@@ -110,21 +164,23 @@ export class ExtHostExtensionService extends AbstractExtensionService<ExtHostExt
private _threadService: IThreadService;
private _storage: ExtHostStorage;
private _storagePath: ExtensionStoragePath;
private _proxy: MainProcessExtensionServiceShape;
private _telemetryService: ITelemetryService;
private _workspaceStoragePath: string;
private _contextService: IWorkspaceContextService;
/**
* This class is constructed manually because it is a service, so it doesn't use any ctor injection
*/
constructor(availableExtensions: IExtensionDescription[], threadService: IThreadService, telemetryService: ITelemetryService, args: { _serviceBrand: any; workspaceStoragePath: string; }) {
constructor(availableExtensions: IExtensionDescription[], environment: IEnvironment, threadService: IThreadService, telemetryService: ITelemetryService, contextService: IWorkspaceContextService) {
super(true);
this._registry.registerExtensions(availableExtensions);
this._threadService = threadService;
this._storage = new ExtHostStorage(threadService);
this._storagePath = new ExtensionStoragePath(contextService, environment);
this._proxy = this._threadService.get(MainContext.MainProcessExtensionService);
this._telemetryService = telemetryService;
this._workspaceStoragePath = args.workspaceStoragePath;
this._contextService = contextService;
}
public getAllExtensionDescriptions(): IExtensionDescription[] {
......@@ -200,15 +256,18 @@ export class ExtHostExtensionService extends AbstractExtensionService<ExtHostExt
let globalState = new ExtensionMemento(extensionDescription.id, true, this._storage);
let workspaceState = new ExtensionMemento(extensionDescription.id, false, this._storage);
let storagePath = this._workspaceStoragePath ? paths.normalize(paths.join(this._workspaceStoragePath, extensionDescription.id)) : undefined;
return TPromise.join([globalState.whenReady, workspaceState.whenReady]).then(() => {
return TPromise.join([
globalState.whenReady,
workspaceState.whenReady,
this._storagePath.whenReady
]).then(() => {
return Object.freeze(<IExtensionContext>{
globalState,
workspaceState,
subscriptions: [],
get extensionPath() { return extensionDescription.extensionFolderPath; },
storagePath: storagePath,
storagePath: paths.join(this._storagePath.value, extensionDescription.id),
asAbsolutePath: (relativePath: string) => { return paths.normalize(paths.join(extensionDescription.extensionFolderPath, relativePath), true); }
});
});
......
......@@ -5,8 +5,6 @@
'use strict';
import * as fs from 'fs';
import * as crypto from 'crypto';
import nls = require('vs/nls');
import pfs = require('vs/base/node/pfs');
import { TPromise } from 'vs/base/common/winjs.base';
......@@ -35,25 +33,19 @@ interface ITestRunner {
export class ExtensionHostMain {
private _isTerminating: boolean;
private _isTerminating: boolean = false;
private _contextService: IWorkspaceContextService;
private _environment: IEnvironment;
private _extensionService: ExtHostExtensionService;
private _extensionApiCreation: TPromise<void>;
constructor(remoteCom: IMainProcessExtHostIPC, initData: IInitData) {
this._isTerminating = false;
// services
this._environment = initData.environment;
this._contextService = new WorkspaceContextService(initData.contextService.workspace);
const workspaceStoragePath = this._getOrCreateWorkspaceStoragePath();
const threadService = new ExtHostThreadService(remoteCom);
const telemetryService = new RemoteTelemetryService('pluginHostTelemetry', threadService);
this._extensionService = new ExtHostExtensionService(initData.extensions, threadService, telemetryService, { _serviceBrand: 'optionalArgs', workspaceStoragePath });
this._extensionService = new ExtHostExtensionService(initData.extensions, initData.environment, threadService, telemetryService, this._contextService);
// Error forwarding
const mainThreadErrors = threadService.get(MainContext.MainThreadErrors);
......@@ -64,53 +56,6 @@ export class ExtensionHostMain {
this._extensionApiCreation = initializeExtensionApi(this._extensionService, apiFactory);
}
private _getOrCreateWorkspaceStoragePath(): string {
let workspaceStoragePath: string;
const workspace = this._contextService.getWorkspace();
function rmkDir(directory: string): boolean {
try {
fs.mkdirSync(directory);
return true;
} catch (err) {
if (err.code === 'ENOENT') {
if (rmkDir(paths.dirname(directory))) {
fs.mkdirSync(directory);
return true;
}
} else {
return fs.statSync(directory).isDirectory();
}
}
}
if (workspace) {
const hash = crypto.createHash('md5');
hash.update(workspace.resource.fsPath);
if (workspace.uid) {
hash.update(workspace.uid.toString());
}
workspaceStoragePath = paths.join(this._environment.appSettingsHome, 'workspaceStorage', hash.digest('hex'));
if (!fs.existsSync(workspaceStoragePath)) {
try {
if (rmkDir(workspaceStoragePath)) {
fs.writeFileSync(paths.join(workspaceStoragePath, 'meta.json'), JSON.stringify({
workspacePath: workspace.resource.fsPath,
uid: workspace.uid ? workspace.uid : null
}, null, 4));
} else {
workspaceStoragePath = undefined;
}
} catch (err) {
workspaceStoragePath = undefined;
}
}
}
return workspaceStoragePath;
}
public start(): TPromise<void> {
return this._extensionApiCreation
.then(() => this.handleEagerExtensions())
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册