diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 61abd4bb8f7..b08da75351f 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -32,8 +32,6 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ILogService, MainLogService } from 'vs/code/electron-main/log'; import { IStorageService, StorageService } from 'vs/code/electron-main/storage'; -import { IBackupService } from 'vs/platform/backup/common/backup'; -import { BackupService } from 'vs/platform/backup/node/backupService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -257,11 +255,11 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo // Open our first window if (environmentService.args['new-window'] && environmentService.args._.length === 0) { - windowsService.open({ cli: environmentService.args, forceNewWindow: true, forceEmpty: true, restoreBackups: true }); // new window if "-n" was used without paths + windowsService.open({ cli: environmentService.args, forceNewWindow: true, forceEmpty: true }); // new window if "-n" was used without paths } else if (global.macOpenFiles && global.macOpenFiles.length && (!environmentService.args._ || !environmentService.args._.length)) { - windowsService.open({ cli: environmentService.args, pathsToOpen: global.macOpenFiles, restoreBackups: true }); // mac: open-file event received on startup + windowsService.open({ cli: environmentService.args, pathsToOpen: global.macOpenFiles }); // mac: open-file event received on startup } else { - windowsService.open({ cli: environmentService.args, forceNewWindow: environmentService.args['new-window'], diffMode: environmentService.args.diff, restoreBackups: true }); // default: read paths from cli + windowsService.open({ cli: environmentService.args, forceNewWindow: environmentService.args['new-window'], diffMode: environmentService.args.diff }); // default: read paths from cli } } @@ -476,7 +474,6 @@ function start(): void { services.set(IConfigurationService, new SyncDescriptor(ConfigurationService)); services.set(IRequestService, new SyncDescriptor(RequestService)); services.set(IUpdateService, new SyncDescriptor(UpdateManager)); - services.set(IBackupService, new SyncDescriptor(BackupService)); services.set(IURLService, new SyncDescriptor(URLService, args['open-url'])); const instantiationService = new InstantiationService(services); diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index aabf064105f..bac9eb6334a 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -15,7 +15,6 @@ import * as types from 'vs/base/common/types'; import * as arrays from 'vs/base/common/arrays'; import { assign, mixin } from 'vs/base/common/objects'; import { EventEmitter } from 'events'; -import { IBackupService } from 'vs/platform/backup/common/backup'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IStorageService } from 'vs/code/electron-main/storage'; import { IPath, VSCodeWindow, ReadyState, IWindowConfiguration, IWindowState as ISingleWindowState, defaultWindowState, IWindowSettings } from 'vs/code/electron-main/window'; @@ -29,7 +28,6 @@ import { IWindowEventService } from 'vs/code/common/windows'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import CommonEvent, { Emitter } from 'vs/base/common/event'; import product from 'vs/platform/product'; -import Uri from 'vs/base/common/uri'; import { ParsedArgs } from 'vs/platform/environment/node/argv'; const EventTypes = { @@ -52,7 +50,6 @@ export interface IOpenConfiguration { forceEmpty?: boolean; windowToUse?: VSCodeWindow; diffMode?: boolean; - restoreBackups?: boolean; } interface IWindowState { @@ -170,8 +167,7 @@ export class WindowsManager implements IWindowsService { @IEnvironmentService private environmentService: IEnvironmentService, @ILifecycleService private lifecycleService: ILifecycleService, @IUpdateService private updateService: IUpdateService, - @IConfigurationService private configurationService: IConfigurationService, - @IBackupService private backupService: IBackupService + @IConfigurationService private configurationService: IConfigurationService ) { } onOpen(clb: (path: IPath) => void): () => void { @@ -639,20 +635,6 @@ export class WindowsManager implements IWindowsService { iPathsToOpen = this.cliToPaths(openConfig.cli, ignoreFileNotFound); } - // Add any existing backup workspaces - if (openConfig.restoreBackups) { - this.backupService.getWorkspaceBackupPathsSync().forEach(ws => { - iPathsToOpen.push(this.toIPath(ws)); - }); - // Get rid of duplicates - iPathsToOpen = arrays.distinct(iPathsToOpen, path => { - if (!('workspacePath' in path)) { - return path.workspacePath; - } - return platform.isLinux ? path.workspacePath : path.workspacePath.toLowerCase(); - }); - } - let filesToOpen: IPath[] = []; let filesToDiff: IPath[] = []; let foldersToOpen = iPathsToOpen.filter(iPath => iPath.workspacePath && !iPath.filePath); @@ -781,11 +763,6 @@ export class WindowsManager implements IWindowsService { // Emit events iPathsToOpen.forEach(iPath => this.eventEmitter.emit(EventTypes.OPEN, iPath)); - // Start tracking workspace backups - this.backupService.pushWorkspaceBackupPathsSync(iPathsToOpen.filter(path => 'workspacePath' in path).map(path => { - return Uri.file(path.workspacePath); - })); - return arrays.distinct(usedWindows); } diff --git a/src/vs/platform/backup/common/backup.ts b/src/vs/platform/backup/common/backup.ts deleted file mode 100644 index fe55e941793..00000000000 --- a/src/vs/platform/backup/common/backup.ts +++ /dev/null @@ -1,83 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -import Uri from 'vs/base/common/uri'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { TPromise } from 'vs/base/common/winjs.base'; - -export const IBackupService = createDecorator('backupService'); - -export interface IBackupService { - _serviceBrand: any; - - /** - * Gets the set of active workspace backup paths being tracked for restoration. - * - * @return The set of active workspace backup paths being tracked for restoration. - */ - getWorkspaceBackupPaths(): TPromise; - - /** - * Gets the set of active workspace backup paths being tracked for restoration. - * - * @return The set of active workspace backup paths being tracked for restoration. - */ - getWorkspaceBackupPathsSync(): string[]; - - /** - * Pushes workspace backup paths to be tracked for restoration. - * - * @param workspaces The workspaces to add. - */ - pushWorkspaceBackupPathsSync(workspaces: Uri[]): void; - - /** - * Removes a workspace backup path being tracked for restoration, deregistering all associated - * resources for backup. - * - * @param workspace The absolute workspace path being removed. - */ - removeWorkspaceBackupPath(workspace: Uri): TPromise; - - /** - * Gets the set of text files that are backed up for a particular workspace. - * - * @param workspace The workspace to get the backed up files for. - * @return The absolute paths for text files _that have backups_. - */ - getWorkspaceTextFilesWithBackupsSync(workspace: Uri): string[]; - - /** - * Gets the set of untitled file backups for a particular workspace. - * - * @param workspace The workspace to get the backups for for. - * @return The absolute paths for all the untitled file _backups_. - */ - getWorkspaceUntitledFileBackupsSync(workspace: Uri): string[]; - - /** - * Registers a resource for backup, flagging it for restoration. - * - * @param resource The resource that is being backed up. - */ - registerResourceForBackup(resource: Uri): TPromise; - - /** - * Deregisters a resource for backup, unflagging it for restoration. - * - * @param resource The resource that is no longer being backed up. - */ - deregisterResourceForBackup(resource: Uri): TPromise; - - /** - * Gets the backup resource for a particular resource within the current workspace. - * - * @param resource The resource that is backed up. - * @return The backup resource. - */ - getBackupResource(resource: Uri): Uri; -} diff --git a/src/vs/platform/backup/node/backupService.ts b/src/vs/platform/backup/node/backupService.ts deleted file mode 100644 index 599672754ee..00000000000 --- a/src/vs/platform/backup/node/backupService.ts +++ /dev/null @@ -1,222 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -import * as path from 'path'; -import * as crypto from 'crypto'; -import * as arrays from 'vs/base/common/arrays'; -import fs = require('fs'); -import pfs = require('vs/base/node/pfs'); -import Uri from 'vs/base/common/uri'; -import { IBackupService } from 'vs/platform/backup/common/backup'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { TPromise } from 'vs/base/common/winjs.base'; - -interface IBackupFormat { - folderWorkspaces?: { - [workspacePath: string]: string[] - }; -} - -export class BackupService implements IBackupService { - - public _serviceBrand: any; - - private workspaceResource: Uri; - private fileContent: IBackupFormat; - private backupHome: string; - private backupWorkspacesPath: string; - - constructor( - @IEnvironmentService environmentService: IEnvironmentService - ) { - this.backupHome = environmentService.backupHome; - this.backupWorkspacesPath = environmentService.backupWorkspacesPath; - } - - public setCurrentWorkspace(resource: Uri): void { - this.workspaceResource = resource; - } - - /** - * Due to the Environment service not being initialized when it's needed on the main thread - * side, this is here so that tests can override the paths pulled from it. - */ - public setBackupPathsForTest(backupHome: string, backupWorkspacesPath: string) { - this.backupHome = backupHome; - this.backupWorkspacesPath = backupWorkspacesPath; - } - - public getWorkspaceBackupPaths(): TPromise { - return this.load().then(() => { - return Object.keys(this.fileContent.folderWorkspaces); - }); - } - - public getWorkspaceBackupPathsSync(): string[] { - this.loadSync(); - return Object.keys(this.fileContent.folderWorkspaces); - } - - public pushWorkspaceBackupPathsSync(workspaces: Uri[]): void { - // Only allow this on the main thread in the window initialization's critical path due to - // the usage of synchronous IO. - if (this.workspaceResource) { - throw new Error('pushWorkspaceBackupPaths should only be called on the main process'); - } - - this.loadSync(); - workspaces.forEach(workspace => { - // Hot exit is disabled for empty workspaces - if (!workspace) { - return; - } - - if (!this.fileContent.folderWorkspaces[workspace.fsPath]) { - this.fileContent.folderWorkspaces[workspace.fsPath] = []; - } - }); - this.saveSync(); - } - - public removeWorkspaceBackupPath(workspace: Uri): TPromise { - return this.load().then(() => { - if (!this.fileContent.folderWorkspaces) { - return TPromise.as(void 0); - } - delete this.fileContent.folderWorkspaces[workspace.fsPath]; - return this.save(); - }); - } - - public getWorkspaceTextFilesWithBackupsSync(workspace: Uri): string[] { - // Allow sync here as it's only used in workbench initialization's critical path - this.loadSync(); - return this.fileContent.folderWorkspaces[workspace.fsPath] || []; - } - - public getWorkspaceUntitledFileBackupsSync(workspace: Uri): string[] { - // Hot exit is disabled for empty workspaces - if (!this.workspaceResource) { - return []; - } - - const workspaceHash = crypto.createHash('md5').update(workspace.fsPath).digest('hex'); - const untitledDir = path.join(this.backupHome, workspaceHash, 'untitled'); - - // Allow sync here as it's only used in workbench initialization's critical path - try { - return fs.readdirSync(untitledDir).map(file => path.join(untitledDir, file)); - } catch (ex) { - return []; - } - } - - public getBackupResource(resource: Uri): Uri { - // Hot exit is disabled for empty workspaces - if (!this.workspaceResource) { - return null; - } - - const workspaceHash = crypto.createHash('md5').update(this.workspaceResource.fsPath).digest('hex'); - const backupName = crypto.createHash('md5').update(resource.fsPath).digest('hex'); - const backupPath = path.join(this.backupHome, workspaceHash, resource.scheme, backupName); - return Uri.file(backupPath); - } - - public registerResourceForBackup(resource: Uri): TPromise { - // Hot exit is disabled for empty workspaces - if (!this.workspaceResource) { - return TPromise.as(void 0); - } - - return this.load().then(() => { - if (!(this.workspaceResource.fsPath in this.fileContent.folderWorkspaces)) { - this.fileContent.folderWorkspaces[this.workspaceResource.fsPath] = []; - } - if (arrays.contains(this.fileContent.folderWorkspaces[this.workspaceResource.fsPath], resource.fsPath)) { - return TPromise.as(void 0); - } - this.fileContent.folderWorkspaces[this.workspaceResource.fsPath].push(resource.fsPath); - return this.save(); - }); - } - - public deregisterResourceForBackup(resource: Uri): TPromise { - // Hot exit is disabled for empty workspaces - if (!this.workspaceResource) { - return TPromise.as(void 0); - } - - return this.load().then(() => { - const workspace = this.fileContent.folderWorkspaces[this.workspaceResource.fsPath]; - if (workspace) { - this.fileContent.folderWorkspaces[this.workspaceResource.fsPath] = workspace.filter(value => value !== resource.fsPath); - return this.save(); - } - return TPromise.as(void 0); - }); - } - - private load(): TPromise { - return pfs.fileExists(this.backupWorkspacesPath).then(exists => { - if (!exists) { - this.fileContent = { - folderWorkspaces: Object.create(null) - }; - return TPromise.as(void 0); - } - - return pfs.readFile(this.backupWorkspacesPath, 'utf8').then(content => { - try { - return JSON.parse(content.toString()); - } catch (ex) { - return Object.create(null); - } - }).then(content => { - this.fileContent = content; - if (!this.fileContent.folderWorkspaces) { - this.fileContent.folderWorkspaces = Object.create(null); - } - return TPromise.as(void 0); - }); - }); - } - - private loadSync(): void { - if (fs.existsSync(this.backupWorkspacesPath)) { - try { - this.fileContent = JSON.parse(fs.readFileSync(this.backupWorkspacesPath, 'utf8').toString()); // invalid JSON or permission issue can happen here - } catch (error) { - this.fileContent = Object.create(null); - } - } else { - this.fileContent = Object.create(null); - } - - if (!this.fileContent.folderWorkspaces) { - this.fileContent.folderWorkspaces = Object.create(null); - } - } - - private save(): TPromise { - const data = JSON.stringify(this.fileContent); - return pfs.mkdirp(this.backupHome).then(() => { - return pfs.writeFile(this.backupWorkspacesPath, data); - }); - } - - private saveSync(): void { - try { - // The user data directory must exist so only the Backup directory needs to be checked. - if (!fs.existsSync(this.backupHome)) { - fs.mkdirSync(this.backupHome); - } - fs.writeFileSync(this.backupWorkspacesPath, JSON.stringify(this.fileContent)); - } catch (ex) { - } - } -} \ No newline at end of file diff --git a/src/vs/platform/backup/test/backupService.test.ts b/src/vs/platform/backup/test/backupService.test.ts deleted file mode 100644 index 66321ddda6d..00000000000 --- a/src/vs/platform/backup/test/backupService.test.ts +++ /dev/null @@ -1,175 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -import * as assert from 'assert'; -import * as platform from 'vs/base/common/platform'; -import crypto = require('crypto'); -import os = require('os'); -import path = require('path'); -import extfs = require('vs/base/node/extfs'); -import pfs = require('vs/base/node/pfs'); -import Uri from 'vs/base/common/uri'; -import { nfcall } from 'vs/base/common/async'; -import { TestEnvironmentService } from 'vs/test/utils/servicesTestUtils'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { BackupService } from 'vs/platform/backup/node/backupService'; - -suite('BackupService', () => { - const parentDir = path.join(os.tmpdir(), 'vsctests', 'service') - const backupHome = path.join(parentDir, 'Backups'); - const backupWorkspacesHome = path.join(backupHome, 'workspaces.json'); - - const fooFile = Uri.file(platform.isWindows ? 'C:\\foo' : '/foo'); - const barFile = Uri.file(platform.isWindows ? 'C:\\bar' : '/bar'); - const bazFile = Uri.file(platform.isWindows ? 'C:\\baz' : '/baz'); - - let backupService: BackupService; - - setup(done => { - const environmentService = TestEnvironmentService; - - backupService = new BackupService(environmentService); - backupService.setBackupPathsForTest(backupHome, backupWorkspacesHome); - - // Delete any existing backups completely and then re-create it. - extfs.del(backupHome, os.tmpdir(), () => { - pfs.mkdirp(backupHome).then(() => { - pfs.writeFileAndFlush(backupWorkspacesHome, '').then(() => { - done(); - }); - }); - }); - }); - - teardown(done => { - extfs.del(backupHome, os.tmpdir(), done); - }); - - test('pushWorkspaceBackupPathsSync should persist paths to workspaces.json', () => { - backupService.pushWorkspaceBackupPathsSync([fooFile, barFile]); - assert.deepEqual(backupService.getWorkspaceBackupPathsSync(), [fooFile.fsPath, barFile.fsPath]); - }); - - test('pushWorkspaceBackupPathsSync should throw if a workspace is set', () => { - backupService.setCurrentWorkspace(fooFile); - assert.throws(() => backupService.pushWorkspaceBackupPathsSync([fooFile])); - }); - - test('removeWorkspaceBackupPath should remove workspaces from workspaces.json', done => { - backupService.pushWorkspaceBackupPathsSync([fooFile, barFile]); - assert.deepEqual(backupService.getWorkspaceBackupPathsSync(), [fooFile.fsPath, barFile.fsPath]); - backupService.removeWorkspaceBackupPath(fooFile).then(() => { - assert.deepEqual(backupService.getWorkspaceBackupPathsSync(), [barFile.fsPath]); - backupService.removeWorkspaceBackupPath(barFile).then(() => { - assert.deepEqual(backupService.getWorkspaceBackupPathsSync(), []); - done(); - }); - }); - }); - - test('removeWorkspaceBackupPath should fail gracefully when removing a path that doesn\'t exist', done => { - backupService.pushWorkspaceBackupPathsSync([fooFile]); - assert.deepEqual(backupService.getWorkspaceBackupPathsSync(), [fooFile.fsPath]); - backupService.removeWorkspaceBackupPath(barFile).then(() => { - assert.deepEqual(backupService.getWorkspaceBackupPathsSync(), [fooFile.fsPath]); - done(); - }); - }); - - test('registerResourceForBackup should register backups to workspaces.json', done => { - backupService.setCurrentWorkspace(fooFile); - backupService.registerResourceForBackup(barFile).then(() => { - assert.deepEqual(backupService.getWorkspaceTextFilesWithBackupsSync(fooFile), [barFile.fsPath]); - done(); - }); - }); - - test('deregisterResourceForBackup should deregister backups from workspaces.json', done => { - backupService.setCurrentWorkspace(fooFile); - backupService.registerResourceForBackup(barFile).then(() => { - assert.deepEqual(backupService.getWorkspaceTextFilesWithBackupsSync(fooFile), [barFile.fsPath]); - backupService.deregisterResourceForBackup(barFile).then(() => { - assert.deepEqual(backupService.getWorkspaceTextFilesWithBackupsSync(fooFile), []); - done(); - }); - }); - }); - - test('getBackupResource should get the correct backup path for text files', () => { - // Format should be: /// - const workspaceResource = fooFile; - backupService.setCurrentWorkspace(workspaceResource); - const backupResource = barFile; - const workspaceHash = crypto.createHash('md5').update(workspaceResource.fsPath).digest('hex'); - const filePathHash = crypto.createHash('md5').update(backupResource.fsPath).digest('hex'); - const expectedPath = Uri.file(path.join(backupHome, workspaceHash, 'file', filePathHash)).fsPath; - assert.equal(backupService.getBackupResource(backupResource).fsPath, expectedPath); - }); - - test('getBackupResource should get the correct backup path for untitled files', () => { - // Format should be: /// - const workspaceResource = barFile; - backupService.setCurrentWorkspace(workspaceResource); - const backupResource = Uri.from({ scheme: 'untitled' }); - const workspaceHash = crypto.createHash('md5').update(workspaceResource.fsPath).digest('hex'); - const filePathHash = crypto.createHash('md5').update(backupResource.fsPath).digest('hex'); - const expectedPath = Uri.file(path.join(backupHome, workspaceHash, 'untitled', filePathHash)).fsPath; - assert.equal(backupService.getBackupResource(backupResource).fsPath, expectedPath); - }); - - test('getBackupResource should get the correct backup path for text files', () => { - // Format should be: /// - const workspaceResource = fooFile; - backupService.setCurrentWorkspace(workspaceResource); - const backupResource = barFile; - const workspaceHash = crypto.createHash('md5').update(workspaceResource.fsPath).digest('hex'); - const filePathHash = crypto.createHash('md5').update(backupResource.fsPath).digest('hex'); - const expectedPath = Uri.file(path.join(backupHome, workspaceHash, 'file', filePathHash)).fsPath; - assert.equal(backupService.getBackupResource(backupResource).fsPath, expectedPath); - }); - - test('getBackupResource should get the correct backup path for untitled files', () => { - // Format should be: /// - const workspaceResource = fooFile; - backupService.setCurrentWorkspace(workspaceResource); - const backupResource = Uri.from({ scheme: 'untitled' }); - const workspaceHash = crypto.createHash('md5').update(workspaceResource.fsPath).digest('hex'); - const filePathHash = crypto.createHash('md5').update(backupResource.fsPath).digest('hex'); - const expectedPath = Uri.file(path.join(backupHome, workspaceHash, 'untitled', filePathHash)).fsPath; - assert.equal(backupService.getBackupResource(backupResource).fsPath, expectedPath); - }); - - test('getWorkspaceTextFilesWithBackupsSync should return text file resources that have backups', done => { - const workspaceResource = fooFile; - backupService.setCurrentWorkspace(workspaceResource); - backupService.registerResourceForBackup(barFile).then(() => { - assert.deepEqual(backupService.getWorkspaceTextFilesWithBackupsSync(workspaceResource), [barFile.fsPath]); - backupService.registerResourceForBackup(bazFile).then(() => { - assert.deepEqual(backupService.getWorkspaceTextFilesWithBackupsSync(workspaceResource), [barFile.fsPath, bazFile.fsPath]); - done(); - }); - }); - }); - - test('getWorkspaceUntitledFileBackupsSync should return untitled file backup resources', done => { - const workspaceResource = fooFile; - backupService.setCurrentWorkspace(workspaceResource); - const workspaceHash = crypto.createHash('md5').update(workspaceResource.fsPath).digest('hex'); - const untitledBackupDir = path.join(backupHome, workspaceHash, 'untitled'); - const untitledBackup1 = path.join(untitledBackupDir, 'bar'); - const untitledBackup2 = path.join(untitledBackupDir, 'foo'); - pfs.mkdirp(untitledBackupDir).then(() => { - pfs.writeFile(untitledBackup1, 'test').then(() => { - assert.deepEqual(backupService.getWorkspaceUntitledFileBackupsSync(workspaceResource), [untitledBackup1]); - pfs.writeFile(untitledBackup2, 'test').then(() => { - assert.deepEqual(backupService.getWorkspaceUntitledFileBackupsSync(workspaceResource), [untitledBackup1, untitledBackup2]); - done(); - }); - }); - }); - }); -}); \ No newline at end of file diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 7cc3288d9e0..23998095f4f 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -23,9 +23,6 @@ export interface IEnvironmentService { appSettingsPath: string; appKeybindingsPath: string; - backupHome: string; - backupWorkspacesPath: string; - disableExtensions: boolean; extensionsPath: string; extensionDevelopmentPath: string; diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index cd24af86de3..51ccedd29da 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -76,12 +76,6 @@ export class EnvironmentService implements IEnvironmentService { @memoize get appKeybindingsPath(): string { return path.join(this.appSettingsHome, 'keybindings.json'); } - @memoize - get backupHome(): string { return path.join(this.userDataPath, 'Backups'); } - - @memoize - get backupWorkspacesPath(): string { return path.join(this.backupHome, 'workspaces.json'); } - @memoize get extensionsPath(): string { return path.normalize(this._args.extensionHomePath || path.join(this.userHome, 'extensions')); } diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index e9b05d227d3..dfa97b21361 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -104,27 +104,6 @@ export interface IFileService { */ del(resource: URI, useTrash?: boolean): TPromise; - /** - * Backs up the provided file to a temporary directory to be used by the hot - * exit feature and crash recovery. - */ - backupFile(resource: URI, content: string): TPromise; - - /** - * Discard the backup for the resource specified. - */ - discardBackup(resource: URI): TPromise; - - /** - * Discards all backups associated with this session. - */ - discardBackups(): TPromise; - - /** - * Whether hot exit is enabled. - */ - isHotExitEnabled(): boolean; - /** * Imports the file to the parent identified by the resource. */ @@ -496,7 +475,6 @@ export interface IFilesConfiguration { autoSave: string; autoSaveDelay: number; eol: string; - hotExit: boolean; }; } diff --git a/src/vs/test/utils/servicesTestUtils.ts b/src/vs/test/utils/servicesTestUtils.ts index 6abec2786c2..e89daabe93c 100644 --- a/src/vs/test/utils/servicesTestUtils.ts +++ b/src/vs/test/utils/servicesTestUtils.ts @@ -17,7 +17,6 @@ import { Storage, InMemoryLocalStorage } from 'vs/workbench/common/storage'; import { IEditorGroup, ConfirmResult } from 'vs/workbench/common/editor'; import Event, { Emitter } from 'vs/base/common/event'; import Severity from 'vs/base/common/severity'; -import { IBackupService } from 'vs/platform/backup/common/backup'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; @@ -112,10 +111,9 @@ export class TestTextFileService extends TextFileService { @IEditorGroupService editorGroupService: IEditorGroupService, @IFileService fileService: IFileService, @IUntitledEditorService untitledEditorService: IUntitledEditorService, - @IInstantiationService instantiationService: IInstantiationService, - @IBackupService backupService: IBackupService + @IInstantiationService instantiationService: IInstantiationService ) { - super(lifecycleService, contextService, configurationService, telemetryService, editorGroupService, editorService, fileService, untitledEditorService, instantiationService, backupService); + super(lifecycleService, contextService, configurationService, telemetryService, editorGroupService, editorService, fileService, untitledEditorService, instantiationService); } public setPromptPath(path: string): void { @@ -176,7 +174,6 @@ export function workbenchInstantiationService(): IInstantiationService { instantiationService.stub(IHistoryService, 'getHistory', []); instantiationService.stub(IModelService, createMockModelService(instantiationService)); instantiationService.stub(IFileService, TestFileService); - instantiationService.stub(IBackupService, new TestBackupService()); instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(IMessageService, new TestMessageService()); instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService)); @@ -573,68 +570,6 @@ export const TestFileService = { name: paths.basename(res.fsPath) }; }); - }, - - backupFile: function (resource: URI, content: string) { - return TPromise.as(void 0); - }, - - discardBackup: function (resource: URI) { - return TPromise.as(void 0); - }, - - discardBackups: function () { - return TPromise.as(void 0); - }, - - isHotExitEnabled: function () { - return false; - } -}; - -export class TestBackupService implements IBackupService { - public _serviceBrand: any; - - // Lists used for verification in tests - public registeredResources: URI[] = []; - public deregisteredResources: URI[] = []; - - public getWorkspaceBackupPaths(): TPromise { - return TPromise.as([]); - } - - public getWorkspaceBackupPathsSync(): string[] { - return []; - } - - public pushWorkspaceBackupPathsSync(workspaces: URI[]): void { - return null; - } - - public removeWorkspaceBackupPath(workspace: URI): TPromise { - return TPromise.as(void 0); - } - - public getWorkspaceTextFilesWithBackupsSync(workspace: URI): string[] { - return []; - } - - public getWorkspaceUntitledFileBackupsSync(workspace: URI): string[] { - return []; - } - - public registerResourceForBackup(resource: URI): TPromise { - this.registeredResources.push(resource); - return TPromise.as(void 0); - } - - public deregisterResourceForBackup(resource: URI): TPromise { - this.deregisteredResources.push(resource); - return TPromise.as(void 0); - } - - public getBackupResource(resource: URI): URI { - return null; } }; diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 0213f07caec..caec780459b 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -319,11 +319,6 @@ export interface IFileEditorInput extends IEditorInput, IEncodingSupport { */ setResource(resource: URI): void; - /** - * Sets whether to restore the resource from backup. - */ - setRestoreFromBackup(restore: boolean): void; - /** * Sets the preferred encodingt to use for this input. */ diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index 32dd24729e6..7761d5135a5 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -28,7 +28,6 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput { public static SCHEMA: string = 'untitled'; private resource: URI; - private restoreResource: URI; private hasAssociatedFilePath: boolean; private modeId: string; private cachedModel: UntitledEditorModel; @@ -47,6 +46,7 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput { @ITextFileService private textFileService: ITextFileService ) { super(); + this.resource = resource; this.hasAssociatedFilePath = hasAssociatedFilePath; this.modeId = modeId; @@ -66,10 +66,6 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput { return this.resource; } - public setRestoreResource(resource: URI): void { - this.restoreResource = resource; - } - public getName(): string { return this.hasAssociatedFilePath ? paths.basename(this.resource.fsPath) : this.resource.fsPath; } @@ -134,25 +130,17 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput { return TPromise.as(this.cachedModel); } - // Otherwise Create Model and load, restoring from backup if necessary - let restorePromise: TPromise; - if (this.restoreResource) { - restorePromise = this.textFileService.resolveTextContent(this.restoreResource).then(rawTextContent => rawTextContent.value.lines.join('\n')); - } else { - restorePromise = TPromise.as(''); - } + // Otherwise Create Model and load + const model = this.createModel(); + return model.load().then((resolvedModel: UntitledEditorModel) => { + this.cachedModel = resolvedModel; - return restorePromise.then(content => { - const model = this.createModel(content); - return model.load().then((resolvedModel: UntitledEditorModel) => { - this.cachedModel = resolvedModel; - - return this.cachedModel; - }); + return this.cachedModel; }); } - private createModel(content: string): UntitledEditorModel { + private createModel(): UntitledEditorModel { + const content = ''; const model = this.instantiationService.createInstance(UntitledEditorModel, content, this.modeId, this.resource, this.hasAssociatedFilePath); // re-emit some events from the model diff --git a/src/vs/workbench/common/editor/untitledEditorModel.ts b/src/vs/workbench/common/editor/untitledEditorModel.ts index d524c67f4a3..ee8d1203866 100644 --- a/src/vs/workbench/common/editor/untitledEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledEditorModel.ts @@ -11,7 +11,7 @@ import { StringEditorModel } from 'vs/workbench/common/editor/stringEditorModel' import URI from 'vs/base/common/uri'; import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import { EndOfLinePreference } from 'vs/editor/common/editorCommon'; -import { IFileService, IFilesConfiguration } from 'vs/platform/files/common/files'; +import { IFilesConfiguration } from 'vs/platform/files/common/files'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -31,8 +31,6 @@ export class UntitledEditorModel extends StringEditorModel implements IEncodingS private hasAssociatedFilePath: boolean; - private backupPromises: TPromise[]; - constructor( value: string, modeId: string, @@ -40,19 +38,16 @@ export class UntitledEditorModel extends StringEditorModel implements IEncodingS hasAssociatedFilePath: boolean, @IModeService modeService: IModeService, @IModelService modelService: IModelService, - @IFileService private fileService: IFileService, @IConfigurationService private configurationService: IConfigurationService ) { super(value, modeId, resource, modeService, modelService); this.hasAssociatedFilePath = hasAssociatedFilePath; - this.dirty = hasAssociatedFilePath || value !== ''; // untitled associated to file path are dirty right away + this.dirty = hasAssociatedFilePath; // untitled associated to file path are dirty right away this._onDidChangeDirty = new Emitter(); this._onDidChangeEncoding = new Emitter(); - this.backupPromises = []; - this.registerListeners(); } @@ -116,10 +111,6 @@ export class UntitledEditorModel extends StringEditorModel implements IEncodingS return this.dirty; } - public getResource(): URI { - return this.resource; - } - public revert(): void { this.dirty = false; @@ -162,15 +153,6 @@ export class UntitledEditorModel extends StringEditorModel implements IEncodingS else if (!this.dirty) { this.dirty = true; this._onDidChangeDirty.fire(); - - } - - if (this.fileService.isHotExitEnabled()) { - if (this.dirty) { - this.doBackup(); - } else { - this.fileService.discardBackup(this.resource); - } } } @@ -189,36 +171,5 @@ export class UntitledEditorModel extends StringEditorModel implements IEncodingS this._onDidChangeDirty.dispose(); this._onDidChangeEncoding.dispose(); - - this.cancelBackupPromises(); - this.fileService.discardBackup(this.resource); - } - - public backup(): TPromise { - return this.doBackup(true); - } - - private doBackup(immediate?: boolean): TPromise { - // Cancel any currently running backups to make this the one that succeeds - this.cancelBackupPromises(); - - if (immediate) { - return this.fileService.backupFile(this.resource, this.getValue()).then(f => void 0); - } - - // Create new backup promise and keep it - const promise = TPromise.timeout(1000).then(() => { - this.fileService.backupFile(this.resource, this.getValue()); // Very important here to not return the promise because if the timeout promise is canceled it will bubble up the error otherwise - do not change - }); - - this.backupPromises.push(promise); - - return promise; - } - - private cancelBackupPromises(): void { - while (this.backupPromises.length) { - this.backupPromises.pop().cancel(); - } } } \ No newline at end of file diff --git a/src/vs/workbench/common/options.ts b/src/vs/workbench/common/options.ts index ce341d575d3..a78e4ccd992 100644 --- a/src/vs/workbench/common/options.ts +++ b/src/vs/workbench/common/options.ts @@ -22,7 +22,4 @@ export interface IOptions { * Instructs the workbench to open a diff of the provided files right after startup. */ filesToDiff?: IResourceInput[]; - - filesToRestore?: IResourceInput[]; - untitledFilesToRestore?: IResourceInput[]; } \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 12bc0e6b256..d845f24475c 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -20,8 +20,6 @@ import product from 'vs/platform/product'; import pkg from 'vs/platform/package'; import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService'; import timer = require('vs/base/common/timer'); -import { BackupService } from 'vs/platform/backup/node/backupService'; -import { IBackupService } from 'vs/platform/backup/common/backup'; import { Workbench } from 'vs/workbench/electron-browser/workbench'; import { Storage, inMemoryLocalStorageInstance } from 'vs/workbench/common/storage'; import { ITelemetryService, NullTelemetryService, loadExperiments } from 'vs/platform/telemetry/common/telemetry'; @@ -245,11 +243,6 @@ export class WorkbenchShell { }); }, errors.onUnexpectedError); - // Backup - const backupService = instantiationService.createInstance(BackupService); - backupService.setCurrentWorkspace(this.contextService.getWorkspace() ? this.contextService.getWorkspace().resource : null); - serviceCollection.set(IBackupService, backupService); - // Storage const disableWorkspaceStorage = this.environmentService.extensionTestsPath || (!this.workspace && !this.environmentService.extensionDevelopmentPath); // without workspace or in any extension test, we use inMemory storage unless we develop an extension where we want to preserve state this.storageService = instantiationService.createInstance(Storage, window.localStorage, disableWorkspaceStorage ? inMemoryLocalStorageInstance : window.localStorage); diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index e998c3b1ded..5d1ce169a7e 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -16,8 +16,6 @@ import { Delayer } from 'vs/base/common/async'; import assert = require('vs/base/common/assert'); import timer = require('vs/base/common/timer'); import errors = require('vs/base/common/errors'); -import Uri from 'vs/base/common/uri'; -import { IBackupService } from 'vs/platform/backup/common/backup'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Registry } from 'vs/platform/platform'; import { isWindows, isLinux } from 'vs/base/common/platform'; @@ -162,8 +160,7 @@ export class Workbench implements IPartService { @IMessageService private messageService: IMessageService, @IConfigurationService private configurationService: IConfigurationService, @ITelemetryService private telemetryService: ITelemetryService, - @IEnvironmentService private environmentService: IEnvironmentService, - @IBackupService private backupService: IBackupService + @IEnvironmentService private environmentService: IEnvironmentService ) { this.container = container; @@ -173,22 +170,7 @@ export class Workbench implements IPartService { serviceCollection }; - // Restore any backups if they exist for this workspace (empty workspaces are not supported yet) - if (workspace) { - options.filesToRestore = this.backupService.getWorkspaceTextFilesWithBackupsSync(workspace.resource).map(filePath => { - return { resource: Uri.file(filePath), options: { pinned: true } }; - }); - options.untitledFilesToRestore = this.backupService.getWorkspaceUntitledFileBackupsSync(workspace.resource).map(untitledFilePath => { - return { resource: Uri.file(untitledFilePath), options: { pinned: true } }; - }); - } - - this.hasFilesToCreateOpenOrDiff = - (options.filesToCreate && options.filesToCreate.length > 0) || - (options.filesToOpen && options.filesToOpen.length > 0) || - (options.filesToDiff && options.filesToDiff.length > 0) || - (options.filesToRestore && options.filesToRestore.length > 0) || - (options.untitledFilesToRestore && options.untitledFilesToRestore.length > 0); + this.hasFilesToCreateOpenOrDiff = (options.filesToCreate && options.filesToCreate.length > 0) || (options.filesToOpen && options.filesToOpen.length > 0) || (options.filesToDiff && options.filesToDiff.length > 0); this.toDispose = []; this.toShutdown = []; @@ -315,8 +297,6 @@ export class Workbench implements IPartService { const wbopt = this.workbenchParams.options; const filesToCreate = wbopt.filesToCreate || []; const filesToOpen = wbopt.filesToOpen || []; - const filesToRestore = wbopt.filesToRestore || []; - const untitledFilesToRestore = wbopt.untitledFilesToRestore || []; const filesToDiff = wbopt.filesToDiff; // Files to diff is exclusive @@ -335,17 +315,10 @@ export class Workbench implements IPartService { inputs.push(...filesToCreate.map(resourceInput => this.untitledEditorService.createOrGet(resourceInput.resource))); options.push(...filesToCreate.map(r => null)); // fill empty options for files to create because we dont have options there - // Files to restore - inputs.push(...untitledFilesToRestore.map(resourceInput => this.untitledEditorService.createOrGet(null, null, resourceInput.resource))); - options.push(...untitledFilesToRestore.map(r => null)); // fill empty options for files to create because we dont have options there - // Files to open - let filesToOpenInputPromise = filesToOpen.map(resourceInput => this.editorService.createInput(resourceInput)); - let filesToRestoreInputPromise = filesToRestore.map(resourceInput => this.editorService.createInput(resourceInput, true)); - - return TPromise.join(filesToOpenInputPromise.concat(filesToRestoreInputPromise)).then((inputsToOpen) => { + return TPromise.join(filesToOpen.map(resourceInput => this.editorService.createInput(resourceInput))).then((inputsToOpen) => { inputs.push(...inputsToOpen); - options.push(...filesToOpen.concat(filesToRestore).map(resourceInput => TextEditorOptions.from(resourceInput))); + options.push(...filesToOpen.map(resourceInput => TextEditorOptions.from(resourceInput))); return inputs.map((input, index) => { return { input, options: options[index] }; }); }); diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index ffedf848498..b750e467a74 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -213,12 +213,6 @@ configurationRegistry.registerConfiguration({ 'default': (platform.isLinux || platform.isMacintosh) ? { '**/.git/objects/**': true, '**/node_modules/**': true } : { '**/.git/objects/**': true }, 'description': nls.localize('watcherExclude', "Configure glob patterns of file paths to exclude from file watching. Changing this setting requires a restart. When you experience Code consuming lots of cpu time on startup, you can exclude large folders to reduce the initial load.") }, - 'files.hotExit': { - 'type': 'boolean', - // TODO: Switch to true once sufficiently stable - 'default': false, - 'description': nls.localize('hotExit', "Controls whether unsaved files are restored after relaunching. If this is enabled there will be no prompt to save when exiting the editor.") - }, 'editor.formatOnSave': { 'type': 'boolean', 'default': false, diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts index 36dc6c1ef61..4a3c9782aec 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts @@ -16,7 +16,6 @@ import { ITextFileService, AutoSaveMode, ModelState, TextFileModelChangeEvent, L import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IEventService } from 'vs/platform/event/common/event'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IBackupService } from 'vs/platform/backup/common/backup'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; @@ -27,7 +26,6 @@ export class FileEditorInput extends CommonFileEditorInput { private resource: URI; private preferredEncoding: string; private forceOpenAsBinary: boolean; - private restoreFromBackup: boolean; private name: string; private description: string; @@ -45,8 +43,7 @@ export class FileEditorInput extends CommonFileEditorInput { @IWorkspaceContextService private contextService: IWorkspaceContextService, @IHistoryService private historyService: IHistoryService, @IEventService private eventService: IEventService, - @ITextFileService private textFileService: ITextFileService, - @IBackupService private backupService: IBackupService + @ITextFileService private textFileService: ITextFileService ) { super(); @@ -105,10 +102,6 @@ export class FileEditorInput extends CommonFileEditorInput { this.verboseDescription = null; } - public setRestoreFromBackup(restore: boolean): void { - this.restoreFromBackup = restore; - } - public getResource(): URI { return this.resource; } @@ -202,8 +195,7 @@ export class FileEditorInput extends CommonFileEditorInput { } public resolve(refresh?: boolean): TPromise { - const backupResource = this.restoreFromBackup ? this.backupService.getBackupResource(this.resource) : null; - return this.textFileService.models.loadOrCreate(this.resource, this.preferredEncoding, refresh, backupResource).then(null, error => { + return this.textFileService.models.loadOrCreate(this.resource, this.preferredEncoding, refresh).then(null, error => { // In case of an error that indicates that the file is binary or too large, just return with the binary editor model if ((error).fileOperationResult === FileOperationResult.FILE_IS_BINARY || (error).fileOperationResult === FileOperationResult.FILE_TOO_LARGE) { diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index 6daf31d6b2a..4d4e2a57d19 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -42,8 +42,6 @@ export abstract class FileEditorInput extends EditorInput implements IFileEditor public abstract setResource(resource: URI): void; - public abstract setRestoreFromBackup(restore: boolean): void; - public abstract getResource(): URI; public abstract setPreferredEncoding(encoding: string): void; diff --git a/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts index 5ef7628a4cb..219ef322dd3 100644 --- a/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts @@ -33,7 +33,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IBackupService } from 'vs/platform/backup/common/backup'; class SettingsTestEnvironmentService extends EnvironmentService { @@ -56,10 +55,9 @@ class TestDirtyTextFileService extends TestTextFileService { @IEditorGroupService editorGroupService: IEditorGroupService, @IFileService fileService: IFileService, @IUntitledEditorService untitledEditorService: IUntitledEditorService, - @IInstantiationService instantiationService: IInstantiationService, - @IBackupService backupService: IBackupService + @IInstantiationService instantiationService: IInstantiationService ) { - super(lifecycleService, contextService, configurationService, telemetryService, editorService, editorGroupService, fileService, untitledEditorService, instantiationService, backupService); + super(lifecycleService, contextService, configurationService, telemetryService, editorService, editorGroupService, fileService, untitledEditorService, instantiationService); } public isDirty(resource?: URI): boolean { @@ -87,7 +85,7 @@ suite('WorkspaceConfigurationEditingService - Node', () => { const configurationService = new WorkspaceConfigurationService(workspaceContextService, new TestEventService(), environmentService); const textFileService = workbenchInstantiationService().createInstance(TestDirtyTextFileService, dirty); const events = new utils.TestEventService(); - const fileService = new FileService(noWorkspace ? null : workspaceDir, { disableWatcher: true }, events, environmentService, configurationService, null); + const fileService = new FileService(noWorkspace ? null : workspaceDir, { disableWatcher: true }, events); return configurationService.initialize().then(() => { return { diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 1b7831c9908..589ec7f00d0 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -208,8 +208,8 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { } public createInput(input: EditorInput): TPromise; - public createInput(input: IResourceInput, restoreFromBackup?: boolean): TPromise; - public createInput(input: any, restoreFromBackup?: boolean): TPromise { + public createInput(input: IResourceInput): TPromise; + public createInput(input: any): TPromise { // Workbench Input Support if (input instanceof EditorInput) { @@ -263,7 +263,7 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { // Base Text Editor Support for file resources else if (this.fileInputDescriptor && resourceInput.resource instanceof URI && resourceInput.resource.scheme === network.Schemas.file) { - return this.createFileInput(resourceInput.resource, resourceInput.encoding, restoreFromBackup); + return this.createFileInput(resourceInput.resource, resourceInput.encoding); } // Treat an URI as ResourceEditorInput @@ -277,11 +277,10 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { return TPromise.as(null); } - private createFileInput(resource: URI, encoding?: string, restoreFromBackup?: boolean): TPromise { + private createFileInput(resource: URI, encoding?: string): TPromise { return this.instantiationService.createInstance(this.fileInputDescriptor).then((typedFileInput) => { typedFileInput.setResource(resource); typedFileInput.setPreferredEncoding(encoding); - typedFileInput.setRestoreFromBackup(restoreFromBackup); return typedFileInput; }); diff --git a/src/vs/workbench/services/files/electron-browser/fileService.ts b/src/vs/workbench/services/files/electron-browser/fileService.ts index e9d2e319a03..36e56861636 100644 --- a/src/vs/workbench/services/files/electron-browser/fileService.ts +++ b/src/vs/workbench/services/files/electron-browser/fileService.ts @@ -26,7 +26,6 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IBackupService } from 'vs/platform/backup/common/backup'; import { shell } from 'electron'; @@ -48,12 +47,11 @@ export class FileService implements IFileService { @IEventService private eventService: IEventService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IEnvironmentService private environmentService: IEnvironmentService, + @IEnvironmentService environmentService: IEnvironmentService, @IEditorGroupService private editorGroupService: IEditorGroupService, @ILifecycleService private lifecycleService: ILifecycleService, @IMessageService private messageService: IMessageService, - @IStorageService private storageService: IStorageService, - @IBackupService private backupService: IBackupService + @IStorageService private storageService: IStorageService ) { this.toUnbind = []; this.activeOutOfWorkspaceWatchers = Object.create(null); @@ -83,7 +81,7 @@ export class FileService implements IFileService { // create service const workspace = this.contextService.getWorkspace(); - this.raw = new NodeFileService(workspace ? workspace.resource.fsPath : void 0, fileServiceConfig, this.eventService, this.environmentService, this.configurationService, this.backupService); + this.raw = new NodeFileService(workspace ? workspace.resource.fsPath : void 0, fileServiceConfig, this.eventService); // Listeners this.registerListeners(); @@ -243,22 +241,6 @@ export class FileService implements IFileService { return this.raw.del(resource); } - public backupFile(resource: uri, content: string): TPromise { - return this.raw.backupFile(resource, content); - } - - public discardBackup(resource: uri): TPromise { - return this.raw.discardBackup(resource); - } - - public discardBackups(): TPromise { - return this.raw.discardBackups(); - } - - public isHotExitEnabled(): boolean { - return this.raw.isHotExitEnabled(); - } - private doMoveItemToTrash(resource: uri): TPromise { const workspace = this.contextService.getWorkspace(); if (!workspace) { diff --git a/src/vs/workbench/services/files/node/fileService.ts b/src/vs/workbench/services/files/node/fileService.ts index 4c0e8a68fa6..738ce04a72c 100644 --- a/src/vs/workbench/services/files/node/fileService.ts +++ b/src/vs/workbench/services/files/node/fileService.ts @@ -28,15 +28,10 @@ import pfs = require('vs/base/node/pfs'); import encoding = require('vs/base/node/encoding'); import mime = require('vs/base/node/mime'); import flow = require('vs/base/node/flow'); -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { FileWatcher as UnixWatcherService } from 'vs/workbench/services/files/node/watcher/unix/watcherService'; import { FileWatcher as WindowsWatcherService } from 'vs/workbench/services/files/node/watcher/win32/watcherService'; import { toFileChangesEvent, normalize, IRawFileChange } from 'vs/workbench/services/files/node/watcher/common'; import { IEventService } from 'vs/platform/event/common/event'; -import { IBackupService } from 'vs/platform/backup/common/backup'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IFilesConfiguration } from 'vs/platform/files/common/files'; export interface IEncodingOverride { resource: uri; @@ -77,7 +72,6 @@ export class FileService implements IFileService { private static FS_EVENT_DELAY = 50; // aggregate and only emit events when changes have stopped for this duration (in ms) private static MAX_DEGREE_OF_PARALLEL_FS_OPS = 10; // degree of parallel fs calls that we accept at the same time - private toUnbind: IDisposable[]; private basePath: string; private tmpPath: string; private options: IFileServiceOptions; @@ -88,16 +82,7 @@ export class FileService implements IFileService { private fileChangesWatchDelayer: ThrottledDelayer; private undeliveredRawFileChangesEvents: IRawFileChange[]; - private configuredHotExit: boolean; - - constructor( - basePath: string, - options: IFileServiceOptions, - private eventEmitter: IEventService, - private environmentService: IEnvironmentService, - private configurationService: IConfigurationService, - private backupService: IBackupService - ) { + constructor(basePath: string, options: IFileServiceOptions, private eventEmitter: IEventService) { this.basePath = basePath ? paths.normalize(basePath) : void 0; if (this.basePath && this.basePath.indexOf('\\\\') === 0 && strings.endsWith(this.basePath, paths.sep)) { @@ -130,19 +115,6 @@ export class FileService implements IFileService { this.activeFileChangesWatchers = Object.create(null); this.fileChangesWatchDelayer = new ThrottledDelayer(FileService.FS_EVENT_DELAY); this.undeliveredRawFileChangesEvents = []; - - // Configuration changes - this.toUnbind = []; - if (this.configurationService) { - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(e.config))); - - const configuration = this.configurationService.getConfiguration(); - this.onConfigurationChange(configuration); - } - } - - private onConfigurationChange(configuration: IFilesConfiguration): void { - this.configuredHotExit = configuration && configuration.files && configuration.files.hotExit; } public updateOptions(options: IFileServiceOptions): void { @@ -455,76 +427,8 @@ export class FileService implements IFileService { return nfcall(extfs.del, absolutePath, this.tmpPath); } - public backupFile(resource: uri, content: string): TPromise { - let registerResourcePromise: TPromise; - if (resource.scheme === 'file') { - registerResourcePromise = this.backupService.registerResourceForBackup(resource); - } else { - registerResourcePromise = TPromise.as(void 0); - } - return registerResourcePromise.then(() => { - const backupResource = this.getBackupPath(resource); - - // Hot exit is disabled for empty workspaces - if (!backupResource) { - return TPromise.as(null); - } - - return this.updateContent(backupResource, content); - }); - } - - public discardBackup(resource: uri): TPromise { - return this.backupService.deregisterResourceForBackup(resource).then(() => { - const backupResource = this.getBackupPath(resource); - - // Hot exit is disabled for empty workspaces - if (!backupResource) { - return TPromise.as(null); - } - - return this.del(backupResource); - }); - } - - public discardBackups(): TPromise { - // Hot exit is disabled for empty workspaces - const backupRootPath = this.getBackupRootPath(); - if (!backupRootPath) { - return TPromise.as(void 0); - } - - return this.del(uri.file(backupRootPath)); - } - - public isHotExitEnabled(): boolean { - return this.configuredHotExit; - } - // Helpers - private getBackupPath(resource: uri): uri { - // Hot exit is disabled for empty workspaces - const backupRootPath = this.getBackupRootPath(); - if (!backupRootPath) { - return null; - } - - const backupName = crypto.createHash('md5').update(resource.fsPath).digest('hex'); - const backupPath = paths.join(backupRootPath, resource.scheme, backupName); - return uri.file(backupPath); - } - - private getBackupRootPath(): string { - // Hot exit is disabled for empty workspaces - if (!this.basePath) { - return null; - } - - const workspaceHash = crypto.createHash('md5').update(this.basePath).digest('hex'); - return paths.join(this.environmentService.userDataPath, 'Backups', workspaceHash); - } - private toAbsolutePath(arg1: uri | IFileStat): string { let resource: uri; if (arg1 instanceof uri) { @@ -760,8 +664,6 @@ export class FileService implements IFileService { watcher.close(); } this.activeFileChangesWatchers = Object.create(null); - - this.toUnbind = dispose(this.toUnbind); } } diff --git a/src/vs/workbench/services/files/test/node/fileService.test.ts b/src/vs/workbench/services/files/test/node/fileService.test.ts index 262577c417c..69bc17f5f90 100644 --- a/src/vs/workbench/services/files/test/node/fileService.test.ts +++ b/src/vs/workbench/services/files/test/node/fileService.test.ts @@ -9,14 +9,11 @@ import fs = require('fs'); import path = require('path'); import os = require('os'); import assert = require('assert'); -import crypto = require('crypto'); import { TPromise } from 'vs/base/common/winjs.base'; import { FileService, IEncodingOverride } from 'vs/workbench/services/files/node/fileService'; import { EventType, FileChangesEvent, FileOperationResult, IFileOperationResult } from 'vs/platform/files/common/files'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { nfcall } from 'vs/base/common/async'; -import { TestBackupService, TestEnvironmentService } from 'vs/test/utils/servicesTestUtils'; import uri from 'vs/base/common/uri'; import uuid = require('vs/base/common/uuid'); import extfs = require('vs/base/node/extfs'); @@ -36,7 +33,7 @@ suite('FileService', () => { extfs.copy(sourceDir, testDir, () => { events = new utils.TestEventService(); - service = new FileService(testDir, { disableWatcher: true }, events, null, null, null); + service = new FileService(testDir, { disableWatcher: true }, events); done(); }); }); @@ -278,107 +275,6 @@ suite('FileService', () => { }); }); - suite('backups', () => { - const environment = TestEnvironmentService; - const fooResource = uri.file('/foo'); - const barResource = uri.file('/bar'); - const untitledResource = uri.from({ scheme: 'untitled' }); - - let _service: FileService; - let backup: TestBackupService; - let workspaceHash; - let workspaceBackupRoot; - let fooBackupPath; - let barBackupPath; - let untitledBackupPath; - - setup((done) => { - extfs.del(TestEnvironmentService.backupHome, os.tmpdir(), done); - backup = new TestBackupService(); - _service = new FileService(testDir, { disableWatcher: true }, events, environment, null, backup); - workspaceHash = crypto.createHash('md5').update(testDir).digest('hex'); - workspaceBackupRoot = path.join(environment.backupHome, workspaceHash); - const fooFileHash = crypto.createHash('md5').update(fooResource.fsPath).digest('hex'); - const barFileHash = crypto.createHash('md5').update(barResource.fsPath).digest('hex'); - const untitledFileHash = crypto.createHash('md5').update(untitledResource.fsPath).digest('hex'); - fooBackupPath = path.join(workspaceBackupRoot, 'file', fooFileHash); - barBackupPath = path.join(workspaceBackupRoot, 'file', barFileHash); - untitledBackupPath = path.join(workspaceBackupRoot, 'untitled', untitledFileHash); - }); - - teardown((done) => { - extfs.del(TestEnvironmentService.backupHome, os.tmpdir(), done); - }); - - test('backupFile - text file', function (done: () => void) { - _service.backupFile(fooResource, 'test').then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupRoot, 'file')).length, 1); - assert.equal(fs.existsSync(fooBackupPath), true); - assert.deepEqual(backup.registeredResources, [fooResource]); - assert.equal(fs.readFileSync(fooBackupPath), 'test'); - done(); - }); - }); - - test('backupFile - untitled file', function (done: () => void) { - _service.backupFile(untitledResource, 'test').then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupRoot, 'untitled')).length, 1); - assert.equal(fs.existsSync(untitledBackupPath), true); - // Untitled files are not registered to workspaces.json as they do not have paths - assert.equal(fs.readFileSync(untitledBackupPath), 'test'); - done(); - }); - }); - - test('discardBackup - text file', function (done: () => void) { - _service.backupFile(fooResource, 'test').then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupRoot, 'file')).length, 1); - _service.discardBackup(fooResource).then(() => { - assert.equal(fs.existsSync(fooBackupPath), false); - assert.equal(fs.readdirSync(path.join(workspaceBackupRoot, 'file')).length, 0); - done(); - }); - }); - }); - - test('discardBackup - untitled file', function (done: () => void) { - _service.backupFile(untitledResource, 'test').then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupRoot, 'untitled')).length, 1); - _service.discardBackup(untitledResource).then(() => { - assert.equal(fs.existsSync(untitledBackupPath), false); - assert.equal(fs.readdirSync(path.join(workspaceBackupRoot, 'untitled')).length, 0); - done(); - }); - }); - }); - - test('discardBackups - text file', function (done: () => void) { - _service.backupFile(fooResource, 'test').then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupRoot, 'file')).length, 1); - _service.backupFile(barResource, 'test').then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupRoot, 'file')).length, 2); - _service.discardBackups().then(() => { - assert.equal(fs.existsSync(fooBackupPath), false); - assert.equal(fs.existsSync(barBackupPath), false); - assert.equal(fs.existsSync(path.join(workspaceBackupRoot, 'file')), false); - done(); - }); - }); - }); - }); - - test('discardBackups - untitled file', function (done: () => void) { - _service.backupFile(untitledResource, 'test').then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupRoot, 'untitled')).length, 1); - _service.discardBackups().then(() => { - assert.equal(fs.existsSync(untitledBackupPath), false); - assert.equal(fs.existsSync(path.join(workspaceBackupRoot, 'untitled')), false); - done(); - }); - }); - }); - }); - test('resolveFile', function (done: () => void) { service.resolveFile(uri.file(testDir), { resolveTo: [uri.file(path.join(testDir, 'deep'))] }).done(r => { assert.equal(r.children.length, 6); @@ -598,7 +494,7 @@ suite('FileService', () => { encoding: 'windows1252', encodingOverride: encodingOverride, disableWatcher: true - }, null, null, null, null); + }, null); _service.resolveContent(uri.file(path.join(testDir, 'index.html'))).done(c => { assert.equal(c.encoding, 'windows1252'); @@ -624,7 +520,7 @@ suite('FileService', () => { let _service = new FileService(_testDir, { disableWatcher: true - }, null, null, null, null); + }, null); extfs.copy(_sourceDir, _testDir, () => { fs.readFile(resource.fsPath, (error, data) => { diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index 55c40224f38..d8195b636e8 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import * as platform from 'vs/base/common/platform'; import { TPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; import paths = require('vs/base/common/paths'); @@ -27,7 +26,6 @@ import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorMo import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IBackupService } from 'vs/platform/backup/common/backup'; /** * The workbench file service implementation implements the raw file service spec and adds additional methods on top. @@ -44,8 +42,6 @@ export abstract class TextFileService implements ITextFileService { private _onFilesAssociationChange: Emitter; private currentFilesAssociationConfig: { [key: string]: string; }; - private configuredHotExit: boolean; - private _onAutoSaveConfigurationChange: Emitter; private configuredAutoSaveDelay: number; private configuredAutoSaveOnFocusChange: boolean; @@ -60,8 +56,7 @@ export abstract class TextFileService implements ITextFileService { @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IFileService protected fileService: IFileService, @IUntitledEditorService private untitledEditorService: IUntitledEditorService, - @IInstantiationService private instantiationService: IInstantiationService, - @IBackupService private backupService: IBackupService + @IInstantiationService private instantiationService: IInstantiationService ) { this.toUnbind = []; @@ -117,33 +112,10 @@ export abstract class TextFileService implements ITextFileService { } private beforeShutdown(): boolean | TPromise { - // If hot exit is enabled then save the dirty files in the workspace and then exit - // Hot exit is currently disabled for both empty workspaces (#13733) and on Mac (#13305) - if (this.configuredHotExit && this.contextService.getWorkspace() && !platform.isMacintosh) { - // If there are no dirty files, clean up and exit - if (this.getDirty().length === 0) { - return this.cleanupBackupsBeforeShutdown(); - } - - return this.backupService.getWorkspaceBackupPaths().then(workspaceBackupPaths => { - // Only remove the workspace from the backup service if it's not the last one or it's not dirty - if (workspaceBackupPaths.length > 1) { - return this.confirmBeforeShutdown(); - } - - // Backup and hot exit - return this.backupAll().then(result => { - if (result.results.some(r => !r.success)) { - return true; // veto if some backups failed - } - - return false; // the backup went smoothly, no veto - }); - }); - } // Dirty files need treatment on shutdown if (this.getDirty().length) { + // If auto save is enabled, save all files and then check again for dirty files if (this.getAutoSaveMode() !== AutoSaveMode.OFF) { return this.saveAll(false /* files only */).then(() => { @@ -151,9 +123,7 @@ export abstract class TextFileService implements ITextFileService { return this.confirmBeforeShutdown(); // we still have dirty files around, so confirm normally } - return this.fileService.discardBackups().then(() => { - return false; // all good, no veto - }); + return false; // all good, no veto }); } @@ -161,9 +131,7 @@ export abstract class TextFileService implements ITextFileService { return this.confirmBeforeShutdown(); } - return this.fileService.discardBackups().then(() => { - return false; // no veto - }); + return false; // no veto } private confirmBeforeShutdown(): boolean | TPromise { @@ -176,13 +144,13 @@ export abstract class TextFileService implements ITextFileService { return true; // veto if some saves failed } - return this.cleanupBackupsBeforeShutdown(); + return false; // no veto }); } // Don't Save else if (confirm === ConfirmResult.DONT_SAVE) { - return this.cleanupBackupsBeforeShutdown(); + return false; // no veto } // Cancel @@ -191,18 +159,6 @@ export abstract class TextFileService implements ITextFileService { } } - private cleanupBackupsBeforeShutdown(): boolean | TPromise { - const workspace = this.contextService.getWorkspace(); - if (!workspace) { - return false; // no backups to cleanup, no eto - } - return this.backupService.removeWorkspaceBackupPath(workspace.resource).then(() => { - return this.fileService.discardBackups().then(() => { - return false; // no veto - }); - }); - } - private onWindowFocusLost(): void { if (this.configuredAutoSaveOnWindowChange && this.isDirty()) { this.saveAll(void 0, SaveReason.WINDOW_CHANGE).done(null, errors.onUnexpectedError); @@ -253,9 +209,6 @@ export abstract class TextFileService implements ITextFileService { this.saveAll().done(null, errors.onUnexpectedError); } - // Hot exit is disabled for empty workspaces - this.configuredHotExit = this.contextService.getWorkspace() && configuration && configuration.files && configuration.files.hotExit; - // Check for change in files associations const filesAssociation = configuration && configuration.files && configuration.files.associations; if (!objects.equals(this.currentFilesAssociationConfig, filesAssociation)) { @@ -405,66 +358,6 @@ export abstract class TextFileService implements ITextFileService { }); } - /** - * Performs an immedate backup of all dirty file and untitled models. - */ - private backupAll(): TPromise { - const toBackup = this.getDirty(); - - // split up between files and untitled - const filesToBackup: URI[] = []; - const untitledToBackup: URI[] = []; - toBackup.forEach(s => { - if (s.scheme === 'file') { - filesToBackup.push(s); - } else if (s.scheme === 'untitled') { - untitledToBackup.push(s); - } - }); - - return this.doBackupAll(filesToBackup, untitledToBackup); - } - - private doBackupAll(fileResources: URI[], untitledResources: URI[]): TPromise { - // Handle file resources first - const dirtyFileModels = this.getDirtyFileModels(fileResources); - - const mapResourceToResult: { [resource: string]: IResult } = Object.create(null); - dirtyFileModels.forEach(m => { - mapResourceToResult[m.getResource().toString()] = { - source: m.getResource() - }; - }); - - return TPromise.join(dirtyFileModels.map(model => { - return model.backup().then(() => { - mapResourceToResult[model.getResource().toString()].success = true; - }); - })).then(results => { - // Handle untitled resources - const untitledModelPromises = untitledResources.map(untitledResource => this.untitledEditorService.get(untitledResource)) - .filter(untitled => !!untitled) - .map(untitled => untitled.resolve()); - - return TPromise.join(untitledModelPromises).then(untitledModels => { - const untitledBackupPromises = untitledModels.map(model => { - mapResourceToResult[model.getResource().toString()] = { - source: model.getResource(), - target: model.getResource() - }; - return model.backup().then(() => { - mapResourceToResult[model.getResource().toString()].success = true; - }); - }); - return TPromise.join(untitledBackupPromises).then(() => { - return { - results: Object.keys(mapResourceToResult).map(k => mapResourceToResult[k]) - }; - }); - }); - }); - } - private getFileModels(resources?: URI[]): ITextFileEditorModel[]; private getFileModels(resource?: URI): ITextFileEditorModel[]; private getFileModels(arg1?: any): ITextFileEditorModel[] { @@ -627,14 +520,6 @@ export abstract class TextFileService implements ITextFileService { }); } - public backup(resource: URI): void { - let model = this.getDirtyFileModels(resource); - if (!model || model.length === 0) { - return; - } - this.fileService.backupFile(resource, model[0].getValue()); - } - public getAutoSaveMode(): AutoSaveMode { if (this.configuredAutoSaveOnFocusChange) { return AutoSaveMode.ON_FOCUS_CHANGE; diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index e215ddea72d..2a30db14498 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -40,7 +40,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private static saveParticipant: ISaveParticipant; private resource: URI; - private restoreResource: URI; private contentEncoding: string; // encoding as reported from disk private preferredEncoding: string; // encoding as chosen by the user private dirty: boolean; @@ -52,7 +51,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private autoSaveAfterMillies: number; private autoSaveAfterMilliesEnabled: boolean; private autoSavePromises: TPromise[]; - private backupPromises: TPromise[]; private mapPendingSaveToVersionId: { [versionId: string]: TPromise }; private disposed: boolean; private inConflictResolutionMode: boolean; @@ -84,7 +82,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.preferredEncoding = preferredEncoding; this.dirty = false; this.autoSavePromises = []; - this.backupPromises = []; this.versionId = 0; this.lastSaveAttemptTime = 0; this.mapPendingSaveToVersionId = {}; @@ -183,10 +180,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil }); } - public setRestoreResource(resource: URI): void { - this.restoreResource = resource; - } - public load(force?: boolean /* bypass any caches and really go to disk */): TPromise { diag('load() - enter', this.resource, new Date()); @@ -264,35 +257,18 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil else { diag('load() - created text editor model', this.resource, new Date()); - if (this.restoreResource) { - this.createTextEditorModelPromise = this.textFileService.resolveTextContent(this.restoreResource, { acceptTextOnly: true, etag: etag, encoding: this.preferredEncoding }).then((restoreContent) => { - return this.createTextEditorModel(restoreContent.value, content.resource).then(() => { - this.createTextEditorModelPromise = null; + this.createTextEditorModelPromise = this.createTextEditorModel(content.value, content.resource).then(() => { + this.createTextEditorModelPromise = null; - this.setDirty(true); - this.toDispose.push(this.textEditorModel.onDidChangeRawContent((e: IModelContentChangedEvent) => this.onModelContentChanged(e))); + this.setDirty(false); // Ensure we are not tracking a stale state + this.toDispose.push(this.textEditorModel.onDidChangeRawContent((e: IModelContentChangedEvent) => this.onModelContentChanged(e))); - return this; - }, (error) => { - this.createTextEditorModelPromise = null; + return this; + }, (error) => { + this.createTextEditorModelPromise = null; - return TPromise.wrapError(error); - }); - }); - } else { - this.createTextEditorModelPromise = this.createTextEditorModel(content.value, content.resource).then(() => { - this.createTextEditorModelPromise = null; - - this.setDirty(false); // Ensure we are not tracking a stale state - this.toDispose.push(this.textEditorModel.onDidChangeRawContent((e: IModelContentChangedEvent) => this.onModelContentChanged(e))); - - return this; - }, (error) => { - this.createTextEditorModelPromise = null; - - return TPromise.wrapError(error); - }); - } + return TPromise.wrapError(error); + }); return this.createTextEditorModelPromise; } @@ -342,10 +318,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this._onDidStateChange.fire(StateChange.REVERTED); } - if (this.fileService.isHotExitEnabled()) { - this.fileService.discardBackup(this.resource); - } - return; } @@ -362,10 +334,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil diag('makeDirty() - prevented save because we are in conflict resolution mode', this.resource, new Date()); } } - - if (this.fileService.isHotExitEnabled()) { - this.doBackup(); - } } private makeDirty(): void { @@ -406,38 +374,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } } - public backup(): TPromise { - if (!this.dirty) { - return TPromise.as(null); - } - - return this.doBackup(true); - } - - private doBackup(immediate?: boolean): TPromise { - // Cancel any currently running backups to make this the one that succeeds - this.cancelBackupPromises(); - - if (immediate) { - return this.fileService.backupFile(this.resource, this.getValue()).then(f => void 0); - } - - // Create new backup promise and keep it - const promise = TPromise.timeout(1000).then(() => { - this.fileService.backupFile(this.resource, this.getValue()); // Very important here to not return the promise because if the timeout promise is canceled it will bubble up the error otherwise - do not change - }); - - this.backupPromises.push(promise); - - return promise; - } - - private cancelBackupPromises(): void { - while (this.backupPromises.length) { - this.backupPromises.pop().cancel(); - } - } - /** * Saves the current versionId of this editor model if it is dirty. */ @@ -786,9 +722,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.createTextEditorModelPromise = null; this.cancelAutoSavePromises(); - this.cancelBackupPromises(); - - this.fileService.discardBackup(this.resource); super.dispose(); } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts index 615570f4a22..605772ca838 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts @@ -171,7 +171,7 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager { return this.mapResourceToModel[resource.toString()]; } - public loadOrCreate(resource: URI, encoding: string, refresh?: boolean, restoreResource?: URI): TPromise { + public loadOrCreate(resource: URI, encoding: string, refresh?: boolean): TPromise { // Return early if model is currently being loaded const pendingLoad = this.mapResourceToPendingModelLoaders[resource.toString()]; @@ -194,9 +194,6 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager { // Model does not exist else { model = this.instantiationService.createInstance(TextFileEditorModel, resource, encoding); - if (restoreResource) { - model.setRestoreResource(restoreResource); - } modelPromise = model.load(); // Install state change listener diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index a033f7813e7..52389b16b68 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -192,7 +192,7 @@ export interface ITextFileEditorModelManager { getAll(resource?: URI): ITextFileEditorModel[]; - loadOrCreate(resource: URI, preferredEncoding: string, refresh?: boolean, restoreResource?: URI): TPromise; + loadOrCreate(resource: URI, preferredEncoding: string, refresh?: boolean): TPromise; } export interface IModelSaveOptions { @@ -217,10 +217,6 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport save(options?: IModelSaveOptions): TPromise; - backup(): TPromise; - - setRestoreResource(resource: URI): void; - revert(): TPromise; setConflictResolutionMode(); @@ -322,14 +318,6 @@ export interface ITextFileService extends IDisposable { */ confirmSave(resources?: URI[]): ConfirmResult; - /** - * Backs up the provided file to a temporary directory to be used by the hot - * exit feature and crash recovery. - * - * @param resource The resource to backup. - */ - backup(resource: URI): void; - /** * Convinient fast access to the current auto save mode. */ diff --git a/src/vs/workbench/services/textfile/electron-browser/textFileService.ts b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts index 7f5adb06600..f71a2929e06 100644 --- a/src/vs/workbench/services/textfile/electron-browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts @@ -27,7 +27,6 @@ import { IEditorGroupService } from 'vs/workbench/services/group/common/groupSer import { IModelService } from 'vs/editor/common/services/modelService'; import { ModelBuilder } from 'vs/editor/node/model/modelBuilder'; import product from 'vs/platform/product'; -import { IBackupService } from 'vs/platform/backup/common/backup'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -43,7 +42,6 @@ export class TextFileService extends AbstractTextFileService { @IInstantiationService instantiationService: IInstantiationService, @ITelemetryService telemetryService: ITelemetryService, @IConfigurationService configurationService: IConfigurationService, - @IBackupService backupService: IBackupService, @IModeService private modeService: IModeService, @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IEditorGroupService editorGroupService: IEditorGroupService, @@ -51,7 +49,7 @@ export class TextFileService extends AbstractTextFileService { @IModelService private modelService: IModelService, @IEnvironmentService private environmentService: IEnvironmentService ) { - super(lifecycleService, contextService, configurationService, telemetryService, editorGroupService, editorService, fileService, untitledEditorService, instantiationService, backupService); + super(lifecycleService, contextService, configurationService, telemetryService, editorGroupService, editorService, fileService, untitledEditorService, instantiationService); } public resolveTextContent(resource: URI, options?: IResolveContentOptions): TPromise { diff --git a/src/vs/workbench/services/textfile/test/textFileService.test.ts b/src/vs/workbench/services/textfile/test/textFileService.test.ts index 4fcada9b2ec..3b1a12f2b03 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.test.ts @@ -60,14 +60,11 @@ suite('Files - TextFileService', () => { accessor.untitledEditorService.revertAll(); }); - test('confirm onWillShutdown - no veto', function (done) { + test('confirm onWillShutdown - no veto', function () { const event = new ShutdownEventImpl(); accessor.lifecycleService.fireWillShutdown(event); - return (>event.value).then(veto => { - assert.ok(!veto); - done(); - }); + assert.ok(!event.value); }); test('confirm onWillShutdown - veto if user cancels', function (done) { @@ -100,10 +97,9 @@ suite('Files - TextFileService', () => { const event = new ShutdownEventImpl(); accessor.lifecycleService.fireWillShutdown(event); - return (>event.value).then(veto => { - assert.ok(!veto); - done(); - }); + assert.ok(!event.value); + + done(); }); }); diff --git a/src/vs/workbench/services/untitled/common/untitledEditorService.ts b/src/vs/workbench/services/untitled/common/untitledEditorService.ts index f240fcde1ec..e064aa9da5f 100644 --- a/src/vs/workbench/services/untitled/common/untitledEditorService.ts +++ b/src/vs/workbench/services/untitled/common/untitledEditorService.ts @@ -58,7 +58,7 @@ export interface IUntitledEditorService { * It is valid to pass in a file resource. In that case the path will be used as identifier. * The use case is to be able to create a new file with a specific path with VSCode. */ - createOrGet(resource?: URI, modeId?: string, restoreResource?: URI): UntitledEditorInput; + createOrGet(resource?: URI, modeId?: string): UntitledEditorInput; /** * A check to find out if a untitled resource has a file path associated or not. @@ -76,9 +76,7 @@ export class UntitledEditorService implements IUntitledEditorService { private _onDidChangeDirty: Emitter; private _onDidChangeEncoding: Emitter; - constructor( - @IInstantiationService private instantiationService: IInstantiationService - ) { + constructor( @IInstantiationService private instantiationService: IInstantiationService) { this._onDidChangeDirty = new Emitter(); this._onDidChangeEncoding = new Emitter(); } @@ -132,7 +130,7 @@ export class UntitledEditorService implements IUntitledEditorService { .map((i) => i.getResource()); } - public createOrGet(resource?: URI, modeId?: string, restoreResource?: URI): UntitledEditorInput { + public createOrGet(resource?: URI, modeId?: string): UntitledEditorInput { let hasAssociatedFilePath = false; if (resource) { hasAssociatedFilePath = (resource.scheme === 'file'); @@ -149,10 +147,10 @@ export class UntitledEditorService implements IUntitledEditorService { } // Create new otherwise - return this.doCreate(resource, hasAssociatedFilePath, modeId, restoreResource); + return this.doCreate(resource, hasAssociatedFilePath, modeId); } - private doCreate(resource?: URI, hasAssociatedFilePath?: boolean, modeId?: string, restoreResource?: URI): UntitledEditorInput { + private doCreate(resource?: URI, hasAssociatedFilePath?: boolean, modeId?: string): UntitledEditorInput { if (!resource) { // Create new taking a resource URI that is not already taken @@ -164,9 +162,6 @@ export class UntitledEditorService implements IUntitledEditorService { } const input = this.instantiationService.createInstance(UntitledEditorInput, resource, hasAssociatedFilePath, modeId); - if (restoreResource) { - input.setRestoreResource(restoreResource); - } const dirtyListener = input.onDidChangeDirty(() => { this._onDidChangeDirty.fire(resource); diff --git a/src/vs/workbench/test/common/editor/editorStacksModel.test.ts b/src/vs/workbench/test/common/editor/editorStacksModel.test.ts index e0cd533d25c..a55d91e090c 100644 --- a/src/vs/workbench/test/common/editor/editorStacksModel.test.ts +++ b/src/vs/workbench/test/common/editor/editorStacksModel.test.ts @@ -145,9 +145,6 @@ class TestFileEditorInput extends EditorInput implements IFileEditorInput { public setResource(r: URI): void { } - public setRestoreFromBackup(restore: boolean): void { - } - public setEncoding(encoding: string) { }