提交 f6f37aa3 编写于 作者: B Benjamin Pasero

sqlite - hook in next storage service to workbench (in memory only)

上级 cfe3e33c
......@@ -99,7 +99,8 @@ function createPaths(environmentService: IEnvironmentService): TPromise<any> {
environmentService.appSettingsHome,
environmentService.extensionsPath,
environmentService.nodeCachedDataDir,
environmentService.logsPath
environmentService.logsPath,
environmentService.storageHome
];
return TPromise.join(paths.map(p => p && mkdirp(p))) as TPromise<any>;
......
......@@ -1174,6 +1174,7 @@ export class WindowsManager implements IWindowsMainService {
const configuration: IWindowConfiguration = mixin({}, options.cli); // inherit all properties from CLI
configuration.appRoot = this.environmentService.appRoot;
configuration.machineId = this.machineId;
configuration.nodeCachedDataDir = this.environmentService.nodeCachedDataDir;
configuration.mainPid = process.pid;
configuration.execPath = process.execPath;
configuration.userEnv = assign({}, this.initialUserEnv, options.userEnv || {});
......@@ -1188,7 +1189,6 @@ export class WindowsManager implements IWindowsMainService {
configuration.filesToDiff = fileInputs.filesToDiff;
configuration.filesToWait = fileInputs.filesToWait;
}
configuration.nodeCachedDataDir = this.environmentService.nodeCachedDataDir;
// if we know the backup folder upfront (for empty windows to restore), we can set it
// directly here which helps for restoring UI state associated with that window.
......
......@@ -105,6 +105,8 @@ export interface IEnvironmentService {
backupHome: string;
backupWorkspacesPath: string;
storageHome: string;
workspacesHome: string;
isExtensionDevelopment: boolean;
......
......@@ -124,6 +124,9 @@ export class EnvironmentService implements IEnvironmentService {
@memoize
get backupHome(): string { return path.join(this.userDataPath, 'Backups'); }
@memoize
get storageHome(): string { return path.join(this.userDataPath, 'Storage'); }
@memoize
get backupWorkspacesPath(): string { return path.join(this.backupHome, 'workspaces.json'); }
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Event } from 'vs/base/common/event';
export const ID = 'nextStorageService';
export const INextStorageService = createDecorator<INextStorageService>(ID);
export interface INextStorageService {
_serviceBrand: any;
readonly onDidChangeStorage: Event<Set<string>>;
/**
* Retrieve an element stored with the given key from storage. Use
* the provided defaultValue if the element is null or undefined.
*/
get(key: string, fallbackValue?: string): string;
/**
* Retrieve an element stored with the given key from storage. Use
* the provided defaultValue if the element is null or undefined. The element
* will be converted to a boolean.
*/
getBoolean(key: string, fallbackValue?: boolean): boolean;
/**
* Retrieve an element stored with the given key from storage. Use
* the provided defaultValue if the element is null or undefined. The element
* will be converted to a number using parseInt with a base of 10.
*/
getInteger(key: string, fallbackValue?: number): number;
/**
* Store a string value under the given key to storage. The value will
* be converted to a string.
*/
set(key: string, value: any): Promise<void>;
/**
* Delete an element stored under the provided key from storage.
*/
delete(key: string): Promise<void>;
}
\ No newline at end of file
......@@ -6,31 +6,56 @@
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Event } from 'vs/base/common/event';
export const ID = 'nextWorkspaceStorageService';
export const INextStorageService = createDecorator<INextStorageService>('nextStorageService');
export const INextWorkspaceStorageService = createDecorator<INextWorkspaceStorageService>(ID);
export interface INextStorageService {
_serviceBrand: any;
export const enum StorageScope {
/**
* Emitted whenever data is updated or deleted.
*/
readonly onDidChangeStorage: Event<Set<string>>;
/**
* The stored data will be scoped to all workspaces.
* Retrieve an element stored with the given key from storage. Use
* the provided defaultValue if the element is null or undefined.
*/
GLOBAL,
get(key: string, fallbackValue?: string): string;
/**
* The stored data will be scoped to the current workspace.
* Retrieve an element stored with the given key from storage. Use
* the provided defaultValue if the element is null or undefined. The element
* will be converted to a boolean.
*/
WORKSPACE
}
getBoolean(key: string, fallbackValue?: boolean): boolean;
export interface IWorkspaceStorageChangeEvent {
keys: Set<string>;
scope: StorageScope;
/**
* Retrieve an element stored with the given key from storage. Use
* the provided defaultValue if the element is null or undefined. The element
* will be converted to a number using parseInt with a base of 10.
*/
getInteger(key: string, fallbackValue?: number): number;
/**
* Store a string value under the given key to storage. The value will
* be converted to a string.
*/
set(key: string, value: any): Promise<void>;
/**
* Delete an element stored under the provided key from storage.
*/
delete(key: string): Promise<void>;
}
export const INextWorkspaceStorageService = createDecorator<INextWorkspaceStorageService>('nextWorkspaceStorageService');
export interface INextWorkspaceStorageService {
_serviceBrand: any;
/**
* Emitted whenever data is updated or deleted.
*/
readonly onDidChangeStorage: Event<IWorkspaceStorageChangeEvent>;
/**
......@@ -78,4 +103,22 @@ export interface INextWorkspaceStorageService {
* operation to either the current workspace only or all workspaces.
*/
delete(key: string, scope?: StorageScope): Promise<void>;
}
export const enum StorageScope {
/**
* The stored data will be scoped to all workspaces.
*/
GLOBAL,
/**
* The stored data will be scoped to the current workspace.
*/
WORKSPACE
}
export interface IWorkspaceStorageChangeEvent {
keys: Set<string>;
scope: StorageScope;
}
\ No newline at end of file
......@@ -6,7 +6,7 @@
import { Disposable } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { INextStorageService } from 'vs/platform/storage2/common/nextStorageService';
import { INextStorageService } from 'vs/platform/storage2/common/storage2';
import { SQLiteStorage } from 'vs/base/node/storage';
import { ILogService } from 'vs/platform/log/common/log';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
......
......@@ -7,10 +7,8 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkspaceStorageChangeEvent, INextWorkspaceStorageService, StorageScope } from 'vs/platform/storage2/common/nextWorkspaceStorageService';
import { INextStorageService, IWorkspaceStorageChangeEvent, INextWorkspaceStorageService, StorageScope } from 'vs/platform/storage2/common/storage2';
import { NextStorageServiceImpl } from 'vs/platform/storage2/node/nextStorageServiceImpl';
import { INextStorageService } from 'vs/platform/storage2/common/nextStorageService';
import { ILifecycleService, ShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle';
export class NextWorkspaceStorageServiceImpl extends Disposable implements INextWorkspaceStorageService {
_serviceBrand: any;
......@@ -24,8 +22,7 @@ export class NextWorkspaceStorageServiceImpl extends Disposable implements INext
constructor(
workspaceDBPath: string,
@ILogService logService: ILogService,
@IEnvironmentService environmentService: IEnvironmentService,
@ILifecycleService private lifecycleService: ILifecycleService
@IEnvironmentService environmentService: IEnvironmentService
) {
super();
......@@ -38,18 +35,12 @@ export class NextWorkspaceStorageServiceImpl extends Disposable implements INext
private registerListeners(): void {
this._register(this.globalStorage.onDidChangeStorage(keys => this.handleDidChangeStorage(keys, StorageScope.GLOBAL)));
this._register(this.workspaceStorage.onDidChangeStorage(keys => this.handleDidChangeStorage(keys, StorageScope.WORKSPACE)));
this._register(this.lifecycleService.onShutdown(event => this.onShutdown(event)));
}
private handleDidChangeStorage(keys: Set<string>, scope: StorageScope): void {
this._onDidChangeStorage.fire({ keys, scope });
}
private onShutdown(event: ShutdownEvent): void {
event.join(this.close());
}
init(): Promise<void> {
return Promise.all([this.globalStorage.init(), this.workspaceStorage.init()]).then(() => void 0);
}
......@@ -68,7 +59,6 @@ export class NextWorkspaceStorageServiceImpl extends Disposable implements INext
set(key: string, value: any, scope: StorageScope = StorageScope.GLOBAL): Promise<void> {
return this.getStorage(scope).set(key, value);
}
delete(key: string, scope: StorageScope = StorageScope.GLOBAL): Promise<void> {
......
......@@ -10,7 +10,7 @@ import { generateUuid } from 'vs/base/common/uuid';
import { join } from 'path';
import { tmpdir } from 'os';
import { equal, ok } from 'assert';
import { INextStorageService } from 'vs/platform/storage2/common/nextStorageService';
import { INextStorageService } from 'vs/platform/storage2/common/storage2';
import { del, mkdirp } from 'vs/base/node/pfs';
suite('Workbench NextStorageService', () => {
......
......@@ -5,7 +5,6 @@
import * as nls from 'vs/nls';
import * as perf from 'vs/base/common/performance';
import { TPromise } from 'vs/base/common/winjs.base';
import { WorkbenchShell } from 'vs/workbench/electron-browser/shell';
import * as browser from 'vs/base/browser/browser';
import { domContentLoaded } from 'vs/base/browser/dom';
......@@ -37,6 +36,7 @@ import { IWorkspacesService, ISingleFolderWorkspaceIdentifier } from 'vs/platfor
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
import * as fs from 'fs';
import { ConsoleLogService, MultiplexLogService, ILogService } from 'vs/platform/log/common/log';
import { NextWorkspaceStorageServiceImpl } from 'vs/platform/storage2/node/nextWorkspaceStorageServiceImpl';
import { IssueChannelClient } from 'vs/platform/issue/node/issueIpc';
import { IIssueService } from 'vs/platform/issue/common/issue';
import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/node/logIpc';
......@@ -48,26 +48,24 @@ import { sanitizeFilePath } from 'vs/base/node/extfs';
gracefulFs.gracefulify(fs); // enable gracefulFs
export function startup(configuration: IWindowConfiguration): TPromise<void> {
export function startup(configuration: IWindowConfiguration): Promise<void> {
// Massage configuration file URIs
revive(configuration);
// Setup perf
perf.importEntries(configuration.perfEntries);
// Ensure others can listen to zoom level changes
browser.setZoomFactor(webFrame.getZoomFactor());
// See https://github.com/Microsoft/vscode/issues/26151
// Can be trusted because we are not setting it ourselves.
browser.setZoomLevel(webFrame.getZoomLevel(), true /* isTrusted */);
// Browser config
browser.setZoomFactor(webFrame.getZoomFactor()); // Ensure others can listen to zoom level changes
browser.setZoomLevel(webFrame.getZoomLevel(), true /* isTrusted */); // Can be trusted because we are not setting it ourselves (https://github.com/Microsoft/vscode/issues/26151)
browser.setFullscreen(!!configuration.fullscreen);
browser.setAccessibilitySupport(configuration.accessibilitySupport ? platform.AccessibilitySupport.Enabled : platform.AccessibilitySupport.Disabled);
// Keyboard support
KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged();
browser.setAccessibilitySupport(configuration.accessibilitySupport ? platform.AccessibilitySupport.Enabled : platform.AccessibilitySupport.Disabled);
// Setup Intl
// Setup Intl for comparers
comparer.setFileNameComparer(new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }));
// Open workbench
......@@ -78,6 +76,7 @@ function revive(workbench: IWindowConfiguration) {
if (workbench.folderUri) {
workbench.folderUri = uri.revive(workbench.folderUri);
}
const filesToWaitPaths = workbench.filesToWait && workbench.filesToWait.paths;
[filesToWaitPaths, workbench.filesToOpen, workbench.filesToCreate, workbench.filesToDiff].forEach(paths => {
if (Array.isArray(paths)) {
......@@ -90,30 +89,42 @@ function revive(workbench: IWindowConfiguration) {
});
}
function openWorkbench(configuration: IWindowConfiguration): TPromise<void> {
function openWorkbench(configuration: IWindowConfiguration): Promise<void> {
const mainProcessClient = new ElectronIPCClient(`window:${configuration.windowId}`);
const mainServices = createMainProcessServices(mainProcessClient, configuration);
const environmentService = new EnvironmentService(configuration, configuration.execPath);
const logService = createLogService(mainProcessClient, configuration, environmentService);
logService.trace('openWorkbench configuration', JSON.stringify(configuration));
// Since the configuration service is one of the core services that is used in so many places, we initialize it
// right before startup of the workbench shell to have its data ready for consumers
return createAndInitializeWorkspaceService(configuration, environmentService).then(workspaceService => {
return Promise.all([
createAndInitializeWorkspaceService(configuration, environmentService),
createNextWorkspaceStorageService(environmentService, logService)
]).then(services => {
const workspaceService = services[0];
const nextStorageService = services[1];
const storageService = createStorageService(workspaceService, environmentService);
return domContentLoaded().then(() => {
// Open Shell
perf.mark('willStartWorkbench');
// Create Shell
const shell = new WorkbenchShell(document.body, {
contextService: workspaceService,
configurationService: workspaceService,
environmentService,
logService,
storageService
storageService,
nextStorageService
}, mainServices, mainProcessClient, configuration);
// Gracefully Shutdown Storage
shell.onShutdown(event => {
event.join(nextStorageService.close());
});
// Open Shell
shell.open();
// Inform user about loading issues from the loader
......@@ -128,20 +139,19 @@ function openWorkbench(configuration: IWindowConfiguration): TPromise<void> {
});
}
function createAndInitializeWorkspaceService(configuration: IWindowConfiguration, environmentService: EnvironmentService): TPromise<WorkspaceService> {
function createAndInitializeWorkspaceService(configuration: IWindowConfiguration, environmentService: EnvironmentService): Promise<WorkspaceService> {
return validateFolderUri(configuration.folderUri, configuration.verbose).then(validatedFolderUri => {
const workspaceService = new WorkspaceService(environmentService);
return workspaceService.initialize(configuration.workspace || validatedFolderUri || configuration).then(() => workspaceService, error => workspaceService);
});
}
function validateFolderUri(folderUri: ISingleFolderWorkspaceIdentifier, verbose: boolean): TPromise<uri> {
function validateFolderUri(folderUri: ISingleFolderWorkspaceIdentifier, verbose: boolean): Promise<uri> {
// Return early if we do not have a single folder uri or if it is a non file uri
if (!folderUri || folderUri.scheme !== Schemas.file) {
return TPromise.as(folderUri);
return Promise.resolve(folderUri);
}
// Ensure absolute existing folder path
......@@ -156,6 +166,12 @@ function validateFolderUri(folderUri: ISingleFolderWorkspaceIdentifier, verbose:
});
}
function createNextWorkspaceStorageService(environmentService: IEnvironmentService, logService: ILogService): Promise<NextWorkspaceStorageServiceImpl> {
const nextStorageService = new NextWorkspaceStorageServiceImpl(':memory:', logService, environmentService);
return nextStorageService.init().then(() => nextStorageService);
}
function createStorageService(workspaceService: IWorkspaceContextService, environmentService: IEnvironmentService): IStorageService {
let workspaceId: string;
let secondaryWorkspaceId: number;
......@@ -203,6 +219,7 @@ function createLogService(mainProcessClient: ElectronIPCClient, configuration: I
const consoleLogService = new ConsoleLogService(configuration.logLevel);
const logService = new MultiplexLogService([consoleLogService, spdlogService]);
const logLevelClient = new LogLevelSetterChannelClient(mainProcessClient.getChannel('loglevel'));
return new FollowerLogService(logLevelClient, logService);
}
......
......@@ -43,8 +43,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { InstantiationService } from 'vs/platform/instantiation/node/instantiationService';
// import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { ILifecycleService, LifecyclePhase, ShutdownReason, StartupKind } from 'vs/platform/lifecycle/common/lifecycle';
import { ILifecycleService, LifecyclePhase, ShutdownReason, StartupKind, ShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ISearchService, ISearchHistoryService } from 'vs/platform/search/common/search';
......@@ -76,6 +75,8 @@ import { IBroadcastService, BroadcastService } from 'vs/platform/broadcast/elect
import { HashService } from 'vs/workbench/services/hash/node/hashService';
import { IHashService } from 'vs/workbench/services/hash/common/hashService';
import { ILogService } from 'vs/platform/log/common/log';
import { INextWorkspaceStorageService } from 'vs/platform/storage2/common/storage2';
import { Event, Emitter } from 'vs/base/common/event';
import { WORKBENCH_BACKGROUND } from 'vs/workbench/common/theme';
import { stat } from 'fs';
import { join } from 'path';
......@@ -109,6 +110,7 @@ export interface ICoreServices {
environmentService: IEnvironmentService;
logService: ILogService;
storageService: IStorageService;
nextStorageService: INextWorkspaceStorageService;
}
/**
......@@ -116,7 +118,12 @@ export interface ICoreServices {
* With the Shell being the top level element in the page, it is also responsible for driving the layouting.
*/
export class WorkbenchShell extends Disposable {
private readonly _onShutdown = this._register(new Emitter<ShutdownEvent>());
get onShutdown(): Event<ShutdownEvent> { return this._onShutdown.event; }
private storageService: IStorageService;
private nextStorageService: INextWorkspaceStorageService;
private environmentService: IEnvironmentService;
private logService: ILogService;
private configurationService: IConfigurationService;
......@@ -147,6 +154,7 @@ export class WorkbenchShell extends Disposable {
this.environmentService = coreServices.environmentService;
this.logService = coreServices.logService;
this.storageService = coreServices.storageService;
this.nextStorageService = coreServices.nextStorageService;
this.mainProcessServices = mainProcessServices;
......@@ -326,8 +334,9 @@ export class WorkbenchShell extends Disposable {
serviceCollection.set(IEnvironmentService, this.environmentService);
serviceCollection.set(ILabelService, new SyncDescriptor(LabelService));
serviceCollection.set(ILogService, this._register(this.logService));
serviceCollection.set(IStorageService, this.storageService);
serviceCollection.set(INextWorkspaceStorageService, this.nextStorageService);
this.mainProcessServices.forEach((serviceIdentifier, serviceInstance) => {
serviceCollection.set(serviceIdentifier, serviceInstance);
});
......@@ -353,7 +362,6 @@ export class WorkbenchShell extends Disposable {
serviceCollection.set(IHashService, new SyncDescriptor(HashService));
// Telemetry
if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) {
const channel = getDelayedChannel<ITelemetryAppenderChannel>(sharedProcess.then(c => c.getChannel('telemetryAppender')));
const config: ITelemetryServiceConfig = {
......@@ -380,7 +388,11 @@ export class WorkbenchShell extends Disposable {
serviceCollection.set(IDialogService, instantiationService.createInstance(DialogService));
const lifecycleService = instantiationService.createInstance(LifecycleService);
this._register(lifecycleService.onShutdown(event => this.dispose(event.reason)));
this._register(lifecycleService.onShutdown(event => {
this._onShutdown.fire(event);
this.dispose(event.reason);
}));
serviceCollection.set(ILifecycleService, lifecycleService);
this.lifecycleService = lifecycleService;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册