Update to VS Code 1.52.1

This commit is contained in:
Asher
2021-02-09 16:08:37 +00:00
1351 changed files with 56560 additions and 38990 deletions

View File

@@ -5,7 +5,7 @@
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { IWorkspaceStorageChangeEvent, IStorageService, StorageScope, IWillSaveStateEvent, WillSaveStateReason, logStorage, IS_NEW_KEY } from 'vs/platform/storage/common/storage';
import { StorageScope, logStorage, IS_NEW_KEY, AbstractStorageService } from 'vs/platform/storage/common/storage';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces';
import { IFileService, FileChangeType } from 'vs/platform/files/common/files';
@@ -16,15 +16,7 @@ import { runWhenIdle, RunOnceScheduler } from 'vs/base/common/async';
import { VSBuffer } from 'vs/base/common/buffer';
import { assertIsDefined, assertAllDefined } from 'vs/base/common/types';
export class BrowserStorageService extends Disposable implements IStorageService {
declare readonly _serviceBrand: undefined;
private readonly _onDidChangeStorage = this._register(new Emitter<IWorkspaceStorageChangeEvent>());
readonly onDidChangeStorage = this._onDidChangeStorage.event;
private readonly _onWillSaveState = this._register(new Emitter<IWillSaveStateEvent>());
readonly onWillSaveState = this._onWillSaveState.event;
export class BrowserStorageService extends AbstractStorageService {
private globalStorage: IStorage | undefined;
private workspaceStorage: IStorage | undefined;
@@ -40,6 +32,10 @@ export class BrowserStorageService extends Disposable implements IStorageService
private readonly periodicFlushScheduler = this._register(new RunOnceScheduler(() => this.doFlushWhenIdle(), 5000 /* every 5s */));
private runWhenIdleDisposable: IDisposable | undefined = undefined;
get hasPendingUpdate(): boolean {
return (!!this.globalStorageDatabase && this.globalStorageDatabase.hasPendingUpdate) || (!!this.workspaceStorageDatabase && this.workspaceStorageDatabase.hasPendingUpdate);
}
constructor(
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IFileService private readonly fileService: IFileService
@@ -66,13 +62,13 @@ export class BrowserStorageService extends Disposable implements IStorageService
this.workspaceStorageDatabase = this._register(new FileStorageDatabase(this.workspaceStorageFile, false /* do not watch for external changes */, this.fileService));
this.workspaceStorage = this._register(new Storage(this.workspaceStorageDatabase));
this._register(this.workspaceStorage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key, scope: StorageScope.WORKSPACE })));
this._register(this.workspaceStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.WORKSPACE, key)));
// Global Storage
this.globalStorageFile = joinPath(stateRoot, 'global.json');
this.globalStorageDatabase = this._register(new FileStorageDatabase(this.globalStorageFile, true /* watch for external changes */, this.fileService));
this.globalStorage = this._register(new Storage(this.globalStorageDatabase));
this._register(this.globalStorage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key, scope: StorageScope.GLOBAL })));
this._register(this.globalStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.GLOBAL, key)));
// Init both
await Promise.all([
@@ -122,11 +118,16 @@ export class BrowserStorageService extends Disposable implements IStorageService
return this.getStorage(scope).getNumber(key, fallbackValue);
}
<<<<<<< HEAD
store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): Promise<void> {
return this.getStorage(scope).set(key, value);
=======
protected doStore(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): void {
this.getStorage(scope).set(key, value);
>>>>>>> e4a830e9b7ca039c7c70697786d29f5b6679d775
}
remove(key: string, scope: StorageScope): void {
protected doRemove(key: string, scope: StorageScope): void {
this.getStorage(scope).delete(key);
}
@@ -149,6 +150,13 @@ export class BrowserStorageService extends Disposable implements IStorageService
throw new Error('Migrating storage is currently unsupported in Web');
}
protected async doFlush(): Promise<void> {
await Promise.all([
this.getStorage(StorageScope.GLOBAL).whenFlushed(),
this.getStorage(StorageScope.WORKSPACE).whenFlushed()
]);
}
private doFlushWhenIdle(): void {
// Dispose any previous idle runner
@@ -175,14 +183,6 @@ export class BrowserStorageService extends Disposable implements IStorageService
});
}
get hasPendingUpdate(): boolean {
return (!!this.globalStorageDatabase && this.globalStorageDatabase.hasPendingUpdate) || (!!this.workspaceStorageDatabase && this.workspaceStorageDatabase.hasPendingUpdate);
}
flush(): void {
this._onWillSaveState.fire({ reason: WillSaveStateReason.NONE });
}
close(): void {
// We explicitly do not close our DBs because writing data onBeforeUnload()
// can result in unexpected results. Namely, it seems that - even though this
@@ -195,10 +195,6 @@ export class BrowserStorageService extends Disposable implements IStorageService
this.dispose();
}
isNew(scope: StorageScope): boolean {
return this.getBoolean(IS_NEW_KEY, scope) === true;
}
dispose(): void {
dispose(this.runWhenIdleDisposable);
this.runWhenIdleDisposable = undefined;

View File

@@ -4,18 +4,27 @@
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Event, Emitter } from 'vs/base/common/event';
import { Event, Emitter, PauseableEmitter } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces';
export const IS_NEW_KEY = '__$__isNewStorageMarker';
const TARGET_KEY = '__$__targetStorageMarker';
export const IStorageService = createDecorator<IStorageService>('storageService');
export enum WillSaveStateReason {
NONE = 0,
SHUTDOWN = 1
/**
* No specific reason to save state.
*/
NONE,
/**
* A hint that the workbench is about to shutdown.
*/
SHUTDOWN
}
export interface IWillSaveStateEvent {
@@ -29,7 +38,12 @@ export interface IStorageService {
/**
* Emitted whenever data is updated or deleted.
*/
readonly onDidChangeStorage: Event<IWorkspaceStorageChangeEvent>;
readonly onDidChangeValue: Event<IStorageValueChangeEvent>;
/**
* Emitted whenever target of a storage entry changes.
*/
readonly onDidChangeTarget: Event<IStorageTargetChangeEvent>;
/**
* Emitted when the storage is about to persist. This is the right time
@@ -48,44 +62,53 @@ export interface IStorageService {
/**
* Retrieve an element stored with the given key from storage. Use
* the provided defaultValue if the element is null or undefined.
* the provided `defaultValue` if the element is `null` or `undefined`.
*
* The scope argument allows to define the scope of the storage
* operation to either the current workspace only or all workspaces.
* @param scope allows to define the scope of the storage operation
* to either the current workspace only or all workspaces.
*/
get(key: string, scope: StorageScope, fallbackValue: string): string;
get(key: string, scope: StorageScope, fallbackValue?: string): string | undefined;
/**
* 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.
* the provided `defaultValue` if the element is `null` or `undefined`.
* The element will be converted to a `boolean`.
*
* The scope argument allows to define the scope of the storage
* operation to either the current workspace only or all workspaces.
* @param scope allows to define the scope of the storage operation
* to either the current workspace only or all workspaces.
*/
getBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean;
getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined;
/**
* 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.
* 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`.
*
* The scope argument allows to define the scope of the storage
* operation to either the current workspace only or all workspaces.
* @param scope allows to define the scope of the storage operation
* to either the current workspace only or all workspaces.
*/
getNumber(key: string, scope: StorageScope, fallbackValue: number): number;
getNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined;
/**
* Store a value under the given key to storage. The value will be converted to a string.
* Storing either undefined or null will remove the entry under the key.
* Store a value under the given key to storage. The value will be
* converted to a `string`. Storing either `undefined` or `null` will
* remove the entry under the key.
*
* The scope argument allows to define the scope of the storage
* operation to either the current workspace only or all workspaces.
* @param scope allows to define the scope of the storage operation
* to either the current workspace only or all workspaces.
*
* @param target allows to define the target of the storage operation
* to either the current machine or user.
*/
<<<<<<< HEAD
store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): Promise<void> | void;
=======
store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope, target: StorageTarget): void;
>>>>>>> e4a830e9b7ca039c7c70697786d29f5b6679d775
/**
* Delete an element stored under the provided key from storage.
@@ -95,6 +118,22 @@ export interface IStorageService {
*/
remove(key: string, scope: StorageScope): void;
/**
* Returns all the keys used in the storage for the provided `scope`
* and `target`.
*
* Note: this will NOT return all keys stored in the storage layer.
* Some keys may not have an associated `StorageTarget` and thus
* will be excluded from the results.
*
* @param scope allows to define the scope for the keys
* to either the current workspace only or all workspaces.
*
* @param target allows to define the target for the keys
* to either the current machine or user.
*/
keys(scope: StorageScope, target: StorageTarget): string[];
/**
* Log the contents of the storage to the console.
*/
@@ -108,16 +147,18 @@ export interface IStorageService {
/**
* Whether the storage for the given scope was created during this session or
* existed before.
*
*/
isNew(scope: StorageScope): boolean;
/**
* Allows to flush state, e.g. in cases where a shutdown is
* imminent. This will send out the onWillSaveState to ask
* imminent. This will send out the `onWillSaveState` to ask
* everyone for latest state.
*
* @returns a `Promise` that can be awaited on when all updates
* to the underlying storage have been flushed.
*/
flush(): void;
flush(): Promise<void>;
}
export const enum StorageScope {
@@ -133,21 +174,247 @@ export const enum StorageScope {
WORKSPACE
}
export interface IWorkspaceStorageChangeEvent {
export const enum StorageTarget {
/**
* The stored data is user specific and applies across machines.
*/
USER,
/**
* The stored data is machine specific.
*/
MACHINE
}
export interface IStorageValueChangeEvent {
/**
* The scope for the storage entry that changed
* or was removed.
*/
readonly scope: StorageScope;
/**
* The `key` of the storage entry that was changed
* or was removed.
*/
readonly key: string;
/**
* The `target` can be `undefined` if a key is being
* removed.
*/
readonly target: StorageTarget | undefined;
}
export interface IStorageTargetChangeEvent {
/**
* The scope for the target that changed. Listeners
* should use `keys(scope, target)` to get an updated
* list of keys for the given `scope` and `target`.
*/
readonly scope: StorageScope;
}
export class InMemoryStorageService extends Disposable implements IStorageService {
interface IKeyTargets {
[key: string]: StorageTarget
}
export abstract class AbstractStorageService extends Disposable implements IStorageService {
declare readonly _serviceBrand: undefined;
private readonly _onDidChangeStorage = this._register(new Emitter<IWorkspaceStorageChangeEvent>());
readonly onDidChangeStorage = this._onDidChangeStorage.event;
private readonly _onDidChangeValue = this._register(new PauseableEmitter<IStorageValueChangeEvent>());
readonly onDidChangeValue = this._onDidChangeValue.event;
protected readonly _onWillSaveState = this._register(new Emitter<IWillSaveStateEvent>());
private readonly _onDidChangeTarget = this._register(new PauseableEmitter<IStorageTargetChangeEvent>());
readonly onDidChangeTarget = this._onDidChangeTarget.event;
private readonly _onWillSaveState = this._register(new Emitter<IWillSaveStateEvent>());
readonly onWillSaveState = this._onWillSaveState.event;
protected emitDidChangeValue(scope: StorageScope, key: string): void {
// Specially handle `TARGET_KEY`
if (key === TARGET_KEY) {
// Clear our cached version which is now out of date
if (scope === StorageScope.GLOBAL) {
this._globalKeyTargets = undefined;
} else if (scope === StorageScope.WORKSPACE) {
this._workspaceKeyTargets = undefined;
}
// Emit as `didChangeTarget` event
this._onDidChangeTarget.fire({ scope });
}
// Emit any other key to outside
else {
this._onDidChangeValue.fire({ scope, key, target: this.getKeyTargets(scope)[key] });
}
}
protected emitWillSaveState(reason: WillSaveStateReason): void {
this._onWillSaveState.fire({ reason });
}
store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope, target: StorageTarget): void {
// We remove the key for undefined/null values
if (isUndefinedOrNull(value)) {
this.remove(key, scope);
return;
}
// Update our datastructures but send events only after
this.withPausedEmitters(() => {
// Update key-target map
this.updateKeyTarget(key, scope, target);
// Store actual value
this.doStore(key, value, scope);
});
}
remove(key: string, scope: StorageScope): void {
// Update our datastructures but send events only after
this.withPausedEmitters(() => {
// Update key-target map
this.updateKeyTarget(key, scope, undefined);
// Remove actual key
this.doRemove(key, scope);
});
}
private withPausedEmitters(fn: Function): void {
// Pause emitters
this._onDidChangeValue.pause();
this._onDidChangeTarget.pause();
try {
fn();
} finally {
// Resume emitters
this._onDidChangeValue.resume();
this._onDidChangeTarget.resume();
}
}
keys(scope: StorageScope, target: StorageTarget): string[] {
const keys: string[] = [];
const keyTargets = this.getKeyTargets(scope);
for (const key of Object.keys(keyTargets)) {
const keyTarget = keyTargets[key];
if (keyTarget === target) {
keys.push(key);
}
}
return keys;
}
private updateKeyTarget(key: string, scope: StorageScope, target: StorageTarget | undefined): void {
// Add
const keyTargets = this.getKeyTargets(scope);
if (typeof target === 'number') {
if (keyTargets[key] !== target) {
keyTargets[key] = target;
this.doStore(TARGET_KEY, JSON.stringify(keyTargets), scope);
}
}
// Remove
else {
if (typeof keyTargets[key] === 'number') {
delete keyTargets[key];
this.doStore(TARGET_KEY, JSON.stringify(keyTargets), scope);
}
}
}
private _workspaceKeyTargets: IKeyTargets | undefined = undefined;
private get workspaceKeyTargets(): IKeyTargets {
if (!this._workspaceKeyTargets) {
this._workspaceKeyTargets = this.loadKeyTargets(StorageScope.WORKSPACE);
}
return this._workspaceKeyTargets;
}
private _globalKeyTargets: IKeyTargets | undefined = undefined;
private get globalKeyTargets(): IKeyTargets {
if (!this._globalKeyTargets) {
this._globalKeyTargets = this.loadKeyTargets(StorageScope.GLOBAL);
}
return this._globalKeyTargets;
}
private getKeyTargets(scope: StorageScope): IKeyTargets {
return scope === StorageScope.GLOBAL ? this.globalKeyTargets : this.workspaceKeyTargets;
}
private loadKeyTargets(scope: StorageScope): { [key: string]: StorageTarget } {
const keysRaw = this.get(TARGET_KEY, scope);
if (keysRaw) {
try {
return JSON.parse(keysRaw);
} catch (error) {
// Fail gracefully
}
}
return Object.create(null);
}
isNew(scope: StorageScope): boolean {
return this.getBoolean(IS_NEW_KEY, scope) === true;
}
flush(): Promise<void> {
// Signal event to collect changes
this._onWillSaveState.fire({ reason: WillSaveStateReason.NONE });
// Await flush
return this.doFlush();
}
// --- abstract
abstract get(key: string, scope: StorageScope, fallbackValue: string): string;
abstract get(key: string, scope: StorageScope, fallbackValue?: string): string | undefined;
abstract getBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean;
abstract getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined;
abstract getNumber(key: string, scope: StorageScope, fallbackValue: number): number;
abstract getNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined;
protected abstract doStore(key: string, value: string | boolean | number, scope: StorageScope): void;
protected abstract doRemove(key: string, scope: StorageScope): void;
protected abstract doFlush(): Promise<void>;
abstract migrate(toWorkspace: IWorkspaceInitializationPayload): Promise<void>;
abstract logStorage(): void;
}
export class InMemoryStorageService extends AbstractStorageService {
private readonly globalCache = new Map<string, string>();
private readonly workspaceCache = new Map<string, string>();
@@ -188,12 +455,7 @@ export class InMemoryStorageService extends Disposable implements IStorageServic
return parseInt(value, 10);
}
store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): Promise<void> {
// We remove the key for undefined/null values
if (isUndefinedOrNull(value)) {
return this.remove(key, scope);
}
protected doStore(key: string, value: string | boolean | number, scope: StorageScope): void {
// Otherwise, convert to String and store
const valueStr = String(value);
@@ -201,28 +463,24 @@ export class InMemoryStorageService extends Disposable implements IStorageServic
// Return early if value already set
const currentValue = this.getCache(scope).get(key);
if (currentValue === valueStr) {
return Promise.resolve();
return;
}
// Update in cache
this.getCache(scope).set(key, valueStr);
// Events
this._onDidChangeStorage.fire({ scope, key });
return Promise.resolve();
this.emitDidChangeValue(scope, key);
}
remove(key: string, scope: StorageScope): Promise<void> {
protected doRemove(key: string, scope: StorageScope): void {
const wasDeleted = this.getCache(scope).delete(key);
if (!wasDeleted) {
return Promise.resolve(); // Return early if value already deleted
return; // Return early if value already deleted
}
// Events
this._onDidChangeStorage.fire({ scope, key });
return Promise.resolve();
this.emitDidChangeValue(scope, key);
}
logStorage(): void {
@@ -233,13 +491,7 @@ export class InMemoryStorageService extends Disposable implements IStorageServic
// not supported
}
flush(): void {
this._onWillSaveState.fire({ reason: WillSaveStateReason.NONE });
}
isNew(): boolean {
return true; // always new when in-memory
}
async doFlush(): Promise<void> { }
async close(): Promise<void> { }
}

View File

@@ -3,10 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
import { IWorkspaceStorageChangeEvent, IStorageService, StorageScope, IWillSaveStateEvent, WillSaveStateReason, logStorage, IS_NEW_KEY } from 'vs/platform/storage/common/storage';
import { StorageScope, WillSaveStateReason, logStorage, IS_NEW_KEY, AbstractStorageService } from 'vs/platform/storage/common/storage';
import { SQLiteStorageDatabase, ISQLiteStorageDatabaseLoggingOptions } from 'vs/base/parts/storage/node/storage';
import { Storage, IStorageDatabase, IStorage, StorageHint } from 'vs/base/parts/storage/common/storage';
import { mark } from 'vs/base/common/performance';
@@ -17,19 +16,11 @@ import { IWorkspaceInitializationPayload, isWorkspaceIdentifier, isSingleFolderW
import { assertIsDefined } from 'vs/base/common/types';
import { RunOnceScheduler, runWhenIdle } from 'vs/base/common/async';
export class NativeStorageService extends Disposable implements IStorageService {
declare readonly _serviceBrand: undefined;
export class NativeStorageService extends AbstractStorageService {
private static readonly WORKSPACE_STORAGE_NAME = 'state.vscdb';
private static readonly WORKSPACE_META_NAME = 'workspace.json';
private readonly _onDidChangeStorage = this._register(new Emitter<IWorkspaceStorageChangeEvent>());
readonly onDidChangeStorage = this._onDidChangeStorage.event;
private readonly _onWillSaveState = this._register(new Emitter<IWillSaveStateEvent>());
readonly onWillSaveState = this._onWillSaveState.event;
private readonly globalStorage = new Storage(this.globalStorageDatabase);
private workspaceStoragePath: string | undefined;
@@ -54,11 +45,7 @@ export class NativeStorageService extends Disposable implements IStorageService
private registerListeners(): void {
// Global Storage change events
this._register(this.globalStorage.onDidChangeStorage(key => this.handleDidChangeStorage(key, StorageScope.GLOBAL)));
}
private handleDidChangeStorage(key: string, scope: StorageScope): void {
this._onDidChangeStorage.fire({ key, scope });
this._register(this.globalStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.GLOBAL, key)));
}
initialize(payload?: IWorkspaceInitializationPayload): Promise<void> {
@@ -134,7 +121,7 @@ export class NativeStorageService extends Disposable implements IStorageService
// Create new
this.workspaceStoragePath = workspaceStoragePath;
this.workspaceStorage = new Storage(new SQLiteStorageDatabase(workspaceStoragePath, { logging: workspaceLoggingOptions }), { hint });
this.workspaceStorageListener = this.workspaceStorage.onDidChangeStorage(key => this.handleDidChangeStorage(key, StorageScope.WORKSPACE));
this.workspaceStorageListener = this.workspaceStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.WORKSPACE, key));
return this.workspaceStorage;
}
@@ -201,11 +188,16 @@ export class NativeStorageService extends Disposable implements IStorageService
return this.getStorage(scope).getNumber(key, fallbackValue);
}
<<<<<<< HEAD
store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): Promise<void> {
return this.getStorage(scope).set(key, value);
=======
protected doStore(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): void {
this.getStorage(scope).set(key, value);
>>>>>>> e4a830e9b7ca039c7c70697786d29f5b6679d775
}
remove(key: string, scope: StorageScope): void {
protected doRemove(key: string, scope: StorageScope): void {
this.getStorage(scope).delete(key);
}
@@ -213,6 +205,19 @@ export class NativeStorageService extends Disposable implements IStorageService
return assertIsDefined(scope === StorageScope.GLOBAL ? this.globalStorage : this.workspaceStorage);
}
protected async doFlush(): Promise<void> {
const promises: Promise<unknown>[] = [];
if (this.globalStorage) {
promises.push(this.globalStorage.whenFlushed());
}
if (this.workspaceStorage) {
promises.push(this.workspaceStorage.whenFlushed());
}
await Promise.all(promises);
}
private doFlushWhenIdle(): void {
// Dispose any previous idle runner
@@ -229,10 +234,6 @@ export class NativeStorageService extends Disposable implements IStorageService
});
}
flush(): void {
this._onWillSaveState.fire({ reason: WillSaveStateReason.NONE });
}
async close(): Promise<void> {
// Stop periodic scheduler and idle runner as we now collect state normally
@@ -241,7 +242,7 @@ export class NativeStorageService extends Disposable implements IStorageService
this.runWhenIdleDisposable = undefined;
// Signal as event so that clients can still store data
this._onWillSaveState.fire({ reason: WillSaveStateReason.SHUTDOWN });
this.emitWillSaveState(WillSaveStateReason.SHUTDOWN);
// Do it
await Promise.all([
@@ -277,8 +278,4 @@ export class NativeStorageService extends Disposable implements IStorageService
// Recreate and init workspace storage
return this.createWorkspaceStorage(newWorkspaceStoragePath).init();
}
isNew(scope: StorageScope): boolean {
return this.getBoolean(IS_NEW_KEY, scope) === true;
}
}

View File

@@ -0,0 +1,198 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { strictEqual, ok, equal } from 'assert';
import { StorageScope, InMemoryStorageService, StorageTarget, IStorageValueChangeEvent, IStorageTargetChangeEvent } from 'vs/platform/storage/common/storage';
suite('StorageService', function () {
test('Get Data, Integer, Boolean (global, in-memory)', () => {
storeData(StorageScope.GLOBAL);
});
test('Get Data, Integer, Boolean (workspace, in-memory)', () => {
storeData(StorageScope.WORKSPACE);
});
function storeData(scope: StorageScope): void {
const storage = new InMemoryStorageService();
let storageValueChangeEvents: IStorageValueChangeEvent[] = [];
storage.onDidChangeValue(e => storageValueChangeEvents.push(e));
strictEqual(storage.get('test.get', scope, 'foobar'), 'foobar');
strictEqual(storage.get('test.get', scope, ''), '');
strictEqual(storage.getNumber('test.getNumber', scope, 5), 5);
strictEqual(storage.getNumber('test.getNumber', scope, 0), 0);
strictEqual(storage.getBoolean('test.getBoolean', scope, true), true);
strictEqual(storage.getBoolean('test.getBoolean', scope, false), false);
storage.store('test.get', 'foobar', scope, StorageTarget.MACHINE);
strictEqual(storage.get('test.get', scope, (undefined)!), 'foobar');
let storageValueChangeEvent = storageValueChangeEvents.find(e => e.key === 'test.get');
equal(storageValueChangeEvent?.scope, scope);
equal(storageValueChangeEvent?.key, 'test.get');
storageValueChangeEvents = [];
storage.store('test.get', '', scope, StorageTarget.MACHINE);
strictEqual(storage.get('test.get', scope, (undefined)!), '');
storageValueChangeEvent = storageValueChangeEvents.find(e => e.key === 'test.get');
equal(storageValueChangeEvent!.scope, scope);
equal(storageValueChangeEvent!.key, 'test.get');
storage.store('test.getNumber', 5, scope, StorageTarget.MACHINE);
strictEqual(storage.getNumber('test.getNumber', scope, (undefined)!), 5);
storage.store('test.getNumber', 0, scope, StorageTarget.MACHINE);
strictEqual(storage.getNumber('test.getNumber', scope, (undefined)!), 0);
storage.store('test.getBoolean', true, scope, StorageTarget.MACHINE);
strictEqual(storage.getBoolean('test.getBoolean', scope, (undefined)!), true);
storage.store('test.getBoolean', false, scope, StorageTarget.MACHINE);
strictEqual(storage.getBoolean('test.getBoolean', scope, (undefined)!), false);
strictEqual(storage.get('test.getDefault', scope, 'getDefault'), 'getDefault');
strictEqual(storage.getNumber('test.getNumberDefault', scope, 5), 5);
strictEqual(storage.getBoolean('test.getBooleanDefault', scope, true), true);
}
test('Remove Data (global, in-memory)', () => {
removeData(StorageScope.GLOBAL);
});
test('Remove Data (workspace, in-memory)', () => {
removeData(StorageScope.WORKSPACE);
});
function removeData(scope: StorageScope): void {
const storage = new InMemoryStorageService();
let storageValueChangeEvents: IStorageValueChangeEvent[] = [];
storage.onDidChangeValue(e => storageValueChangeEvents.push(e));
storage.store('test.remove', 'foobar', scope, StorageTarget.MACHINE);
strictEqual('foobar', storage.get('test.remove', scope, (undefined)!));
storage.remove('test.remove', scope);
ok(!storage.get('test.remove', scope, (undefined)!));
let storageValueChangeEvent = storageValueChangeEvents.find(e => e.key === 'test.remove');
equal(storageValueChangeEvent?.scope, scope);
equal(storageValueChangeEvent?.key, 'test.remove');
}
test('Keys (in-memory)', () => {
const storage = new InMemoryStorageService();
let storageTargetEvent: IStorageTargetChangeEvent | undefined = undefined;
storage.onDidChangeTarget(e => storageTargetEvent = e);
let storageValueChangeEvent: IStorageValueChangeEvent | undefined = undefined;
storage.onDidChangeValue(e => storageValueChangeEvent = e);
// Empty
for (const scope of [StorageScope.WORKSPACE, StorageScope.GLOBAL]) {
for (const target of [StorageTarget.MACHINE, StorageTarget.USER]) {
strictEqual(storage.keys(scope, target).length, 0);
}
}
// Add values
for (const scope of [StorageScope.WORKSPACE, StorageScope.GLOBAL]) {
for (const target of [StorageTarget.MACHINE, StorageTarget.USER]) {
storageTargetEvent = Object.create(null);
storageValueChangeEvent = Object.create(null);
storage.store('test.target1', 'value1', scope, target);
strictEqual(storage.keys(scope, target).length, 1);
equal(storageTargetEvent?.scope, scope);
equal(storageValueChangeEvent?.key, 'test.target1');
equal(storageValueChangeEvent?.scope, scope);
equal(storageValueChangeEvent?.target, target);
storageTargetEvent = undefined;
storageValueChangeEvent = Object.create(null);
storage.store('test.target1', 'otherValue1', scope, target);
strictEqual(storage.keys(scope, target).length, 1);
equal(storageTargetEvent, undefined);
equal(storageValueChangeEvent?.key, 'test.target1');
equal(storageValueChangeEvent?.scope, scope);
equal(storageValueChangeEvent?.target, target);
storage.store('test.target2', 'value2', scope, target);
storage.store('test.target3', 'value3', scope, target);
strictEqual(storage.keys(scope, target).length, 3);
}
}
// Remove values
for (const scope of [StorageScope.WORKSPACE, StorageScope.GLOBAL]) {
for (const target of [StorageTarget.MACHINE, StorageTarget.USER]) {
const keysLength = storage.keys(scope, target).length;
storage.store('test.target4', 'value1', scope, target);
strictEqual(storage.keys(scope, target).length, keysLength + 1);
storageTargetEvent = Object.create(null);
storageValueChangeEvent = Object.create(null);
storage.remove('test.target4', scope);
strictEqual(storage.keys(scope, target).length, keysLength);
equal(storageTargetEvent?.scope, scope);
equal(storageValueChangeEvent?.key, 'test.target4');
equal(storageValueChangeEvent?.scope, scope);
}
}
// Remove all
for (const scope of [StorageScope.WORKSPACE, StorageScope.GLOBAL]) {
for (const target of [StorageTarget.MACHINE, StorageTarget.USER]) {
const keys = storage.keys(scope, target);
for (const key of keys) {
storage.remove(key, scope);
}
strictEqual(storage.keys(scope, target).length, 0);
}
}
// Adding undefined or null removes value
for (const scope of [StorageScope.WORKSPACE, StorageScope.GLOBAL]) {
for (const target of [StorageTarget.MACHINE, StorageTarget.USER]) {
storage.store('test.target1', 'value1', scope, target);
strictEqual(storage.keys(scope, target).length, 1);
storageTargetEvent = Object.create(null);
storage.store('test.target1', undefined, scope, target);
strictEqual(storage.keys(scope, target).length, 0);
equal(storageTargetEvent?.scope, scope);
storage.store('test.target1', '', scope, target);
strictEqual(storage.keys(scope, target).length, 1);
storage.store('test.target1', null, scope, target);
strictEqual(storage.keys(scope, target).length, 0);
}
}
// Target change
storageTargetEvent = undefined;
storage.store('test.target5', 'value1', StorageScope.GLOBAL, StorageTarget.MACHINE);
ok(storageTargetEvent);
storageTargetEvent = undefined;
storage.store('test.target5', 'value1', StorageScope.GLOBAL, StorageTarget.USER);
ok(storageTargetEvent);
storageTargetEvent = undefined;
storage.store('test.target5', 'value1', StorageScope.GLOBAL, StorageTarget.MACHINE);
ok(storageTargetEvent);
storageTargetEvent = undefined;
storage.store('test.target5', 'value1', StorageScope.GLOBAL, StorageTarget.MACHINE);
ok(!storageTargetEvent); // no change in target
});
});

View File

@@ -3,8 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { strictEqual, ok, equal } from 'assert';
import { StorageScope, InMemoryStorageService } from 'vs/platform/storage/common/storage';
import { equal } from 'assert';
import { StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { NativeStorageService } from 'vs/platform/storage/node/storageService';
import { generateUuid } from 'vs/base/common/uuid';
import { join } from 'vs/base/common/path';
@@ -16,66 +16,7 @@ import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv';
import { InMemoryStorageDatabase } from 'vs/base/parts/storage/common/storage';
import { URI } from 'vs/base/common/uri';
suite('StorageService', function () {
test('Remove Data (global, in-memory)', () => {
removeData(StorageScope.GLOBAL);
});
test('Remove Data (workspace, in-memory)', () => {
removeData(StorageScope.WORKSPACE);
});
function removeData(scope: StorageScope): void {
const storage = new InMemoryStorageService();
storage.store('test.remove', 'foobar', scope);
strictEqual('foobar', storage.get('test.remove', scope, (undefined)!));
storage.remove('test.remove', scope);
ok(!storage.get('test.remove', scope, (undefined)!));
}
test('Get Data, Integer, Boolean (global, in-memory)', () => {
storeData(StorageScope.GLOBAL);
});
test('Get Data, Integer, Boolean (workspace, in-memory)', () => {
storeData(StorageScope.WORKSPACE);
});
function storeData(scope: StorageScope): void {
const storage = new InMemoryStorageService();
strictEqual(storage.get('test.get', scope, 'foobar'), 'foobar');
strictEqual(storage.get('test.get', scope, ''), '');
strictEqual(storage.getNumber('test.getNumber', scope, 5), 5);
strictEqual(storage.getNumber('test.getNumber', scope, 0), 0);
strictEqual(storage.getBoolean('test.getBoolean', scope, true), true);
strictEqual(storage.getBoolean('test.getBoolean', scope, false), false);
storage.store('test.get', 'foobar', scope);
strictEqual(storage.get('test.get', scope, (undefined)!), 'foobar');
storage.store('test.get', '', scope);
strictEqual(storage.get('test.get', scope, (undefined)!), '');
storage.store('test.getNumber', 5, scope);
strictEqual(storage.getNumber('test.getNumber', scope, (undefined)!), 5);
storage.store('test.getNumber', 0, scope);
strictEqual(storage.getNumber('test.getNumber', scope, (undefined)!), 0);
storage.store('test.getBoolean', true, scope);
strictEqual(storage.getBoolean('test.getBoolean', scope, (undefined)!), true);
storage.store('test.getBoolean', false, scope);
strictEqual(storage.getBoolean('test.getBoolean', scope, (undefined)!), false);
strictEqual(storage.get('test.getDefault', scope, 'getDefault'), 'getDefault');
strictEqual(storage.getNumber('test.getNumberDefault', scope, 5), 5);
strictEqual(storage.getBoolean('test.getBooleanDefault', scope, true), true);
}
suite('NativeStorageService', function () {
function uniqueStorageDir(): string {
const id = generateUuid();
@@ -111,9 +52,13 @@ suite('StorageService', function () {
const storage = new NativeStorageService(new InMemoryStorageDatabase(), new NullLogService(), new StorageTestEnvironmentService(URI.file(storageDir), storageDir));
await storage.initialize({ id: String(Date.now()) });
storage.store('bar', 'foo', StorageScope.WORKSPACE);
storage.store('barNumber', 55, StorageScope.WORKSPACE);
storage.store('barBoolean', true, StorageScope.GLOBAL);
storage.store('bar', 'foo', StorageScope.WORKSPACE, StorageTarget.MACHINE);
storage.store('barNumber', 55, StorageScope.WORKSPACE, StorageTarget.MACHINE);
storage.store('barBoolean', true, StorageScope.GLOBAL, StorageTarget.MACHINE);
equal(storage.get('bar', StorageScope.WORKSPACE), 'foo');
equal(storage.getNumber('barNumber', StorageScope.WORKSPACE), 55);
equal(storage.getBoolean('barBoolean', StorageScope.GLOBAL), true);
await storage.migrate({ id: String(Date.now() + 100) });