backupMainService.ts 3.9 KB
Newer Older
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import * as crypto from 'crypto';
7 8
import * as fs from 'fs';
import * as path from 'path';
9
import Uri from 'vs/base/common/uri';
D
Daniel Imms 已提交
10
import { IBackupWorkspacesFormat, IBackupMainService } from 'vs/platform/backup/common/backup';
11
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
12
import { ILifecycleMainService } from 'vs/platform/lifecycle/common/mainLifecycle';
D
Daniel Imms 已提交
13
import { VSCodeWindow } from 'vs/code/electron-main/window';
14

D
Daniel Imms 已提交
15
export class BackupMainService implements IBackupMainService {
16 17 18 19

	public _serviceBrand: any;

	protected backupHome: string;
D
Daniel Imms 已提交
20
	protected workspacesJsonPath: string;
21

D
Daniel Imms 已提交
22
	private workspacesJsonContent: IBackupWorkspacesFormat;
23 24

	constructor(
D
Daniel Imms 已提交
25
		@IEnvironmentService environmentService: IEnvironmentService,
26
		@ILifecycleMainService lifecycleService: ILifecycleMainService
27 28
	) {
		this.backupHome = environmentService.backupHome;
D
Daniel Imms 已提交
29
		this.workspacesJsonPath = environmentService.backupWorkspacesPath;
D
Daniel Imms 已提交
30

31
		lifecycleService.onBeforeUnload(this.onBeforeUnloadWindow.bind(this));
D
Daniel Imms 已提交
32

33
		this.loadSync();
34 35
	}

36
	private onBeforeUnloadWindow(vscodeWindow: VSCodeWindow) {
D
Daniel Imms 已提交
37 38 39 40 41 42 43 44 45
		if (vscodeWindow.openedWorkspacePath) {
			// Clear out workspace from workspaces.json if it doesn't have any backups
			const workspaceResource = Uri.file(vscodeWindow.openedWorkspacePath);
			if (!this.hasWorkspaceBackup(workspaceResource)) {
				this.removeWorkspaceBackupPathSync(workspaceResource);
			}
		}
	}

46
	public getWorkspaceBackupPaths(): string[] {
D
Daniel Imms 已提交
47
		return this.workspacesJsonContent.folderWorkspaces;
48 49 50 51 52 53 54 55 56
	}

	public pushWorkspaceBackupPathsSync(workspaces: Uri[]): void {
		workspaces.forEach(workspace => {
			// Hot exit is disabled for empty workspaces
			if (!workspace) {
				return;
			}

D
Daniel Imms 已提交
57 58
			if (this.workspacesJsonContent.folderWorkspaces.indexOf(workspace.fsPath) === -1) {
				this.workspacesJsonContent.folderWorkspaces.push(workspace.fsPath);
59 60 61 62 63
			}
		});
		this.saveSync();
	}

64 65 66 67 68 69 70 71 72 73 74 75
	public removeWorkspaceBackupPathSync(workspace: Uri): void {
		if (!this.workspacesJsonContent.folderWorkspaces) {
			return;
		}
		const index = this.workspacesJsonContent.folderWorkspaces.indexOf(workspace.fsPath);
		if (index === -1) {
			return;
		}
		this.workspacesJsonContent.folderWorkspaces.splice(index, 1);
		this.saveSync();
	}

76
	public hasWorkspaceBackup(workspace: Uri): boolean {
77 78 79 80 81 82 83 84
		return fs.existsSync(this.getWorkspaceBackupDirectory(workspace));
	}

	private getWorkspaceBackupDirectory(workspace: Uri): string {
		const workspaceHash = crypto.createHash('md5').update(workspace.fsPath).digest('hex');
		return path.join(this.backupHome, workspaceHash);
	}

85
	protected loadSync(): void {
D
Daniel Imms 已提交
86
		try {
D
Daniel Imms 已提交
87
			this.workspacesJsonContent = JSON.parse(fs.readFileSync(this.workspacesJsonPath, 'utf8').toString()); // invalid JSON or permission issue can happen here
D
Daniel Imms 已提交
88
		} catch (error) {
D
Daniel Imms 已提交
89 90 91 92 93 94 95 96 97
			this.workspacesJsonContent = Object.create(null);
		}

		// Ensure folderWorkspaces is a string[]
		if (this.workspacesJsonContent.folderWorkspaces) {
			const fws = this.workspacesJsonContent.folderWorkspaces;
			if (!Array.isArray(fws) || fws.some(f => typeof f !== 'string')) {
				this.workspacesJsonContent = Object.create(null);
			}
98 99
		}

D
Daniel Imms 已提交
100 101
		if (!this.workspacesJsonContent.folderWorkspaces) {
			this.workspacesJsonContent.folderWorkspaces = [];
102 103 104 105 106 107 108 109 110
		}
	}

	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);
			}
D
Daniel Imms 已提交
111
			fs.writeFileSync(this.workspacesJsonPath, JSON.stringify(this.workspacesJsonContent));
112
		} catch (ex) {
113
			console.error('Could not save workspaces.json', ex);
114 115
		}
	}
116
}