提交 356d9f78 编写于 作者: S Sandeep Somavarapu

Fix #109015

上级 cf1596bb
......@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { mark } from 'vs/base/common/performance';
import { hash } from 'vs/base/common/hash';
import { domContentLoaded, addDisposableListener, EventType, EventHelper, detectFullscreen, addDisposableThrottledListener } from 'vs/base/browser/dom';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { ILogService, ConsoleLogService, MultiplexLogService, getLogLevel } from 'vs/platform/log/common/log';
......@@ -44,7 +45,6 @@ import { isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/wi
import { getWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces';
import { coalesce } from 'vs/base/common/arrays';
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
import { WebResourceIdentityService, IResourceIdentityService } from 'vs/workbench/services/resourceIdentity/common/resourceIdentityService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IIndexedDBFileSystemProvider, IndexedDB, INDEXEDDB_LOGS_OBJECT_STORE, INDEXEDDB_USERDATA_OBJECT_STORE } from 'vs/platform/files/browser/indexedDBFileSystemProvider';
import { BrowserRequestService } from 'vs/workbench/services/request/browser/requestService';
......@@ -164,11 +164,7 @@ class BrowserMain extends Disposable {
// CONTRIBUTE IT VIA WORKBENCH.WEB.MAIN.TS AND registerSingleton().
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Resource Identity
const resourceIdentityService = this._register(new WebResourceIdentityService());
serviceCollection.set(IResourceIdentityService, resourceIdentityService);
const payload = await this.resolveWorkspaceInitializationPayload(resourceIdentityService);
const payload = await this.resolveWorkspaceInitializationPayload();
// Product
const productService: IProductService = { _serviceBrand: undefined, ...product, ...this.configuration.productConfiguration };
......@@ -347,7 +343,7 @@ class BrowserMain extends Disposable {
}
}
private async resolveWorkspaceInitializationPayload(resourceIdentityService: IResourceIdentityService): Promise<IWorkspaceInitializationPayload> {
private async resolveWorkspaceInitializationPayload(): Promise<IWorkspaceInitializationPayload> {
let workspace: IWorkspace | undefined = undefined;
if (this.configuration.workspaceProvider) {
workspace = this.configuration.workspaceProvider.workspace;
......@@ -360,7 +356,7 @@ class BrowserMain extends Disposable {
// Single-folder workspace
if (workspace && isFolderToOpen(workspace)) {
const id = await resourceIdentityService.resolveResourceIdentity(workspace.folderUri);
const id = hash(workspace.folderUri.toString()).toString(16);
return { id, folder: workspace.folderUri };
}
......
......@@ -5,6 +5,9 @@
import * as fs from 'fs';
import * as gracefulFs from 'graceful-fs';
import { createHash } from 'crypto';
import { stat } from 'vs/base/node/pfs';
import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
import { zoomLevelToZoomFactor } from 'vs/platform/windows/common/windows';
import { importEntries, mark } from 'vs/base/common/performance';
import { Workbench } from 'vs/workbench/browser/workbench';
......@@ -45,8 +48,6 @@ import { FileUserDataProvider } from 'vs/workbench/services/userData/common/file
import { basename } from 'vs/base/common/resources';
import { IProductService } from 'vs/platform/product/common/productService';
import product from 'vs/platform/product/common/product';
import { NativeResourceIdentityService } from 'vs/workbench/services/resourceIdentity/node/resourceIdentityServiceImpl';
import { IResourceIdentityService } from 'vs/workbench/services/resourceIdentity/common/resourceIdentityService';
import { NativeLogService } from 'vs/workbench/services/log/electron-browser/logService';
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
import { NativeHostService } from 'vs/platform/native/electron-sandbox/nativeHostService';
......@@ -253,10 +254,7 @@ class DesktopMain extends Disposable {
fileService.registerProvider(Schemas.vscodeRemote, remoteFileSystemProvider);
}
const resourceIdentityService = this._register(new NativeResourceIdentityService());
serviceCollection.set(IResourceIdentityService, resourceIdentityService);
const payload = await this.resolveWorkspaceInitializationPayload(resourceIdentityService);
const payload = await this.resolveWorkspaceInitializationPayload();
const services = await Promise.all([
this.createWorkspaceService(payload, fileService, remoteAgentService, logService).then(service => {
......@@ -296,7 +294,7 @@ class DesktopMain extends Disposable {
return { serviceCollection, logService, storageService: services[1] };
}
private async resolveWorkspaceInitializationPayload(resourceIdentityService: IResourceIdentityService): Promise<IWorkspaceInitializationPayload> {
private async resolveWorkspaceInitializationPayload(): Promise<IWorkspaceInitializationPayload> {
// Multi-root workspace
if (this.configuration.workspace) {
......@@ -306,7 +304,7 @@ class DesktopMain extends Disposable {
// Single-folder workspace
let workspaceInitializationPayload: IWorkspaceInitializationPayload | undefined;
if (this.configuration.folderUri) {
workspaceInitializationPayload = await this.resolveSingleFolderWorkspaceInitializationPayload(this.configuration.folderUri, resourceIdentityService);
workspaceInitializationPayload = await this.resolveSingleFolderWorkspaceInitializationPayload(this.configuration.folderUri);
}
// Fallback to empty workspace if we have no payload yet.
......@@ -326,12 +324,12 @@ class DesktopMain extends Disposable {
return workspaceInitializationPayload;
}
private async resolveSingleFolderWorkspaceInitializationPayload(folderUri: ISingleFolderWorkspaceIdentifier, resourceIdentityService: IResourceIdentityService): Promise<ISingleFolderWorkspaceInitializationPayload | undefined> {
private async resolveSingleFolderWorkspaceInitializationPayload(folderUri: ISingleFolderWorkspaceIdentifier): Promise<ISingleFolderWorkspaceInitializationPayload | undefined> {
try {
const folder = folderUri.scheme === Schemas.file
? URI.file(sanitizeFilePath(folderUri.fsPath, process.env['VSCODE_CWD'] || process.cwd())) // For local: ensure path is absolute
: folderUri;
const id = await resourceIdentityService.resolveResourceIdentity(folderUri);
const id = await this.createHash(folderUri);
return { id, folder };
} catch (error) {
onUnexpectedError(error);
......@@ -339,6 +337,31 @@ class DesktopMain extends Disposable {
return;
}
private async createHash(resource: URI): Promise<string> {
// Return early the folder is not local
if (resource.scheme !== Schemas.file) {
return createHash('md5').update(resource.toString()).digest('hex');
}
const fileStat = await stat(resource.fsPath);
let ctime: number | undefined;
if (isLinux) {
ctime = fileStat.ino; // Linux: birthtime is ctime, so we cannot use it! We use the ino instead!
} else if (isMacintosh) {
ctime = fileStat.birthtime.getTime(); // macOS: birthtime is fine to use as is
} else if (isWindows) {
if (typeof fileStat.birthtimeMs === 'number') {
ctime = Math.floor(fileStat.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 = fileStat.birthtime.getTime();
}
}
// we use the ctime as extra salt to the ID so that we catch the case of a folder getting
// deleted and recreated. in that case we do not want to carry over previous state
return createHash('md5').update(resource.fsPath).update(ctime ? String(ctime) : '').digest('hex');
}
private async createWorkspaceService(payload: IWorkspaceInitializationPayload, fileService: FileService, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise<WorkspaceService> {
const workspaceService = new WorkspaceService({ remoteAuthority: this.environmentService.remoteAuthority, configurationCache: new ConfigurationCache(this.environmentService) }, this.environmentService, fileService, remoteAgentService, logService);
......
......@@ -29,10 +29,9 @@ import { ISignService } from 'vs/platform/sign/common/sign';
import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider';
import { IProductService } from 'vs/platform/product/common/productService';
import product from 'vs/platform/product/common/product';
import { IResourceIdentityService } from 'vs/workbench/services/resourceIdentity/common/resourceIdentityService';
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
import { NativeHostService } from 'vs/platform/native/electron-sandbox/nativeHostService';
import { SimpleConfigurationService, simpleFileSystemProvider, SimpleLogService, SimpleRemoteAgentService, SimpleResourceIdentityService, SimpleSignService, SimpleStorageService, SimpleNativeWorkbenchEnvironmentService, SimpleWorkspaceService } from 'vs/workbench/electron-sandbox/sandbox.simpleservices';
import { SimpleConfigurationService, simpleFileSystemProvider, SimpleLogService, SimpleRemoteAgentService, SimpleSignService, SimpleStorageService, SimpleNativeWorkbenchEnvironmentService, SimpleWorkspaceService } from 'vs/workbench/electron-sandbox/sandbox.simpleservices';
import { INativeWorkbenchConfiguration, INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService';
import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-sandbox/remoteAuthorityResolverService';
......@@ -214,10 +213,6 @@ class DesktopMain extends Disposable {
fileService.registerProvider(Schemas.vscodeRemote, remoteFileSystemProvider);
}
const resourceIdentityService = new SimpleResourceIdentityService();
serviceCollection.set(IResourceIdentityService, resourceIdentityService);
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// NOTE: Please do NOT register services here. Use `registerSingleton()`
......
......@@ -7,9 +7,7 @@
/* eslint-disable code-import-patterns */
import { ConsoleLogService } from 'vs/platform/log/common/log';
import { IResourceIdentityService } from 'vs/workbench/services/resourceIdentity/common/resourceIdentityService';
import { ISignService } from 'vs/platform/sign/common/sign';
import { hash } from 'vs/base/common/hash';
import { URI } from 'vs/base/common/uri';
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
import { Event } from 'vs/base/common/event';
......@@ -418,19 +416,6 @@ module.exports = testRunner;`);
//#endregion
//#region Resource Identity
export class SimpleResourceIdentityService implements IResourceIdentityService {
declare readonly _serviceBrand: undefined;
async resolveResourceIdentity(resource: URI): Promise<string> { return hash(resource.toString()).toString(16); }
}
//#endregion
//#region Remote
export class SimpleRemoteAgentService implements IRemoteAgentService {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { URI } from 'vs/base/common/uri';
import { hash } from 'vs/base/common/hash';
import { Disposable } from 'vs/base/common/lifecycle';
export const IResourceIdentityService = createDecorator<IResourceIdentityService>('IResourceIdentityService');
export interface IResourceIdentityService {
readonly _serviceBrand: undefined;
resolveResourceIdentity(resource: URI): Promise<string>;
}
export class WebResourceIdentityService extends Disposable implements IResourceIdentityService {
declare readonly _serviceBrand: undefined;
async resolveResourceIdentity(resource: URI): Promise<string> {
return hash(resource.toString()).toString(16);
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createHash } from 'crypto';
import { stat } from 'vs/base/node/pfs';
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
import { IResourceIdentityService } from 'vs/workbench/services/resourceIdentity/common/resourceIdentityService';
import { Disposable } from 'vs/base/common/lifecycle';
import { ResourceMap } from 'vs/base/common/map';
export class NativeResourceIdentityService extends Disposable implements IResourceIdentityService {
declare readonly _serviceBrand: undefined;
private readonly cache: ResourceMap<Promise<string>> = new ResourceMap<Promise<string>>();
resolveResourceIdentity(resource: URI): Promise<string> {
let promise = this.cache.get(resource);
if (!promise) {
promise = this.createIdentity(resource);
this.cache.set(resource, promise);
}
return promise;
}
private async createIdentity(resource: URI): Promise<string> {
// Return early the folder is not local
if (resource.scheme !== Schemas.file) {
return createHash('md5').update(resource.toString()).digest('hex');
}
const fileStat = await stat(resource.fsPath);
let ctime: number | undefined;
if (isLinux) {
ctime = fileStat.ino; // Linux: birthtime is ctime, so we cannot use it! We use the ino instead!
} else if (isMacintosh) {
ctime = fileStat.birthtime.getTime(); // macOS: birthtime is fine to use as is
} else if (isWindows) {
if (typeof fileStat.birthtimeMs === 'number') {
ctime = Math.floor(fileStat.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 = fileStat.birthtime.getTime();
}
}
// we use the ctime as extra salt to the ID so that we catch the case of a folder getting
// deleted and recreated. in that case we do not want to carry over previous state
return createHash('md5').update(resource.fsPath).update(ctime ? String(ctime) : '').digest('hex');
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册