multi root: restore untitled workspaces based on untitled workspaces on disk

This commit is contained in:
Benjamin Pasero
2017-07-20 12:53:17 +02:00
parent be413a0eff
commit d3f677dfd6
4 changed files with 98 additions and 28 deletions
+2 -24
View File
@@ -341,8 +341,8 @@ export class WindowsManager implements IWindowsMainService {
if (openConfig.initialStartup && !openConfig.cli.extensionDevelopmentPath) {
foldersToRestore = this.backupService.getFolderBackupPaths();
workspacesToRestore = this.backupService.getWorkspaceBackups(); // collect from workspaces with hot-exit backups
workspacesToRestore.push(...this.doGetUntitledWorkspacesFromLastSession()); // collect from previous window session
workspacesToRestore = this.backupService.getWorkspaceBackups(); // collect from workspaces with hot-exit backups
workspacesToRestore.push(...this.workspacesService.getUntitledWorkspacesSync()); // collect from previous window session
emptyToRestore = this.backupService.getEmptyWindowBackupPaths();
emptyToRestore.push(...windowsToOpen.filter(w => !w.workspace && !w.folderPath && w.backupPath).map(w => path.basename(w.backupPath))); // add empty windows with backupPath
@@ -782,28 +782,6 @@ export class WindowsManager implements IWindowsMainService {
return [Object.create(null)];
}
private doGetUntitledWorkspacesFromLastSession(): IWorkspaceIdentifier[] {
const candidates: IWorkspaceIdentifier[] = [];
if (this.isUntitledWorkspace(this.windowsState.lastActiveWindow)) {
candidates.push(this.windowsState.lastActiveWindow.workspace);
}
for (let i = 0; i < this.windowsState.openedWindows.length; i++) {
const state = this.windowsState.openedWindows[i];
if (this.isUntitledWorkspace(state)) {
candidates.push(state.workspace);
}
}
// Validate all workspace paths and only return the workspaces that are valid
return arrays.coalesce(candidates.map(candidate => this.parsePath(candidate.configPath)).map(window => window && window.workspace));
}
private isUntitledWorkspace(state: IWindowState): boolean {
return state && state.workspace && this.workspacesService.isUntitledWorkspace(state.workspace);
}
private getRestoreWindowsSetting(): RestoreWindowsSetting {
let restoreWindows: RestoreWindowsSetting;
if (this.lifecycleService.wasRestarted) {
@@ -20,6 +20,7 @@ export const IWorkspacesService = createDecorator<IWorkspacesService>('workspace
export const WORKSPACE_EXTENSION = 'code-workspace';
export const WORKSPACE_FILTER = [{ name: localize('codeWorkspace', "Code Workspace"), extensions: [WORKSPACE_EXTENSION] }];
export const UNTITLED_WORKSPACE_NAME = 'workspace.json';
/**
* A single folder workspace identifier is just the path to the folder.
@@ -51,6 +52,8 @@ export interface IWorkspacesMainService extends IWorkspacesService {
isUntitledWorkspace(workspace: IWorkspaceIdentifier): boolean;
deleteUntitledWorkspaceSync(workspace: IWorkspaceIdentifier): void;
getUntitledWorkspacesSync(): IWorkspaceIdentifier[];
}
export interface IWorkspacesService {
@@ -5,7 +5,7 @@
'use strict';
import { IWorkspacesMainService, IWorkspaceIdentifier, IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent } from "vs/platform/workspaces/common/workspaces";
import { IWorkspacesMainService, IWorkspaceIdentifier, IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME } from "vs/platform/workspaces/common/workspaces";
import { TPromise } from "vs/base/common/winjs.base";
import { isParent } from "vs/platform/files/common/files";
import { IEnvironmentService } from "vs/platform/environment/common/environment";
@@ -13,11 +13,12 @@ import { extname, join, dirname } from "path";
import { mkdirp, writeFile } from "vs/base/node/pfs";
import { readFileSync } from "fs";
import { isLinux } from "vs/base/common/platform";
import { copy, delSync } from "vs/base/node/extfs";
import { copy, delSync, readdirSync } from "vs/base/node/extfs";
import { nfcall } from "vs/base/common/async";
import Event, { Emitter } from "vs/base/common/event";
import { ILogService } from "vs/platform/log/common/log";
import { isEqual } from "vs/base/common/paths";
import { coalesce } from "vs/base/common/arrays";
export class WorkspacesMainService implements IWorkspacesMainService {
@@ -79,7 +80,7 @@ export class WorkspacesMainService implements IWorkspacesMainService {
const workspaceId = this.nextWorkspaceId();
const workspaceConfigFolder = join(this.workspacesHome, workspaceId);
const workspaceConfigPath = join(workspaceConfigFolder, 'workspace.json');
const workspaceConfigPath = join(workspaceConfigFolder, UNTITLED_WORKSPACE_NAME);
return mkdirp(workspaceConfigFolder).then(() => {
const storedWorkspace: IStoredWorkspace = {
@@ -130,9 +131,39 @@ export class WorkspacesMainService implements IWorkspacesMainService {
}
// Delete from disk
delSync(dirname(workspace.configPath));
this.doDeleteUntitledWorkspaceSync(workspace.configPath);
// Event
this._onWorkspaceDeleted.fire(workspace);
}
private doDeleteUntitledWorkspaceSync(configPath: string): void {
try {
delSync(dirname(configPath));
} catch (error) {
this.logService.log(`Unable to delete untitled workspace ${configPath} (${error}).`);
}
}
public getUntitledWorkspacesSync(): IWorkspaceIdentifier[] {
let untitledWorkspacePaths: string[] = [];
try {
untitledWorkspacePaths = readdirSync(this.workspacesHome).map(folder => join(this.workspacesHome, folder, UNTITLED_WORKSPACE_NAME));
} catch (error) {
this.logService.log(`Unable to read folders in ${this.workspacesHome} (${error}).`);
}
const untitledWorkspaces: IWorkspaceIdentifier[] = coalesce(untitledWorkspacePaths.map(untitledWorkspacePath => {
const workspace = this.resolveWorkspaceSync(untitledWorkspacePath);
if (!workspace) {
this.doDeleteUntitledWorkspaceSync(untitledWorkspacePath);
return null; // invalid workspace
}
return { id: workspace.id, configPath: untitledWorkspacePath };
}));
return untitledWorkspaces;
}
}
@@ -93,6 +93,10 @@ suite('WorkspacesMainService', () => {
const resolved = service.resolveWorkspaceSync(workspace.configPath);
assert.deepEqual(resolved, { id: workspace.id, folders: [process.cwd(), os.tmpdir()] });
fs.writeFileSync(workspace.configPath, JSON.stringify({ id: 'someid' })); // invalid workspace
const resolvedInvalid = service.resolveWorkspaceSync(workspace.configPath);
assert.ok(!resolvedInvalid);
done();
});
});
@@ -162,4 +166,58 @@ suite('WorkspacesMainService', () => {
});
});
});
test('deleteUntitledWorkspaceSync (untitled)', done => {
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
assert.ok(fs.existsSync(workspace.configPath));
service.deleteUntitledWorkspaceSync(workspace);
assert.ok(!fs.existsSync(workspace.configPath));
done();
});
});
test('deleteUntitledWorkspaceSync (saved)', done => {
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
const workspaceConfigPath = path.join(os.tmpdir(), `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`);
return service.saveWorkspace(workspace, workspaceConfigPath).then(savedWorkspace => {
assert.ok(fs.existsSync(savedWorkspace.configPath));
service.deleteUntitledWorkspaceSync(savedWorkspace);
assert.ok(fs.existsSync(savedWorkspace.configPath));
done();
});
});
});
test('getUntitledWorkspaceSync', done => {
let untitled = service.getUntitledWorkspacesSync();
assert.equal(0, untitled.length);
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(untitledOne => {
untitled = service.getUntitledWorkspacesSync();
assert.equal(1, untitled.length);
assert.equal(untitledOne.id, untitled[0].id);
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(untitledTwo => {
untitled = service.getUntitledWorkspacesSync();
assert.equal(2, untitled.length);
service.deleteUntitledWorkspaceSync(untitledOne);
service.deleteUntitledWorkspaceSync(untitledTwo);
untitled = service.getUntitledWorkspacesSync();
assert.equal(0, untitled.length);
done();
});
});
});
});