Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move backup unload logic to an event #15493

Merged
merged 6 commits into from
Nov 17, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/vs/code/common/window.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

'use strict';

export enum ReadyState {

/**
* This window has not loaded any HTML yet
*/
NONE,

/**
* This window is loading HTML
*/
LOADING,

/**
* This window is navigating to another HTML
*/
NAVIGATING,

/**
* This window is done loading HTML
*/
READY
}

export interface IVSCodeWindow {
id: number;
readyState: ReadyState;
win: Electron.BrowserWindow;

send(channel: string, ...args: any[]): void;
}
47 changes: 14 additions & 33 deletions src/vs/code/electron-main/lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,21 @@

'use strict';

import Uri from 'vs/base/common/uri';
import { EventEmitter } from 'events';
import { ipcMain as ipc, app } from 'electron';
import { TPromise, TValueCallback } from 'vs/base/common/winjs.base';
import { ReadyState, VSCodeWindow } from 'vs/code/electron-main/window';
import { ReadyState, IVSCodeWindow } from 'vs/code/common/window';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IBackupMainService } from 'vs/platform/backup/common/backup';
import { ILogService } from 'vs/code/electron-main/log';
import { IStorageService } from 'vs/code/electron-main/storage';
import { ILifecycleMainService } from 'vs/platform/lifecycle/common/mainLifecycle';

const EventTypes = {
BEFORE_CLOSE: 'before-close',
BEFORE_QUIT: 'before-quit'
};

export const ILifecycleService = createDecorator<ILifecycleService>('lifecycleService');

export interface ILifecycleService {
_serviceBrand: any;

/**
* Will be true if an update was applied. Will only be true for each update once.
*/
wasUpdated: boolean;

onBeforeQuit(clb: () => void): () => void;
ready(): void;
registerWindow(vscodeWindow: VSCodeWindow): void;
unload(vscodeWindow: VSCodeWindow): TPromise<boolean /* veto */>;
quit(fromUpdate?: boolean): TPromise<boolean /* veto */>;
}

export class LifecycleService implements ILifecycleService {
export class LifecycleService implements ILifecycleMainService {

_serviceBrand: any;

Expand All @@ -54,8 +36,7 @@ export class LifecycleService implements ILifecycleService {
constructor(
@IEnvironmentService private environmentService: IEnvironmentService,
@ILogService private logService: ILogService,
@IStorageService private storageService: IStorageService,
@IBackupMainService private backupService: IBackupMainService
@IStorageService private storageService: IStorageService
) {
this.windowToCloseRequest = Object.create(null);
this.quitRequested = false;
Expand Down Expand Up @@ -88,6 +69,12 @@ export class LifecycleService implements ILifecycleService {
return () => this.eventEmitter.removeListener(EventTypes.BEFORE_QUIT, clb);
}

onAfterUnload(clb: (vscodeWindow: IVSCodeWindow) => void): () => void {
this.eventEmitter.addListener(EventTypes.BEFORE_CLOSE, clb);

return () => this.eventEmitter.removeListener(EventTypes.BEFORE_CLOSE, clb);
}

public ready(): void {
this.registerListeners();
}
Expand Down Expand Up @@ -118,7 +105,7 @@ export class LifecycleService implements ILifecycleService {
});
}

public registerWindow(vscodeWindow: VSCodeWindow): void {
public registerWindow(vscodeWindow: IVSCodeWindow): void {

// Window Before Closing: Main -> Renderer
vscodeWindow.win.on('close', (e) => {
Expand Down Expand Up @@ -148,7 +135,7 @@ export class LifecycleService implements ILifecycleService {
});
}

public unload(vscodeWindow: VSCodeWindow): TPromise<boolean /* veto */> {
public unload(vscodeWindow: IVSCodeWindow): TPromise<boolean /* veto */> {

// Always allow to unload a window that is not yet ready
if (vscodeWindow.readyState !== ReadyState.READY) {
Expand All @@ -163,13 +150,7 @@ export class LifecycleService implements ILifecycleService {
const oneTimeCancelEvent = 'vscode:cancel' + oneTimeEventToken;

ipc.once(oneTimeOkEvent, () => {
// Clear out any workspace backups from workspaces.json that don't have any backups
if (vscodeWindow.openedWorkspacePath) {
const workspaceResource = Uri.file(vscodeWindow.openedWorkspacePath);
if (!this.backupService.hasWorkspaceBackup(workspaceResource)) {
this.backupService.removeWorkspaceBackupPathSync(workspaceResource);
}
}
this.eventEmitter.emit(EventTypes.BEFORE_CLOSE, vscodeWindow);

c(false); // no veto
});
Expand Down
9 changes: 5 additions & 4 deletions src/vs/code/electron-main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import { IWindowsMainService, WindowsManager } from 'vs/code/electron-main/windo
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { WindowsChannel } from 'vs/platform/windows/common/windowsIpc';
import { WindowsService } from 'vs/platform/windows/electron-main/windowsService';
import { ILifecycleService, LifecycleService } from 'vs/code/electron-main/lifecycle';
import { LifecycleService } from 'vs/code/electron-main/lifecycle';
import { ILifecycleMainService } from 'vs/platform/lifecycle/common/mainLifecycle';
import { VSCodeMenu } from 'vs/code/electron-main/menus';
import { IUpdateService } from 'vs/platform/update/common/update';
import { UpdateChannel } from 'vs/platform/update/common/updateIpc';
Expand All @@ -35,7 +36,7 @@ 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 { IBackupMainService } from 'vs/platform/backup/common/backup';
import { BackupMainService } from 'vs/platform/backup/node/backupMainService';
import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
Expand Down Expand Up @@ -81,7 +82,7 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo
const instantiationService = accessor.get(IInstantiationService);
const logService = accessor.get(ILogService);
const environmentService = accessor.get(IEnvironmentService);
const lifecycleService = accessor.get(ILifecycleService);
const lifecycleService = accessor.get(ILifecycleMainService);
const configurationService = accessor.get(IConfigurationService) as ConfigurationService<any>;
let windowsMainService: IWindowsMainService;

Expand Down Expand Up @@ -423,7 +424,7 @@ function createServices(args): IInstantiationService {

services.set(IEnvironmentService, new SyncDescriptor(EnvironmentService, args, process.execPath));
services.set(ILogService, new SyncDescriptor(MainLogService));
services.set(ILifecycleService, new SyncDescriptor(LifecycleService));
services.set(ILifecycleMainService, new SyncDescriptor(LifecycleService));
services.set(IStorageService, new SyncDescriptor(StorageService));
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService));
services.set(IRequestService, new SyncDescriptor(RequestService));
Expand Down
26 changes: 2 additions & 24 deletions src/vs/code/electron-main/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { getCommonHTTPHeaders } from 'vs/platform/environment/node/http';
import { IBackupMainService } from 'vs/platform/backup/common/backup';
import { IWindowSettings } from 'vs/platform/windows/common/windows';
import Uri from 'vs/base/common/uri';
import { ReadyState, IVSCodeWindow } from 'vs/code/common/window';

export interface IWindowState {
width?: number;
Expand Down Expand Up @@ -51,29 +52,6 @@ export const defaultWindowState = function (mode = WindowMode.Normal): IWindowSt
};
};

export enum ReadyState {

/**
* This window has not loaded any HTML yet
*/
NONE,

/**
* This window is loading HTML
*/
LOADING,

/**
* This window is navigating to another HTML
*/
NAVIGATING,

/**
* This window is done loading HTML
*/
READY
}

export interface IPath {

// the workspace spath for a VSCode instance which can be null
Expand Down Expand Up @@ -116,7 +94,7 @@ export interface IWindowConfiguration extends ParsedArgs {
untitledToRestore?: IPath[];
}

export class VSCodeWindow {
export class VSCodeWindow implements IVSCodeWindow {

public static menuBarHiddenKey = 'menuBarHidden';
public static colorThemeStorageKey = 'theme';
Expand Down
7 changes: 4 additions & 3 deletions src/vs/code/electron-main/windows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ import { IBackupMainService } from 'vs/platform/backup/common/backup';
import { trim } from 'vs/base/common/strings';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { IStorageService } from 'vs/code/electron-main/storage';
import { IPath, VSCodeWindow, ReadyState, IWindowConfiguration, IWindowState as ISingleWindowState, defaultWindowState } from 'vs/code/electron-main/window';
import { IPath, VSCodeWindow, IWindowConfiguration, IWindowState as ISingleWindowState, defaultWindowState } from 'vs/code/electron-main/window';
import { ReadyState } from 'vs/code/common/window';
import { ipcMain as ipc, app, screen, BrowserWindow, dialog } from 'electron';
import { IPathWithLineAndColumn, parseLineAndColumnAware } from 'vs/code/electron-main/paths';
import { ILifecycleService } from 'vs/code/electron-main/lifecycle';
import { ILifecycleMainService } from 'vs/platform/lifecycle/common/mainLifecycle';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService } from 'vs/code/electron-main/log';
import { getPathLabel } from 'vs/base/common/labels';
Expand Down Expand Up @@ -152,7 +153,7 @@ export class WindowsManager implements IWindowsMainService {
@ILogService private logService: ILogService,
@IStorageService private storageService: IStorageService,
@IEnvironmentService private environmentService: IEnvironmentService,
@ILifecycleService private lifecycleService: ILifecycleService,
@ILifecycleMainService private lifecycleService: ILifecycleMainService,
@IBackupMainService private backupService: IBackupMainService,
@IConfigurationService private configurationService: IConfigurationService,
@ITelemetryService private telemetryService: ITelemetryService
Expand Down
38 changes: 38 additions & 0 deletions src/vs/code/test/electron-main/servicesTestUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { ILifecycleMainService } from 'vs/platform/lifecycle/common/mainLifecycle';
import { IVSCodeWindow } from 'vs/code/common/window';
import { TPromise } from 'vs/base/common/winjs.base';

export class TestLifecycleService implements ILifecycleMainService {
public _serviceBrand: any;

public get wasUpdated(): boolean {
return false;
}

public onBeforeQuit(clb: () => void): () => void {
return () => { };
}

public onAfterUnload(clb: (vscodeWindow: IVSCodeWindow) => void): () => void {
return () => { };
}

public ready(): void {
}

public registerWindow(vscodeWindow: IVSCodeWindow): void {
}

public unload(vscodeWindow: IVSCodeWindow): TPromise<boolean /* veto */> {
return TPromise.as(false);
}

public quit(fromUpdate?: boolean): TPromise<boolean /* veto */> {
return TPromise.as(false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import Uri from 'vs/base/common/uri';
import { readdirSync } from 'vs/base/node/extfs';
import { IBackupWorkspacesFormat, IBackupMainService } from 'vs/platform/backup/common/backup';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ILifecycleMainService } from 'vs/platform/lifecycle/common/mainLifecycle';
import { VSCodeWindow } from 'vs/code/electron-main/window';

export class BackupMainService implements IBackupMainService {

Expand All @@ -21,13 +23,27 @@ export class BackupMainService implements IBackupMainService {
private workspacesJsonContent: IBackupWorkspacesFormat;

constructor(
@IEnvironmentService environmentService: IEnvironmentService
@IEnvironmentService environmentService: IEnvironmentService,
@ILifecycleMainService lifecycleService: ILifecycleMainService
) {
this.backupHome = environmentService.backupHome;
this.workspacesJsonPath = environmentService.backupWorkspacesPath;

lifecycleService.onAfterUnload(this.onAfterUnloadWindow.bind(this));

this.loadSync();
}

private onAfterUnloadWindow(vscodeWindow: VSCodeWindow) {
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);
}
}
}

public getWorkspaceBackupPaths(): string[] {
return this.workspacesJsonContent.folderWorkspaces;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ import extfs = require('vs/base/node/extfs');
import pfs = require('vs/base/node/pfs');
import Uri from 'vs/base/common/uri';
import { TestEnvironmentService } from 'vs/test/utils/servicesTestUtils';
import { BackupMainService } from 'vs/platform/backup/node/backupMainService';
import { TestLifecycleService } from 'vs/code/test/electron-main/servicesTestUtils';
import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService';
import { IBackupWorkspacesFormat } from 'vs/platform/backup/common/backup';

class TestBackupMainService extends BackupMainService {
constructor(backupHome: string, backupWorkspacesPath: string) {
super(TestEnvironmentService);
super(TestEnvironmentService, new TestLifecycleService());

this.backupHome = backupHome;
this.workspacesJsonPath = backupWorkspacesPath;
Expand Down
27 changes: 27 additions & 0 deletions src/vs/platform/lifecycle/common/mainLifecycle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*---------------------------------------------------------------------------------------------
* 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 { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IVSCodeWindow } from 'vs/code/common/window';
import { TPromise } from 'vs/base/common/winjs.base';

export const ILifecycleMainService = createDecorator<ILifecycleMainService>('lifecycleMainService');

export interface ILifecycleMainService {
_serviceBrand: any;

/**
* Will be true if an update was applied. Will only be true for each update once.
*/
wasUpdated: boolean;

onBeforeQuit(clb: () => void): () => void;
onAfterUnload(clb: (vscodeWindow: IVSCodeWindow) => void): () => void;
ready(): void;
registerWindow(vscodeWindow: IVSCodeWindow): void;
unload(vscodeWindow: IVSCodeWindow): TPromise<boolean /* veto */>;
quit(fromUpdate?: boolean): TPromise<boolean /* veto */>;
}
4 changes: 2 additions & 2 deletions src/vs/platform/update/electron-main/auto-updater.win32.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { mkdirp } from 'vs/base/node/extfs';
import { isString } from 'vs/base/common/types';
import { Promise, TPromise } from 'vs/base/common/winjs.base';
import { download, asJson } from 'vs/base/node/request';
import { ILifecycleService } from 'vs/code/electron-main/lifecycle';
import { ILifecycleMainService } from 'vs/platform/lifecycle/common/mainLifecycle';
import { IRequestService } from 'vs/platform/request/node/request';
import { IAutoUpdater } from 'vs/platform/update/common/update';
import product from 'vs/platform/product';
Expand All @@ -36,7 +36,7 @@ export class Win32AutoUpdaterImpl extends EventEmitter implements IAutoUpdater {
private updatePackagePath: string = null;

constructor(
@ILifecycleService private lifecycleService: ILifecycleService,
@ILifecycleMainService private lifecycleService: ILifecycleMainService,
@IRequestService private requestService: IRequestService
) {
super();
Expand Down