mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-11 14:04:49 -05:00
Merge pull request #15493 from Microsoft/tyriar/hot_exit/15260
Move backup unload logic to an event
This commit is contained in:
37
src/vs/code/common/window.ts
Normal file
37
src/vs/code/common/window.ts
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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) => {
|
||||
@@ -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) {
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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';
|
||||
@@ -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';
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
@@ -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
|
||||
|
||||
38
src/vs/code/test/electron-main/servicesTestUtils.ts
Normal file
38
src/vs/code/test/electron-main/servicesTestUtils.ts
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
27
src/vs/platform/lifecycle/common/mainLifecycle.ts
Normal file
27
src/vs/platform/lifecycle/common/mainLifecycle.ts
Normal file
@@ -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 */>;
|
||||
}
|
||||
@@ -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';
|
||||
@@ -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();
|
||||
|
||||
@@ -16,7 +16,7 @@ import { fromEventEmitter } from 'vs/base/node/event';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { Win32AutoUpdaterImpl } from './auto-updater.win32';
|
||||
import { LinuxAutoUpdaterImpl } from './auto-updater.linux';
|
||||
import { ILifecycleService } from 'vs/code/electron-main/lifecycle';
|
||||
import { ILifecycleMainService } from 'vs/platform/lifecycle/common/mainLifecycle';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import product from 'vs/platform/product';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
@@ -85,7 +85,7 @@ export class UpdateService implements IUpdateService {
|
||||
|
||||
constructor(
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@ILifecycleService private lifecycleService: ILifecycleService,
|
||||
@ILifecycleMainService private lifecycleService: ILifecycleMainService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@ITelemetryService private telemetryService: ITelemetryService
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user