提交 7aef0f87 编写于 作者: B Benjamin Pasero

storage - workspace ID computation fully from main.ts

上级 fd0c9390
......@@ -13,7 +13,7 @@ import * as comparer from 'vs/base/common/comparers';
import * as platform from 'vs/base/common/platform';
import { URI as uri } from 'vs/base/common/uri';
import { IWorkspaceContextService, Workspace, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { WorkspaceService, ISingleFolderWorkspaceInitializationPayload, IMultiFolderWorkspaceInitializationPayload, IEmptyWorkspaceInitializationPayload } from 'vs/workbench/services/configuration/node/configurationService';
import { WorkspaceService, ISingleFolderWorkspaceInitializationPayload, IMultiFolderWorkspaceInitializationPayload, IEmptyWorkspaceInitializationPayload, IWorkspaceInitializationPayload } from 'vs/workbench/services/configuration/node/configurationService';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { stat } from 'vs/base/node/pfs';
......@@ -45,6 +45,7 @@ import { IMenubarService } from 'vs/platform/menubar/common/menubar';
import { Schemas } from 'vs/base/common/network';
import { sanitizeFilePath } from 'vs/base/node/extfs';
import { basename } from 'path';
import { createHash } from 'crypto';
gracefulFs.gracefulify(fs); // enable gracefulFs
......@@ -140,7 +141,7 @@ function openWorkbench(configuration: IWindowConfiguration): Promise<void> {
}
function createAndInitializeWorkspaceService(configuration: IWindowConfiguration, environmentService: EnvironmentService): Promise<WorkspaceService> {
let workspaceInitializationPayload: Promise<IMultiFolderWorkspaceInitializationPayload | ISingleFolderWorkspaceInitializationPayload | IEmptyWorkspaceInitializationPayload> = Promise.resolve(void 0);
let workspaceInitializationPayload: Promise<IWorkspaceInitializationPayload> = Promise.resolve(void 0);
// Multi-root workspace
if (configuration.workspace) {
......@@ -154,7 +155,7 @@ function createAndInitializeWorkspaceService(configuration: IWindowConfiguration
return workspaceInitializationPayload.then(payload => {
// Fallback to empty workspace
// Fallback to empty workspace if we have no payload yet
if (!payload) {
payload = { id: configuration.backupPath ? uri.from({ path: basename(configuration.backupPath), scheme: 'empty' }).toString() : '' } as IEmptyWorkspaceInitializationPayload;
}
......@@ -167,17 +168,39 @@ function createAndInitializeWorkspaceService(configuration: IWindowConfiguration
function resolveSingleFolderWorkspaceInitializationPayload(folderUri: ISingleFolderWorkspaceIdentifier, verbose: boolean): Promise<ISingleFolderWorkspaceInitializationPayload> {
function singleFolderId(folder: uri, stat?: fs.Stats): string {
if (folder.scheme === Schemas.file && stat) {
let ctime: number;
if (platform.isLinux) {
ctime = stat.ino; // Linux: birthtime is ctime, so we cannot use it! We use the ino instead!
} else if (platform.isMacintosh) {
ctime = stat.birthtime.getTime(); // macOS: birthtime is fine to use as is
} else if (platform.isWindows) {
if (typeof stat.birthtimeMs === 'number') {
ctime = Math.floor(stat.birthtimeMs); // Windows: fix precision issue in node.js 8.x to get 7.x results (see https://github.com/nodejs/node/issues/19897)
} else {
ctime = stat.birthtime.getTime();
}
}
return createHash('md5').update(folder.fsPath).update(ctime ? String(ctime) : '').digest('hex');
}
return createHash('md5').update(folder.toString()).digest('hex');
}
// Return early the folder is not local
if (folderUri.scheme !== Schemas.file) {
return Promise.resolve({ folder: folderUri });
return Promise.resolve({ id: singleFolderId(folderUri), folder: folderUri });
}
// For local: ensure path is absolute and exists
const sanitizedFolderPath = sanitizeFilePath(folderUri.fsPath, process.env['VSCODE_CWD'] || process.cwd());
return stat(sanitizedFolderPath).then(stat => {
const sanitizedFolderUri = uri.file(sanitizedFolderPath);
return {
folder: uri.file(sanitizedFolderPath),
stat
id: singleFolderId(sanitizedFolderUri, stat),
folder: sanitizedFolderUri
} as ISingleFolderWorkspaceInitializationPayload;
}, error => {
if (verbose) {
......
......@@ -5,7 +5,6 @@
import { URI } from 'vs/base/common/uri';
import { dirname } from 'path';
import { Stats } from 'fs';
import * as assert from 'vs/base/common/assert';
import { Event, Emitter } from 'vs/base/common/event';
import { ResourceMap } from 'vs/base/common/map';
......@@ -15,7 +14,7 @@ import { Queue } from 'vs/base/common/async';
import { writeFile } from 'vs/base/node/pfs';
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { IWorkspaceContextService, Workspace, WorkbenchState, IWorkspaceFolder, toWorkspaceFolders, IWorkspaceFoldersChangeEvent, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { isLinux, isWindows, isMacintosh } from 'vs/base/common/platform';
import { isLinux } from 'vs/base/common/platform';
import { IFileService } from 'vs/platform/files/common/files';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ConfigurationChangeEvent, ConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
......@@ -24,7 +23,6 @@ import { Configuration, WorkspaceConfigurationChangeEvent, AllKeysConfigurationC
import { IWorkspaceConfigurationService, FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationNode, IConfigurationRegistry, Extensions, IConfigurationPropertySchema, allSettings, windowSettings, resourceSettings, applicationSettings } from 'vs/platform/configuration/common/configurationRegistry';
import { createHash } from 'crypto';
import { IWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ICommandService } from 'vs/platform/commands/common/commands';
......@@ -41,8 +39,9 @@ import { localize } from 'vs/nls';
import { isEqual } from 'vs/base/common/resources';
export type IMultiFolderWorkspaceInitializationPayload = IWorkspaceIdentifier;
export interface ISingleFolderWorkspaceInitializationPayload { folder: ISingleFolderWorkspaceIdentifier; stat?: Stats; }
export interface ISingleFolderWorkspaceInitializationPayload { id: string; folder: URI; }
export interface IEmptyWorkspaceInitializationPayload { id: string; }
export type IWorkspaceInitializationPayload = IMultiFolderWorkspaceInitializationPayload | ISingleFolderWorkspaceInitializationPayload | IEmptyWorkspaceInitializationPayload;
function isSingleFolderWorkspaceInitializationPayload(obj: any): obj is ISingleFolderWorkspaceInitializationPayload {
return isSingleFolderWorkspaceIdentifier((obj.folder as ISingleFolderWorkspaceIdentifier));
......@@ -352,27 +351,15 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
private createSingleFolderWorkspace(singleFolder: ISingleFolderWorkspaceInitializationPayload): Promise<Workspace> {
const folder = singleFolder.folder;
if (folder.scheme === Schemas.file && singleFolder.stat) {
const workspaceStat = singleFolder.stat;
let ctime: number;
if (isLinux) {
ctime = workspaceStat.ino; // Linux: birthtime is ctime, so we cannot use it! We use the ino instead!
} else if (isMacintosh) {
ctime = workspaceStat.birthtime.getTime(); // macOS: birthtime is fine to use as is
} else if (isWindows) {
if (typeof workspaceStat.birthtimeMs === 'number') {
ctime = Math.floor(workspaceStat.birthtimeMs); // Windows: fix precision issue in node.js 8.x to get 7.x results (see https://github.com/nodejs/node/issues/19897)
} else {
ctime = workspaceStat.birthtime.getTime();
}
}
const id = createHash('md5').update(folder.fsPath).update(ctime ? String(ctime) : '').digest('hex');
return Promise.resolve(new Workspace(id, toWorkspaceFolders([{ path: folder.fsPath }]), null, ctime));
let configuredFolders: IStoredWorkspaceFolder[];
if (folder.scheme === 'file') {
configuredFolders = [{ path: folder.fsPath }];
} else {
const id = createHash('md5').update(folder.toString()).digest('hex');
return Promise.resolve(new Workspace(id, toWorkspaceFolders([{ uri: folder.toString() }]), null));
configuredFolders = [{ uri: folder.toString() }];
}
return Promise.resolve(new Workspace(singleFolder.id, toWorkspaceFolders(configuredFolders), null));
}
private createEmptyWorkspace(emptyWorkspace: IEmptyWorkspaceInitializationPayload): Promise<Workspace> {
......
......@@ -36,6 +36,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
import { CommandService } from 'vs/workbench/services/commands/common/commandService';
import { URI } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { createHash } from 'crypto';
class SettingsTestEnvironmentService extends EnvironmentService {
......@@ -101,7 +102,7 @@ suite('ConfigurationEditingService', () => {
instantiationService.stub(IEnvironmentService, environmentService);
const workspaceService = new WorkspaceService(environmentService);
instantiationService.stub(IWorkspaceContextService, workspaceService);
return workspaceService.initialize(noWorkspace ? { id: '' } : { folder: URI.file(workspaceDir) }).then(() => {
return workspaceService.initialize(noWorkspace ? { id: '' } : { folder: URI.file(workspaceDir), id: createHash('md5').update(URI.file(workspaceDir).toString()).digest('hex') }).then(() => {
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IFileService, new FileService(workspaceService, TestEnvironmentService, new TestTextResourceConfigurationService(), new TestConfigurationService(), new TestLifecycleService(), new TestStorageService(), new TestNotificationService(), { disableWatcher: true }));
instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService));
......
......@@ -16,7 +16,7 @@ import { parseArgs } from 'vs/platform/environment/node/argv';
import * as pfs from 'vs/base/node/pfs';
import * as uuid from 'vs/base/common/uuid';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService';
import { WorkspaceService, ISingleFolderWorkspaceInitializationPayload } from 'vs/workbench/services/configuration/node/configurationService';
import { ConfigurationEditingErrorCode } from 'vs/workbench/services/configuration/node/configurationEditingService';
import { IFileService } from 'vs/platform/files/common/files';
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace';
......@@ -31,6 +31,8 @@ import { TextModelResolverService } from 'vs/workbench/services/textmodelResolve
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { Uri } from 'vscode';
import { createHash } from 'crypto';
class SettingsTestEnvironmentService extends EnvironmentService {
......@@ -53,6 +55,13 @@ function setUpFolder(folderName: string, parentDir: string): Promise<string> {
return Promise.resolve(pfs.mkdirp(workspaceSettingsDir, 493).then(() => folderDir));
}
function convertToWorkspacePayload(folder: Uri): ISingleFolderWorkspaceInitializationPayload {
return {
id: createHash('md5').update(folder.fsPath).digest('hex'),
folder
} as ISingleFolderWorkspaceInitializationPayload;
}
function setUpWorkspace(folders: string[]): Promise<{ parentDir: string, configPath: string }> {
const id = uuid.generateUuid();
......@@ -83,7 +92,7 @@ suite('WorkspaceContextService - Folder', () => {
const globalSettingsFile = path.join(parentDir, 'settings.json');
const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile);
workspaceContextService = new WorkspaceService(environmentService);
return (<WorkspaceService>workspaceContextService).initialize({ folder: URI.file(folderDir) });
return (<WorkspaceService>workspaceContextService).initialize(convertToWorkspacePayload(URI.file(folderDir)));
});
});
......@@ -441,7 +450,7 @@ suite('WorkspaceService - Initialization', () => {
testObject.onDidChangeWorkspaceFolders(target);
testObject.onDidChangeConfiguration(target);
return testObject.initialize({ folder: URI.file(path.join(parentResource, '1')) })
return testObject.initialize(convertToWorkspacePayload(URI.file(path.join(parentResource, '1'))))
.then(() => {
assert.equal(testObject.getValue('initialization.testSetting1'), 'userValue');
assert.equal(target.callCount, 3);
......@@ -470,7 +479,7 @@ suite('WorkspaceService - Initialization', () => {
fs.writeFileSync(path.join(parentResource, '1', '.vscode', 'settings.json'), '{ "initialization.testSetting1": "workspaceValue" }');
return testObject.initialize({ folder: URI.file(path.join(parentResource, '1')) })
return testObject.initialize(convertToWorkspacePayload(URI.file(path.join(parentResource, '1'))))
.then(() => {
assert.equal(testObject.getValue('initialization.testSetting1'), 'workspaceValue');
assert.equal(target.callCount, 4);
......@@ -544,7 +553,7 @@ suite('WorkspaceService - Initialization', () => {
test('initialize a folder workspace from a folder workspace with no configuration changes', () => {
return testObject.initialize({ folder: URI.file(path.join(parentResource, '1')) })
return testObject.initialize(convertToWorkspacePayload(URI.file(path.join(parentResource, '1'))))
.then(() => {
fs.writeFileSync(globalSettingsFile, '{ "initialization.testSetting1": "userValue" }');
......@@ -556,7 +565,7 @@ suite('WorkspaceService - Initialization', () => {
testObject.onDidChangeWorkspaceFolders(target);
testObject.onDidChangeConfiguration(target);
return testObject.initialize({ folder: URI.file(path.join(parentResource, '2')) })
return testObject.initialize(convertToWorkspacePayload(URI.file(path.join(parentResource, '2'))))
.then(() => {
assert.equal(testObject.getValue('initialization.testSetting1'), 'userValue');
assert.equal(target.callCount, 1);
......@@ -572,7 +581,7 @@ suite('WorkspaceService - Initialization', () => {
test('initialize a folder workspace from a folder workspace with configuration changes', () => {
return testObject.initialize({ folder: URI.file(path.join(parentResource, '1')) })
return testObject.initialize(convertToWorkspacePayload(URI.file(path.join(parentResource, '1'))))
.then(() => {
const target = sinon.spy();
......@@ -582,7 +591,7 @@ suite('WorkspaceService - Initialization', () => {
testObject.onDidChangeConfiguration(target);
fs.writeFileSync(path.join(parentResource, '2', '.vscode', 'settings.json'), '{ "initialization.testSetting1": "workspaceValue2" }');
return testObject.initialize({ folder: URI.file(path.join(parentResource, '2')) })
return testObject.initialize(convertToWorkspacePayload(URI.file(path.join(parentResource, '2'))))
.then(() => {
assert.equal(testObject.getValue('initialization.testSetting1'), 'workspaceValue2');
assert.equal(target.callCount, 2);
......@@ -597,7 +606,7 @@ suite('WorkspaceService - Initialization', () => {
test('initialize a multi folder workspace from a folder workspacce triggers change events in the right order', () => {
const folderDir = path.join(parentResource, '1');
return testObject.initialize({ folder: URI.file(folderDir) })
return testObject.initialize(convertToWorkspacePayload(URI.file(folderDir)))
.then(() => {
const target = sinon.spy();
......@@ -662,7 +671,7 @@ suite('WorkspaceConfigurationService - Folder', () => {
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IEnvironmentService, environmentService);
return workspaceService.initialize({ folder: URI.file(folderDir) }).then(() => {
return workspaceService.initialize(convertToWorkspacePayload(URI.file(folderDir))).then(() => {
const fileService = new FileService(<IWorkspaceContextService>workspaceService, TestEnvironmentService, new TestTextResourceConfigurationService(), workspaceService, new TestLifecycleService(), new TestStorageService(), new TestNotificationService(), { disableWatcher: true });
instantiationService.stub(IFileService, fileService);
instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册