diff --git a/src/vs/workbench/electron-browser/desktop.main.ts b/src/vs/workbench/electron-browser/desktop.main.ts index 0c07d0613342987b177c68b2e552a8ecebc3c827..14c0514844f4b2d2699c24ebb798b533bf5bd0e1 100644 --- a/src/vs/workbench/electron-browser/desktop.main.ts +++ b/src/vs/workbench/electron-browser/desktop.main.ts @@ -234,7 +234,7 @@ class DesktopMain extends Disposable { fileService.registerProvider(Schemas.file, diskFileSystemProvider); // User Data Provider - fileService.registerProvider(Schemas.userData, new FileUserDataProvider(this.environmentService.appSettingsHome, this.configuration.backupPath ? URI.file(this.configuration.backupPath) : undefined, diskFileSystemProvider, this.environmentService, logService)); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.userData, logService)); // Uri Identity const uriIdentityService = new UriIdentityService(fileService); diff --git a/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-sandbox/desktop.main.ts index ad30130ca97a61670f200c01d54b34a2a798a092..eddd5ab64aa1797b77442d77c4ed7e5be7b2bb1d 100644 --- a/src/vs/workbench/electron-sandbox/desktop.main.ts +++ b/src/vs/workbench/electron-sandbox/desktop.main.ts @@ -207,7 +207,7 @@ class DesktopMain extends Disposable { fileService.registerProvider(Schemas.file, simpleFileSystemProvider); // User Data Provider - fileService.registerProvider(Schemas.userData, new FileUserDataProvider(URI.file('user-home'), undefined, simpleFileSystemProvider, this.environmentService, logService)); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(Schemas.file, simpleFileSystemProvider, Schemas.userData, logService)); // Uri Identity const uriIdentityService = new UriIdentityService(fileService); diff --git a/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts b/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts index 0e00c5a49826c9039a2ba8dc41feffc365f9b2eb..1cef40c5da75f880807899ae3b9cf4f5a17df2ec 100644 --- a/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts +++ b/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts @@ -67,7 +67,7 @@ export class NodeTestBackupFileService extends BackupFileService { const fileService = new FileService(logService); const diskFileSystemProvider = new DiskFileSystemProvider(logService); fileService.registerProvider(Schemas.file, diskFileSystemProvider); - fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, URI.file(workspaceBackupPath), diskFileSystemProvider, environmentService, logService)); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.userData, logService)); super(environmentService, fileService, logService); diff --git a/src/vs/workbench/services/configuration/browser/configuration.ts b/src/vs/workbench/services/configuration/browser/configuration.ts index 717a91dd1a7de6de2fa9fbd0f837854ccadc671d..973ef52ffc5cb456f7f5654277503815f35c8bdc 100644 --- a/src/vs/workbench/services/configuration/browser/configuration.ts +++ b/src/vs/workbench/services/configuration/browser/configuration.ts @@ -7,7 +7,7 @@ import { URI } from 'vs/base/common/uri'; import * as resources from 'vs/base/common/resources'; import { Event, Emitter } from 'vs/base/common/event'; import * as errors from 'vs/base/common/errors'; -import { Disposable, IDisposable, dispose, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, dispose, toDisposable, MutableDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { RunOnceScheduler } from 'vs/base/common/async'; import { FileChangeType, FileChangesEvent, IFileService, whenProviderRegistered, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; import { ConfigurationModel, ConfigurationModelParser, UserSettings } from 'vs/platform/configuration/common/configurationModels'; @@ -92,6 +92,7 @@ class FileServiceBasedConfiguration extends Disposable { ) { super(); this.allResources = [...this.settingsResources, ...this.standAloneConfigurationResources.map(([, resource]) => resource)]; + this._register(combinedDisposable(...this.allResources.map(resource => this.fileService.watch(resources.dirname(resource))))); this._folderSettingsModelParser = new ConfigurationModelParser(name, this.scopes); this._standAloneConfigurations = []; this._cache = new ConfigurationModel(); diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts index ac1d3153443f5b2c2f2cbb95e81813261ac033cb..637d37c0d44d4e9e6806da2dbeb5a0d997ff58e9 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts @@ -111,7 +111,7 @@ suite('ConfigurationEditingService', () => { const fileService = new FileService(new NullLogService()); const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); fileService.registerProvider(Schemas.file, diskFileSystemProvider); - fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, undefined, diskFileSystemProvider, environmentService, new NullLogService())); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.userData, new NullLogService())); instantiationService.stub(IFileService, fileService); instantiationService.stub(IRemoteAgentService, remoteAgentService); const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService()); diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts index e64febc610b8075dcae74802872e098e3919dcba..931cac2dbc8ac877fe0416768ccc69aff6ca8e08 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts @@ -116,7 +116,7 @@ suite('WorkspaceContextService - Folder', () => { const fileService = new FileService(new NullLogService()); const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); fileService.registerProvider(Schemas.file, diskFileSystemProvider); - fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, undefined, new DiskFileSystemProvider(new NullLogService()), environmentService, new NullLogService())); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService()), Schemas.userData, new NullLogService())); workspaceContextService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, new RemoteAgentService(environmentService, { _serviceBrand: undefined, ...product }, new RemoteAuthorityResolverService(), new SignService(undefined), new NullLogService()), new UriIdentityService(fileService), new NullLogService()); return (workspaceContextService).initialize(convertToWorkspacePayload(URI.file(folderDir))); }); @@ -182,7 +182,7 @@ suite('WorkspaceContextService - Workspace', () => { const fileService = new FileService(new NullLogService()); const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); fileService.registerProvider(Schemas.file, diskFileSystemProvider); - fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, undefined, diskFileSystemProvider, environmentService, new NullLogService())); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.userData, new NullLogService())); const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService()); instantiationService.stub(IWorkspaceContextService, workspaceService); @@ -242,7 +242,7 @@ suite('WorkspaceContextService - Workspace Editing', () => { const fileService = new FileService(new NullLogService()); const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); fileService.registerProvider(Schemas.file, diskFileSystemProvider); - fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, undefined, diskFileSystemProvider, environmentService, new NullLogService())); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.userData, new NullLogService())); const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService()); instantiationService.stub(IWorkspaceContextService, workspaceService); @@ -503,7 +503,7 @@ suite('WorkspaceService - Initialization', () => { const fileService = new FileService(new NullLogService()); const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); fileService.registerProvider(Schemas.file, diskFileSystemProvider); - fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, undefined, diskFileSystemProvider, environmentService, new NullLogService())); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.userData, new NullLogService())); const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService()); instantiationService.stub(IWorkspaceContextService, workspaceService); instantiationService.stub(IConfigurationService, workspaceService); @@ -780,7 +780,7 @@ suite('WorkspaceConfigurationService - Folder', () => { fileService = new FileService(new NullLogService()); const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); fileService.registerProvider(Schemas.file, diskFileSystemProvider); - fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, undefined, diskFileSystemProvider, environmentService, new NullLogService())); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.userData, new NullLogService())); workspaceService = disposableStore.add(new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService())); instantiationService.stub(IWorkspaceContextService, workspaceService); instantiationService.stub(IConfigurationService, workspaceService); @@ -1286,7 +1286,7 @@ suite('WorkspaceConfigurationService-Multiroot', () => { const fileService = new FileService(new NullLogService()); const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); fileService.registerProvider(Schemas.file, diskFileSystemProvider); - fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, undefined, diskFileSystemProvider, environmentService, new NullLogService())); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.userData, new NullLogService())); const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService()); instantiationService.stub(IWorkspaceContextService, workspaceService); @@ -1889,7 +1889,7 @@ suite('WorkspaceConfigurationService - Remote Folder', () => { const remoteAgentService = instantiationService.stub(IRemoteAgentService, >{ getEnvironment: () => remoteEnvironmentPromise }); const fileService = new FileService(new NullLogService()); fileService.registerProvider(Schemas.file, diskFileSystemProvider); - fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, undefined, diskFileSystemProvider, environmentService, new NullLogService())); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.userData, new NullLogService())); const configurationCache: IConfigurationCache = { read: () => Promise.resolve(''), write: () => Promise.resolve(), remove: () => Promise.resolve(), needsCaching: () => false }; testObject = new WorkspaceService({ configurationCache, remoteAuthority }, environmentService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService()); instantiationService.stub(IWorkspaceContextService, testObject); diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index 66eb5445b4e875d3da648886c167432c9c1d0450..909aeac5a8a2e43fe9a65ce18b60a87541b06627 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -49,6 +49,7 @@ import { flatten } from 'vs/base/common/arrays'; import { BrowserFeatures, KeyboardSupport } from 'vs/base/browser/canIUse'; import { ILogService } from 'vs/platform/log/common/log'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { dirname } from 'vs/base/common/resources'; interface ContributedKeyBinding { command: string; @@ -658,6 +659,7 @@ class UserKeybindings extends Disposable { ) { super(); + this._register(fileService.watch(dirname(keybindingsResource))); this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(changed => { if (changed) { this._onDidChange.fire(); diff --git a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts index 44173a02b6beaceaf365c3fddd8c3840657d00a3..352710b85ad47d02706ffd8c84b5dbd568459af3 100644 --- a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts @@ -117,7 +117,7 @@ suite('KeybindingsEditing', () => { const fileService = new FileService(new NullLogService()); const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); fileService.registerProvider(Schemas.file, diskFileSystemProvider); - fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, undefined, diskFileSystemProvider, environmentService, new NullLogService())); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.userData, new NullLogService())); instantiationService.stub(IFileService, fileService); instantiationService.stub(IUriIdentityService, new UriIdentityService(fileService)); instantiationService.stub(IWorkingCopyService, new TestWorkingCopyService()); diff --git a/src/vs/workbench/services/userData/common/fileUserDataProvider.ts b/src/vs/workbench/services/userData/common/fileUserDataProvider.ts index e099b405019c8d214a48459bf3cbd9a9dcb7582e..64e339cd23442e37ab7d5c245367874804f59748 100644 --- a/src/vs/workbench/services/userData/common/fileUserDataProvider.ts +++ b/src/vs/workbench/services/userData/common/fileUserDataProvider.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { Event, Emitter } from 'vs/base/common/event'; -import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IFileSystemProviderWithFileReadWriteCapability, IFileChange, IWatchOptions, IStat, FileOverwriteOptions, FileType, FileWriteOptions, FileDeleteOptions, FileSystemProviderCapabilities, IFileSystemProviderWithOpenReadWriteCloseCapability, FileOpenOptions, hasReadWriteCapability, hasOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadStreamCapability, FileReadStreamOptions, hasFileReadStreamCapability } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ReadableStreamEvents } from 'vs/base/common/stream'; import { ILogService } from 'vs/platform/log/common/log'; import { ExtUri, extUri, extUriIgnorePathCase } from 'vs/base/common/resources'; +import { TernarySearchTree } from 'vs/base/common/map'; export class FileUserDataProvider extends Disposable implements IFileSystemProviderWithFileReadWriteCapability, @@ -24,38 +24,32 @@ export class FileUserDataProvider extends Disposable implements private readonly _onDidChangeFile = this._register(new Emitter()); readonly onDidChangeFile: Event = this._onDidChangeFile.event; - private readonly userDataHome: URI; - private readonly backupHome: URI | undefined; private extUri: ExtUri; + private readonly watchResources = TernarySearchTree.forUris(uri => this.extUri.ignorePathCasing(uri)); + constructor( - /* - Original userdata and backup home locations. Used to - - listen to changes and trigger change events - - Compute UserData URIs from original URIs and vice-versa - */ - private readonly fileSystemUserDataHome: URI, - public fileSystemBackupsHome: URI | undefined, + private readonly fileSystemScheme: string, private readonly fileSystemProvider: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability, - environmentService: IWorkbenchEnvironmentService, + private readonly userDataScheme: string, private readonly logService: ILogService, ) { super(); - this.userDataHome = environmentService.userRoamingDataHome; - this.backupHome = environmentService.backupWorkspaceHome; this.extUri = !!(this.capabilities & FileSystemProviderCapabilities.PathCaseSensitive) ? extUri : extUriIgnorePathCase; // update extUri as capabilites might change. this._register(this.onDidChangeCapabilities(() => this.extUri = !!(this.capabilities & FileSystemProviderCapabilities.PathCaseSensitive) ? extUri : extUriIgnorePathCase)); - - // Assumption: This path always exists - this._register(this.fileSystemProvider.watch(this.fileSystemUserDataHome, { recursive: false, excludes: [] })); this._register(this.fileSystemProvider.onDidChangeFile(e => this.handleFileChanges(e))); } watch(resource: URI, opts: IWatchOptions): IDisposable { - return this.fileSystemProvider.watch(this.toFileSystemResource(resource), opts); + this.watchResources.set(resource, resource); + const disposable = this.fileSystemProvider.watch(this.toFileSystemResource(resource), opts); + return toDisposable(() => { + this.watchResources.delete(resource); + disposable.dispose(); + }); } stat(resource: URI): Promise { @@ -131,7 +125,7 @@ export class FileUserDataProvider extends Disposable implements const userDataChanges: IFileChange[] = []; for (const change of changes) { const userDataResource = this.toUserDataResource(change.resource); - if (userDataResource) { + if (this.watchResources.findSubstr(userDataResource)) { userDataChanges.push({ resource: userDataResource, type: change.type @@ -145,26 +139,11 @@ export class FileUserDataProvider extends Disposable implements } private toFileSystemResource(userDataResource: URI): URI { - // Backup Resource - if (this.backupHome && this.fileSystemBackupsHome && this.extUri.isEqualOrParent(userDataResource, this.backupHome)) { - const relativePath = this.extUri.relativePath(this.backupHome, userDataResource); - return relativePath ? this.extUri.joinPath(this.fileSystemBackupsHome, relativePath) : this.fileSystemBackupsHome; - } - - const relativePath = this.extUri.relativePath(this.userDataHome, userDataResource)!; - return this.extUri.joinPath(this.fileSystemUserDataHome, relativePath); + return userDataResource.with({ scheme: this.fileSystemScheme }); } - private toUserDataResource(fileSystemResource: URI): URI | null { - if (this.extUri.isEqualOrParent(fileSystemResource, this.fileSystemUserDataHome)) { - const relativePath = this.extUri.relativePath(this.fileSystemUserDataHome, fileSystemResource); - return relativePath ? this.extUri.joinPath(this.userDataHome, relativePath) : this.userDataHome; - } - if (this.backupHome && this.fileSystemBackupsHome && this.extUri.isEqualOrParent(fileSystemResource, this.fileSystemBackupsHome)) { - const relativePath = this.extUri.relativePath(this.fileSystemBackupsHome, fileSystemResource); - return relativePath ? this.extUri.joinPath(this.backupHome, relativePath) : this.backupHome; - } - return null; + private toUserDataResource(fileSystemResource: URI): URI { + return fileSystemResource.with({ scheme: this.userDataScheme }); } } diff --git a/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts b/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts index c0f583b948f92ada428b20dd7d71635070ec61d3..c739df8a71620addd7eee7bbe0df1de4dfd76359 100644 --- a/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts +++ b/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts @@ -13,15 +13,15 @@ import { NullLogService } from 'vs/platform/log/common/log'; import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; -import { joinPath, dirname } from 'vs/base/common/resources'; +import { dirname, isEqual, joinPath } from 'vs/base/common/resources'; import { VSBuffer } from 'vs/base/common/buffer'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { DisposableStore, IDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; import { Emitter, Event } from 'vs/base/common/event'; -import { timeout } from 'vs/base/common/async'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { TestProductService } from 'vs/workbench/test/browser/workbenchTestServices'; +import { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; +import { TestWorkbenchConfiguration } from 'vs/workbench/test/electron-browser/workbenchTestServices'; suite('FileUserDataProvider', () => { @@ -43,15 +43,15 @@ suite('FileUserDataProvider', () => { disposables.add(testObject.registerProvider(Schemas.file, diskFileSystemProvider)); const workspaceId = 'workspaceId'; - environmentService = new BrowserWorkbenchEnvironmentService({ remoteAuthority: 'remote', workspaceId, logsPath: URI.file('logFile') }, TestProductService); - rootResource = URI.file(path.join(os.tmpdir(), 'vsctests', uuid.generateUuid())); userDataHomeOnDisk = joinPath(rootResource, 'user'); const backupHome = joinPath(rootResource, 'Backups'); backupWorkspaceHomeOnDisk = joinPath(backupHome, workspaceId); await Promise.all([testObject.createFolder(userDataHomeOnDisk), testObject.createFolder(backupWorkspaceHomeOnDisk)]); - fileUserDataProvider = new FileUserDataProvider(userDataHomeOnDisk, backupWorkspaceHomeOnDisk, diskFileSystemProvider, environmentService, logService); + environmentService = new NativeWorkbenchEnvironmentService({ ...TestWorkbenchConfiguration, 'user-data-dir': rootResource.fsPath, backupPath: backupWorkspaceHomeOnDisk.fsPath }, TestProductService); + + fileUserDataProvider = new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.userData, logService); disposables.add(fileUserDataProvider); disposables.add(testObject.registerProvider(Schemas.userData, fileUserDataProvider)); }); @@ -305,41 +305,29 @@ class TestFileSystemProvider implements IFileSystemProviderWithFileReadWriteCapa suite('FileUserDataProvider - Watching', () => { - let testObject: IFileService; - let localBackupsResource: URI; - let localUserDataResource: URI; - let environmentService: IWorkbenchEnvironmentService; + let testObject: FileUserDataProvider; const disposables = new DisposableStore(); + const rootFileResource = URI.file(path.join(os.tmpdir(), 'vsctests', uuid.generateUuid())); + const rootUserDataResource = rootFileResource.with({ scheme: Schemas.userData }); const fileEventEmitter: Emitter = new Emitter(); disposables.add(fileEventEmitter); setup(() => { - - environmentService = new BrowserWorkbenchEnvironmentService({ remoteAuthority: 'remote', workspaceId: 'workspaceId', logsPath: URI.file('logFile') }, TestProductService); - - const rootResource = URI.file(path.join(os.tmpdir(), 'vsctests', uuid.generateUuid())); - localUserDataResource = joinPath(rootResource, 'user'); - localBackupsResource = joinPath(rootResource, 'Backups'); - - const userDataFileSystemProvider = new FileUserDataProvider(localUserDataResource, localBackupsResource, new TestFileSystemProvider(fileEventEmitter.event), environmentService, new NullLogService()); - disposables.add(userDataFileSystemProvider); - - testObject = new FileService(new NullLogService()); - disposables.add(testObject); - disposables.add(testObject.registerProvider(Schemas.userData, userDataFileSystemProvider)); + testObject = disposables.add(new FileUserDataProvider(Schemas.file, new TestFileSystemProvider(fileEventEmitter.event), Schemas.userData, new NullLogService())); }); teardown(() => disposables.clear()); test('file added change event', done => { - const expected = environmentService.settingsResource; - const target = joinPath(localUserDataResource, 'settings.json'); - testObject.onDidFilesChange(e => { - if (e.contains(expected, FileChangeType.ADDED)) { + disposables.add(testObject.watch(rootUserDataResource, { excludes: [], recursive: false })); + const expected = joinPath(rootUserDataResource, 'settings.json'); + const target = joinPath(rootFileResource, 'settings.json'); + disposables.add(testObject.onDidChangeFile(e => { + if (isEqual(e[0].resource, expected) && e[0].type === FileChangeType.ADDED) { done(); } - }); + })); fileEventEmitter.fire([{ resource: target, type: FileChangeType.ADDED @@ -347,13 +335,14 @@ suite('FileUserDataProvider - Watching', () => { }); test('file updated change event', done => { - const expected = environmentService.settingsResource; - const target = joinPath(localUserDataResource, 'settings.json'); - testObject.onDidFilesChange(e => { - if (e.contains(expected, FileChangeType.UPDATED)) { + disposables.add(testObject.watch(rootUserDataResource, { excludes: [], recursive: false })); + const expected = joinPath(rootUserDataResource, 'settings.json'); + const target = joinPath(rootFileResource, 'settings.json'); + disposables.add(testObject.onDidChangeFile(e => { + if (isEqual(e[0].resource, expected) && e[0].type === FileChangeType.UPDATED) { done(); } - }); + })); fileEventEmitter.fire([{ resource: target, type: FileChangeType.UPDATED @@ -361,13 +350,14 @@ suite('FileUserDataProvider - Watching', () => { }); test('file deleted change event', done => { - const expected = environmentService.settingsResource; - const target = joinPath(localUserDataResource, 'settings.json'); - testObject.onDidFilesChange(e => { - if (e.contains(expected, FileChangeType.DELETED)) { + disposables.add(testObject.watch(rootUserDataResource, { excludes: [], recursive: false })); + const expected = joinPath(rootUserDataResource, 'settings.json'); + const target = joinPath(rootFileResource, 'settings.json'); + disposables.add(testObject.onDidChangeFile(e => { + if (isEqual(e[0].resource, expected) && e[0].type === FileChangeType.DELETED) { done(); } - }); + })); fileEventEmitter.fire([{ resource: target, type: FileChangeType.DELETED @@ -375,13 +365,14 @@ suite('FileUserDataProvider - Watching', () => { }); test('file under folder created change event', done => { - const expected = joinPath(environmentService.snippetsHome, 'settings.json'); - const target = joinPath(localUserDataResource, 'snippets', 'settings.json'); - testObject.onDidFilesChange(e => { - if (e.contains(expected, FileChangeType.ADDED)) { + disposables.add(testObject.watch(rootUserDataResource, { excludes: [], recursive: false })); + const expected = joinPath(rootUserDataResource, 'snippets', 'settings.json'); + const target = joinPath(rootFileResource, 'snippets', 'settings.json'); + disposables.add(testObject.onDidChangeFile(e => { + if (isEqual(e[0].resource, expected) && e[0].type === FileChangeType.ADDED) { done(); } - }); + })); fileEventEmitter.fire([{ resource: target, type: FileChangeType.ADDED @@ -389,13 +380,14 @@ suite('FileUserDataProvider - Watching', () => { }); test('file under folder updated change event', done => { - const expected = joinPath(environmentService.snippetsHome, 'settings.json'); - const target = joinPath(localUserDataResource, 'snippets', 'settings.json'); - testObject.onDidFilesChange(e => { - if (e.contains(expected, FileChangeType.UPDATED)) { + disposables.add(testObject.watch(rootUserDataResource, { excludes: [], recursive: false })); + const expected = joinPath(rootUserDataResource, 'snippets', 'settings.json'); + const target = joinPath(rootFileResource, 'snippets', 'settings.json'); + disposables.add(testObject.onDidChangeFile(e => { + if (isEqual(e[0].resource, expected) && e[0].type === FileChangeType.UPDATED) { done(); } - }); + })); fileEventEmitter.fire([{ resource: target, type: FileChangeType.UPDATED @@ -403,72 +395,45 @@ suite('FileUserDataProvider - Watching', () => { }); test('file under folder deleted change event', done => { - const expected = joinPath(environmentService.snippetsHome, 'settings.json'); - const target = joinPath(localUserDataResource, 'snippets', 'settings.json'); - testObject.onDidFilesChange(e => { - if (e.contains(expected, FileChangeType.DELETED)) { + disposables.add(testObject.watch(rootUserDataResource, { excludes: [], recursive: false })); + const expected = joinPath(rootUserDataResource, 'snippets', 'settings.json'); + const target = joinPath(rootFileResource, 'snippets', 'settings.json'); + disposables.add(testObject.onDidChangeFile(e => { + if (isEqual(e[0].resource, expected) && e[0].type === FileChangeType.DELETED) { done(); } - }); + })); fileEventEmitter.fire([{ resource: target, type: FileChangeType.DELETED }]); }); - test('event is not triggered if file is not under user data', async () => { - const target = joinPath(dirname(localUserDataResource), 'settings.json'); + test('event is not triggered if not watched', async () => { + const target = joinPath(rootFileResource, 'settings.json'); let triggered = false; - testObject.onDidFilesChange(() => triggered = true); + testObject.onDidChangeFile(() => triggered = true); fileEventEmitter.fire([{ resource: target, type: FileChangeType.DELETED }]); - await timeout(0); if (triggered) { assert.fail('event should not be triggered'); } }); - test('backup file created change event', done => { - const expected = joinPath(environmentService.backupWorkspaceHome!, 'settings.json'); - const target = joinPath(localBackupsResource, 'settings.json'); - testObject.onDidFilesChange(e => { - if (e.contains(expected, FileChangeType.ADDED)) { - done(); - } - }); - fileEventEmitter.fire([{ - resource: target, - type: FileChangeType.ADDED - }]); - }); - - test('backup file update change event', done => { - const expected = joinPath(environmentService.backupWorkspaceHome!, 'settings.json'); - const target = joinPath(localBackupsResource, 'settings.json'); - testObject.onDidFilesChange(e => { - if (e.contains(expected, FileChangeType.UPDATED)) { - done(); - } - }); - fileEventEmitter.fire([{ - resource: target, - type: FileChangeType.UPDATED - }]); - }); - - test('backup file delete change event', done => { - const expected = joinPath(environmentService.backupWorkspaceHome!, 'settings.json'); - const target = joinPath(localBackupsResource, 'settings.json'); - testObject.onDidFilesChange(e => { - if (e.contains(expected, FileChangeType.DELETED)) { - done(); - } - }); + test('event is not triggered if not watched 2', async () => { + disposables.add(testObject.watch(rootUserDataResource, { excludes: [], recursive: false })); + const target = joinPath(dirname(rootFileResource), 'settings.json'); + let triggered = false; + testObject.onDidChangeFile(() => triggered = true); fileEventEmitter.fire([{ resource: target, type: FileChangeType.DELETED }]); + if (triggered) { + assert.fail('event should not be triggered'); + } }); + });