Merge from vscode 5b9869eb02fa4c96205a74d05cad9164dfd06d60 (#5607)

This commit is contained in:
Anthony Dresser
2019-05-24 12:20:30 -07:00
committed by GitHub
parent 361ada4963
commit bcc449b524
126 changed files with 3096 additions and 2255 deletions

View File

@@ -100,6 +100,10 @@ export const enum MenuId {
NotebookToolbar,
DataExplorerContext,
DataExplorerAction,
CommentThreadTitle,
CommentThreadActions,
CommentTitle,
CommentActions
}
export interface IMenuActionOptions {

View File

@@ -8,7 +8,7 @@ import * as path from 'vs/base/common/path';
import * as pfs from 'vs/base/node/pfs';
import { assign } from 'vs/base/common/objects';
import { toDisposable, Disposable } from 'vs/base/common/lifecycle';
import { flatten } from 'vs/base/common/arrays';
import { flatten, isNonEmptyArray } from 'vs/base/common/arrays';
import { extract, ExtractError, zip, IFile } from 'vs/base/node/zip';
import {
IExtensionManagementService, IExtensionGalleryService, ILocalExtension,
@@ -44,9 +44,7 @@ import { Schemas } from 'vs/base/common/network';
import { CancellationToken } from 'vs/base/common/cancellation';
import { getPathFromAmdModule } from 'vs/base/common/amd';
import { getManifest } from 'vs/platform/extensionManagement/node/extensionManagementUtil';
import { IExtensionManifest, ExtensionType, ExtensionIdentifierWithVersion, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { isUIExtension } from 'vs/platform/extensions/node/extensionsUtil';
import { IExtensionManifest, ExtensionType, ExtensionIdentifierWithVersion } from 'vs/platform/extensions/common/extensions';
// {{SQL CARBON EDIT}
import product from 'vs/platform/product/node/product';
@@ -132,9 +130,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
onDidUninstallExtension: Event<DidUninstallExtensionEvent> = this._onDidUninstallExtension.event;
constructor(
private readonly remote: boolean,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IExtensionGalleryService private readonly galleryService: IExtensionGalleryService,
@ILogService private readonly logService: ILogService,
@optional(IDownloadService) private downloadService: IDownloadService,
@@ -270,7 +266,18 @@ export class ExtensionManagementService extends Disposable implements IExtension
private installFromZipPath(identifierWithVersion: ExtensionIdentifierWithVersion, zipPath: string, metadata: IGalleryMetadata | null, type: ExtensionType, operation: InstallOperation, token: CancellationToken): Promise<ILocalExtension> {
return this.toNonCancellablePromise(this.installExtension({ zipPath, identifierWithVersion, metadata }, type, token)
.then(local => this.installDependenciesAndPackExtensions(local, null).then(() => local, error => this.uninstall(local, true).then(() => Promise.reject(error), () => Promise.reject(error))))
.then(local => this.installDependenciesAndPackExtensions(local, null)
.then(
() => local,
error => {
if (isNonEmptyArray(local.manifest.extensionDependencies)) {
this.logService.warn(`Cannot install dependencies of extension:`, local.identifier.id, error.message);
}
if (isNonEmptyArray(local.manifest.extensionPack)) {
this.logService.warn(`Cannot install packed extensions of extension:`, local.identifier.id, error.message);
}
return local;
}))
.then(
local => { this._onDidInstallExtension.fire({ identifier: identifierWithVersion.identifier, zipPath, local, operation }); return local; },
error => { this._onDidInstallExtension.fire({ identifier: identifierWithVersion.identifier, zipPath, operation, error }); return Promise.reject(error); }
@@ -526,16 +533,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
return this.galleryService.query({ names, pageSize: dependenciesAndPackExtensions.length }, CancellationToken.None)
.then(galleryResult => {
const extensionsToInstall = galleryResult.firstPage;
return Promise.all(extensionsToInstall.map(async e => {
if (this.remote) {
const manifest = await this.galleryService.getManifest(e, CancellationToken.None);
if (manifest && isUIExtension(manifest, [], this.configurationService) && !isLanguagePackExtension(manifest)) {
this.logService.info('Ignored installing the UI dependency', e.identifier.id);
return;
}
}
return this.installFromGallery(e);
}))
return Promise.all(extensionsToInstall.map(e => this.installFromGallery(e)))
.then(() => null, errors => this.rollback(extensionsToInstall).then(() => Promise.reject(errors), () => Promise.reject(errors)));
});
}

View File

@@ -1,51 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
import { getGalleryExtensionId, areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import product from 'vs/platform/product/node/product';
export function isUIExtension(manifest: IExtensionManifest, uiContributions: string[], configurationService: IConfigurationService): boolean {
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
const extensionKind = getExtensionKind(manifest, configurationService);
switch (extensionKind) {
case 'ui': return true;
case 'workspace': return false;
default: {
// Tagged as UI extension in product
if (isNonEmptyArray(product.uiExtensions) && product.uiExtensions.some(id => areSameExtensions({ id }, { id: extensionId }))) {
return true;
}
// Not an UI extension if it has main
if (manifest.main) {
return false;
}
// Not an UI extension if it has dependencies or an extension pack
if (isNonEmptyArray(manifest.extensionDependencies) || isNonEmptyArray(manifest.extensionPack)) {
return false;
}
if (manifest.contributes) {
// Not an UI extension if it has no ui contributions
if (!uiContributions.length || Object.keys(manifest.contributes).some(contribution => uiContributions.indexOf(contribution) === -1)) {
return false;
}
}
return true;
}
}
}
function getExtensionKind(manifest: IExtensionManifest, configurationService: IConfigurationService): string | undefined {
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
const configuredExtensionKinds = configurationService.getValue<{ [key: string]: string }>('remote.extensionKind') || {};
for (const id of Object.keys(configuredExtensionKinds)) {
if (areSameExtensions({ id: extensionId }, { id })) {
return configuredExtensionKinds[id];
}
}
return manifest.extensionKind;
}

View File

@@ -75,6 +75,23 @@ export class IssueService implements IIssueService {
event.sender.send('vscode:listProcessesResponse', processes);
});
ipcMain.on('vscode:issueReporterClipboard', (event: Event) => {
const messageOptions = {
message: localize('issueReporterWriteToClipboard', "There is too much data to send to GitHub. Would you like to write the information to the clipboard so that it can be pasted?"),
type: 'warning',
buttons: [
localize('yes', "Yes"),
localize('cancel', "Cancel")
]
};
if (this._issueWindow) {
dialog.showMessageBox(this._issueWindow, messageOptions, response => {
event.sender.send('vscode:issueReporterClipboardResponse', response === 0);
});
}
});
ipcMain.on('vscode:issuePerformanceInfoRequest', (event: Event) => {
this.getPerformanceInfo().then(msg => {
event.sender.send('vscode:issuePerformanceInfoResponse', msg);

View File

@@ -58,9 +58,9 @@ export abstract class AbstractLifecycleService extends Disposable implements ILi
}
}
when(phase: LifecyclePhase): Promise<void> {
async when(phase: LifecyclePhase): Promise<void> {
if (phase <= this._phase) {
return Promise.resolve();
return;
}
let barrier = this.phaseWhen.get(phase);
@@ -69,6 +69,6 @@ export abstract class AbstractLifecycleService extends Disposable implements ILi
this.phaseWhen.set(phase, barrier);
}
return barrier.wait().then(undefined);
await barrier.wait();
}
}

View File

@@ -75,18 +75,17 @@ export class LifecycleService extends AbstractLifecycleService {
});
// Main side indicates that we will indeed shutdown
ipc.on('vscode:onWillUnload', (_event: unknown, reply: { replyChannel: string, reason: ShutdownReason }) => {
ipc.on('vscode:onWillUnload', async (_event: unknown, reply: { replyChannel: string, reason: ShutdownReason }) => {
this.logService.trace(`lifecycle: onWillUnload (reason: ${reply.reason})`);
// trigger onWillShutdown events and joining
return this.handleWillShutdown(reply.reason).then(() => {
await this.handleWillShutdown(reply.reason);
// trigger onShutdown event now that we know we will quit
this._onShutdown.fire();
// trigger onShutdown event now that we know we will quit
this._onShutdown.fire();
// acknowledge to main side
ipc.send(reply.replyChannel, windowId);
});
// acknowledge to main side
ipc.send(reply.replyChannel, windowId);
});
// Save shutdown reason to retrieve on next startup
@@ -111,7 +110,7 @@ export class LifecycleService extends AbstractLifecycleService {
});
}
private handleWillShutdown(reason: ShutdownReason): Promise<void> {
private async handleWillShutdown(reason: ShutdownReason): Promise<void> {
const joiners: Promise<void>[] = [];
this._onWillShutdown.fire({
@@ -123,9 +122,11 @@ export class LifecycleService extends AbstractLifecycleService {
reason
});
return Promise.all(joiners).then(() => undefined, err => {
this.notificationService.error(toErrorMessage(err));
onUnexpectedError(err);
});
try {
await Promise.all(joiners);
} catch (error) {
this.notificationService.error(toErrorMessage(error));
onUnexpectedError(error);
}
}
}

View File

@@ -291,7 +291,7 @@ export class LifecycleService extends Disposable implements ILifecycleService {
});
}
unload(window: ICodeWindow, reason: UnloadReason): Promise<boolean /* veto */> {
async unload(window: ICodeWindow, reason: UnloadReason): Promise<boolean /* veto */> {
// Always allow to unload a window that is not yet ready
if (!window.isReady) {
@@ -302,27 +302,27 @@ export class LifecycleService extends Disposable implements ILifecycleService {
// first ask the window itself if it vetos the unload
const windowUnloadReason = this._quitRequested ? UnloadReason.QUIT : reason;
return this.onBeforeUnloadWindowInRenderer(window, windowUnloadReason).then(veto => {
if (veto) {
this.logService.trace(`Lifecycle#unload() - veto in renderer (window ID ${window.id})`);
let veto = await this.onBeforeUnloadWindowInRenderer(window, windowUnloadReason);
if (veto) {
this.logService.trace(`Lifecycle#unload() - veto in renderer (window ID ${window.id})`);
return this.handleWindowUnloadVeto(veto);
}
return this.handleWindowUnloadVeto(veto);
}
// then check for vetos in the main side
return this.onBeforeUnloadWindowInMain(window, windowUnloadReason).then(veto => {
if (veto) {
this.logService.trace(`Lifecycle#unload() - veto in main (window ID ${window.id})`);
// then check for vetos in the main side
veto = await this.onBeforeUnloadWindowInMain(window, windowUnloadReason);
if (veto) {
this.logService.trace(`Lifecycle#unload() - veto in main (window ID ${window.id})`);
return this.handleWindowUnloadVeto(veto);
}
return this.handleWindowUnloadVeto(veto);
}
this.logService.trace(`Lifecycle#unload() - no veto (window ID ${window.id})`);
this.logService.trace(`Lifecycle#unload() - no veto (window ID ${window.id})`);
// finally if there are no vetos, unload the renderer
return this.onWillUnloadWindowInRenderer(window, windowUnloadReason).then(() => false);
});
});
// finally if there are no vetos, unload the renderer
await this.onWillUnloadWindowInRenderer(window, windowUnloadReason);
return false;
}
private handleWindowUnloadVeto(veto: boolean): boolean {

View File

@@ -26,21 +26,23 @@ export class FileStorage {
return this._database;
}
init(): Promise<void> {
return readFile(this.dbPath).then(contents => {
async init(): Promise<void> {
try {
const contents = await readFile(this.dbPath);
try {
this.lastFlushedSerializedDatabase = contents.toString();
this._database = JSON.parse(this.lastFlushedSerializedDatabase);
} catch (error) {
this._database = {};
}
}, error => {
} catch (error) {
if (error.code !== 'ENOENT') {
this.onError(error);
}
this._database = {};
});
}
}
private loadSync(): object {

View File

@@ -14,38 +14,37 @@ suite('StateService', () => {
const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'stateservice');
const storageFile = path.join(parentDir, 'storage.json');
teardown(done => {
rimraf(parentDir, RimRafMode.MOVE).then(done, done);
teardown(async () => {
await rimraf(parentDir, RimRafMode.MOVE);
});
test('Basics', () => {
return mkdirp(parentDir).then(() => {
writeFileSync(storageFile, '');
test('Basics', async () => {
await mkdirp(parentDir);
writeFileSync(storageFile, '');
let service = new FileStorage(storageFile, () => null);
let service = new FileStorage(storageFile, () => null);
service.setItem('some.key', 'some.value');
assert.equal(service.getItem('some.key'), 'some.value');
service.setItem('some.key', 'some.value');
assert.equal(service.getItem('some.key'), 'some.value');
service.removeItem('some.key');
assert.equal(service.getItem('some.key', 'some.default'), 'some.default');
service.removeItem('some.key');
assert.equal(service.getItem('some.key', 'some.default'), 'some.default');
assert.ok(!service.getItem('some.unknonw.key'));
assert.ok(!service.getItem('some.unknonw.key'));
service.setItem('some.other.key', 'some.other.value');
service.setItem('some.other.key', 'some.other.value');
service = new FileStorage(storageFile, () => null);
service = new FileStorage(storageFile, () => null);
assert.equal(service.getItem('some.other.key'), 'some.other.value');
assert.equal(service.getItem('some.other.key'), 'some.other.value');
service.setItem('some.other.key', 'some.other.value');
assert.equal(service.getItem('some.other.key'), 'some.other.value');
service.setItem('some.other.key', 'some.other.value');
assert.equal(service.getItem('some.other.key'), 'some.other.value');
service.setItem('some.undefined.key', undefined);
assert.equal(service.getItem('some.undefined.key', 'some.default'), 'some.default');
service.setItem('some.undefined.key', undefined);
assert.equal(service.getItem('some.undefined.key', 'some.default'), 'some.default');
service.setItem('some.null.key', null);
assert.equal(service.getItem('some.null.key', 'some.default'), 'some.default');
});
service.setItem('some.null.key', null);
assert.equal(service.getItem('some.null.key', 'some.default'), 'some.default');
});
});

View File

@@ -45,20 +45,21 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC
this.whenReady = this.init();
}
private init(): Promise<void> {
return this.storageMainService.initialize().then(undefined, error => {
private async init(): Promise<void> {
try {
await this.storageMainService.initialize();
} catch (error) {
onUnexpectedError(error);
this.logService.error(error);
}).then(() => {
}
// Apply global telemetry values as part of the initialization
// These are global across all windows and thereby should be
// written from the main process once.
this.initTelemetry();
// Apply global telemetry values as part of the initialization
// These are global across all windows and thereby should be
// written from the main process once.
this.initTelemetry();
// Setup storage change listeners
this.registerListeners();
});
// Setup storage change listeners
this.registerListeners();
}
private initTelemetry(): void {
@@ -112,33 +113,39 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC
throw new Error(`Event not found: ${event}`);
}
call(_: unknown, command: string, arg?: any): Promise<any> {
async call(_: unknown, command: string, arg?: any): Promise<any> {
// ensure to always wait for ready
await this.whenReady;
// handle call
switch (command) {
case 'getItems': {
return this.whenReady.then(() => mapToSerializable(this.storageMainService.items));
return mapToSerializable(this.storageMainService.items);
}
case 'updateItems': {
return this.whenReady.then(() => {
const items: ISerializableUpdateRequest = arg;
if (items.insert) {
for (const [key, value] of items.insert) {
this.storageMainService.store(key, value);
}
const items: ISerializableUpdateRequest = arg;
if (items.insert) {
for (const [key, value] of items.insert) {
this.storageMainService.store(key, value);
}
}
if (items.delete) {
items.delete.forEach(key => this.storageMainService.remove(key));
}
});
if (items.delete) {
items.delete.forEach(key => this.storageMainService.remove(key));
}
break;
}
case 'checkIntegrity': {
return this.whenReady.then(() => this.storageMainService.checkIntegrity(arg));
return this.storageMainService.checkIntegrity(arg);
}
}
throw new Error(`Call not found: ${command}`);
default:
throw new Error(`Call not found: ${command}`);
}
}
}
@@ -167,8 +174,10 @@ export class GlobalStorageDatabaseChannelClient extends Disposable implements IS
}
}
getItems(): Promise<Map<string, string>> {
return this.channel.call('getItems').then((data: Item[]) => serializableToMap(data));
async getItems(): Promise<Map<string, string>> {
const items: Item[] = await this.channel.call('getItems');
return serializableToMap(items);
}
updateItems(request: IUpdateRequest): Promise<void> {

View File

@@ -10,7 +10,6 @@ import { ILogService, LogLevel } from 'vs/platform/log/common/log';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IStorage, Storage, SQLiteStorageDatabase, ISQLiteStorageDatabaseLoggingOptions, InMemoryStorageDatabase } from 'vs/base/node/storage';
import { join } from 'vs/base/common/path';
import { exists } from 'vs/base/node/pfs';
export const IStorageMainService = createDecorator<IStorageMainService>('storageMainService');
@@ -121,25 +120,14 @@ export class StorageMainService extends Disposable implements IStorageMainServic
}
private doInitialize(): Promise<void> {
const useInMemoryStorage = this.storagePath === SQLiteStorageDatabase.IN_MEMORY_PATH;
this.storage.dispose();
this.storage = new Storage(new SQLiteStorageDatabase(this.storagePath, {
logging: this.createLogginOptions()
}));
let globalStorageExists: Promise<boolean>;
if (useInMemoryStorage) {
globalStorageExists = Promise.resolve(true);
} else {
globalStorageExists = exists(this.storagePath);
}
this._register(this.storage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key })));
return globalStorageExists.then(exists => {
this.storage.dispose();
this.storage = new Storage(new SQLiteStorageDatabase(this.storagePath, {
logging: this.createLogginOptions()
}));
this._register(this.storage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key })));
return this.storage.init();
});
return this.storage.init();
}
get(key: string, fallbackValue: string): string;

View File

@@ -62,38 +62,38 @@ export class StorageService extends Disposable implements IStorageService {
return this.initializePromise;
}
private doInitialize(payload: IWorkspaceInitializationPayload): Promise<void> {
return Promise.all([
private async doInitialize(payload: IWorkspaceInitializationPayload): Promise<void> {
await Promise.all([
this.initializeGlobalStorage(),
this.initializeWorkspaceStorage(payload)
]).then(() => undefined);
]);
}
private initializeGlobalStorage(): Promise<void> {
return this.globalStorage.init();
}
private initializeWorkspaceStorage(payload: IWorkspaceInitializationPayload): Promise<void> {
private async initializeWorkspaceStorage(payload: IWorkspaceInitializationPayload): Promise<void> {
// Prepare workspace storage folder for DB
return this.prepareWorkspaceStorageFolder(payload).then(result => {
try {
const result = await this.prepareWorkspaceStorageFolder(payload);
const useInMemoryStorage = !!this.environmentService.extensionTestsLocationURI; // no storage during extension tests!
// Create workspace storage and initalize
mark('willInitWorkspaceStorage');
return this.createWorkspaceStorage(useInMemoryStorage ? SQLiteStorageDatabase.IN_MEMORY_PATH : join(result.path, StorageService.WORKSPACE_STORAGE_NAME), result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined).init().then(() => {
try {
await this.createWorkspaceStorage(useInMemoryStorage ? SQLiteStorageDatabase.IN_MEMORY_PATH : join(result.path, StorageService.WORKSPACE_STORAGE_NAME), result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined).init();
} finally {
mark('didInitWorkspaceStorage');
}, error => {
mark('didInitWorkspaceStorage');
return Promise.reject(error);
});
}).then(undefined, error => {
}
} catch (error) {
onUnexpectedError(error);
// Upon error, fallback to in-memory storage
return this.createWorkspaceStorage(SQLiteStorageDatabase.IN_MEMORY_PATH).init();
});
}
}
private createWorkspaceStorage(workspaceStoragePath: string, hint?: StorageHint): IStorage {
@@ -120,22 +120,20 @@ export class StorageService extends Disposable implements IStorageService {
return join(this.environmentService.workspaceStorageHome, payload.id); // workspace home + workspace id;
}
private prepareWorkspaceStorageFolder(payload: IWorkspaceInitializationPayload): Promise<{ path: string, wasCreated: boolean }> {
private async prepareWorkspaceStorageFolder(payload: IWorkspaceInitializationPayload): Promise<{ path: string, wasCreated: boolean }> {
const workspaceStorageFolderPath = this.getWorkspaceStorageFolderPath(payload);
return exists(workspaceStorageFolderPath).then<{ path: string, wasCreated: boolean }>(exists => {
if (exists) {
return { path: workspaceStorageFolderPath, wasCreated: false };
}
const storageExists = await exists(workspaceStorageFolderPath);
if (storageExists) {
return { path: workspaceStorageFolderPath, wasCreated: false };
}
return mkdirp(workspaceStorageFolderPath).then(() => {
await mkdirp(workspaceStorageFolderPath);
// Write metadata into folder
this.ensureWorkspaceStorageFolderMeta(payload);
// Write metadata into folder
this.ensureWorkspaceStorageFolderMeta(payload);
return { path: workspaceStorageFolderPath, wasCreated: true };
});
});
return { path: workspaceStorageFolderPath, wasCreated: true };
}
private ensureWorkspaceStorageFolderMeta(payload: IWorkspaceInitializationPayload): void {
@@ -148,13 +146,16 @@ export class StorageService extends Disposable implements IStorageService {
if (meta) {
const workspaceStorageMetaPath = join(this.getWorkspaceStorageFolderPath(payload), StorageService.WORKSPACE_META_NAME);
exists(workspaceStorageMetaPath).then(exists => {
if (exists) {
return undefined; // already existing
(async function () {
try {
const storageExists = await exists(workspaceStorageMetaPath);
if (!storageExists) {
await writeFile(workspaceStorageMetaPath, JSON.stringify(meta, undefined, 2));
}
} catch (error) {
onUnexpectedError(error);
}
return writeFile(workspaceStorageMetaPath, JSON.stringify(meta, undefined, 2));
}).then(undefined, error => onUnexpectedError(error));
})();
}
}
@@ -184,16 +185,16 @@ export class StorageService extends Disposable implements IStorageService {
this.getStorage(scope).delete(key);
}
close(): Promise<void> {
async close(): Promise<void> {
// Signal as event so that clients can still store data
this._onWillSaveState.fire({ reason: WillSaveStateReason.SHUTDOWN });
// Do it
return Promise.all([
await Promise.all([
this.globalStorage.close(),
this.workspaceStorage.close()
]).then(() => undefined);
]);
}
private getStorage(scope: StorageScope): IStorage {
@@ -208,77 +209,75 @@ export class StorageService extends Disposable implements IStorageService {
return scope === StorageScope.GLOBAL ? this.globalStorage.checkIntegrity(full) : this.workspaceStorage.checkIntegrity(full);
}
logStorage(): Promise<void> {
return Promise.all([
async logStorage(): Promise<void> {
const result = await Promise.all([
this.globalStorage.items,
this.workspaceStorage.items,
this.globalStorage.checkIntegrity(true /* full */),
this.workspaceStorage.checkIntegrity(true /* full */)
]).then(result => {
const safeParse = (value: string) => {
try {
return JSON.parse(value);
} catch (error) {
return value;
}
};
]);
const globalItems = new Map<string, string>();
const globalItemsParsed = new Map<string, string>();
result[0].forEach((value, key) => {
globalItems.set(key, value);
globalItemsParsed.set(key, safeParse(value));
});
const safeParse = (value: string) => {
try {
return JSON.parse(value);
} catch (error) {
return value;
}
};
const workspaceItems = new Map<string, string>();
const workspaceItemsParsed = new Map<string, string>();
result[1].forEach((value, key) => {
workspaceItems.set(key, value);
workspaceItemsParsed.set(key, safeParse(value));
});
console.group(`Storage: Global (integrity: ${result[2]}, path: ${this.environmentService.globalStorageHome})`);
let globalValues: { key: string, value: string }[] = [];
globalItems.forEach((value, key) => {
globalValues.push({ key, value });
});
console.table(globalValues);
console.groupEnd();
console.log(globalItemsParsed);
console.group(`Storage: Workspace (integrity: ${result[3]}, load: ${getDuration('willInitWorkspaceStorage', 'didInitWorkspaceStorage')}, path: ${this.workspaceStoragePath})`);
let workspaceValues: { key: string, value: string }[] = [];
workspaceItems.forEach((value, key) => {
workspaceValues.push({ key, value });
});
console.table(workspaceValues);
console.groupEnd();
console.log(workspaceItemsParsed);
const globalItems = new Map<string, string>();
const globalItemsParsed = new Map<string, string>();
result[0].forEach((value, key) => {
globalItems.set(key, value);
globalItemsParsed.set(key, safeParse(value));
});
const workspaceItems = new Map<string, string>();
const workspaceItemsParsed = new Map<string, string>();
result[1].forEach((value, key) => {
workspaceItems.set(key, value);
workspaceItemsParsed.set(key, safeParse(value));
});
console.group(`Storage: Global (integrity: ${result[2]}, path: ${this.environmentService.globalStorageHome})`);
let globalValues: { key: string, value: string }[] = [];
globalItems.forEach((value, key) => {
globalValues.push({ key, value });
});
console.table(globalValues);
console.groupEnd();
console.log(globalItemsParsed);
console.group(`Storage: Workspace (integrity: ${result[3]}, load: ${getDuration('willInitWorkspaceStorage', 'didInitWorkspaceStorage')}, path: ${this.workspaceStoragePath})`);
let workspaceValues: { key: string, value: string }[] = [];
workspaceItems.forEach((value, key) => {
workspaceValues.push({ key, value });
});
console.table(workspaceValues);
console.groupEnd();
console.log(workspaceItemsParsed);
}
migrate(toWorkspace: IWorkspaceInitializationPayload): Promise<void> {
async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise<void> {
if (this.workspaceStoragePath === SQLiteStorageDatabase.IN_MEMORY_PATH) {
return Promise.resolve(); // no migration needed if running in memory
}
// Close workspace DB to be able to copy
return this.workspaceStorage.close().then(() => {
await this.workspaceStorage.close();
// Prepare new workspace storage folder
return this.prepareWorkspaceStorageFolder(toWorkspace).then(result => {
const newWorkspaceStoragePath = join(result.path, StorageService.WORKSPACE_STORAGE_NAME);
// Prepare new workspace storage folder
const result = await this.prepareWorkspaceStorageFolder(toWorkspace);
// Copy current storage over to new workspace storage
return copy(this.workspaceStoragePath, newWorkspaceStoragePath).then(() => {
const newWorkspaceStoragePath = join(result.path, StorageService.WORKSPACE_STORAGE_NAME);
// Recreate and init workspace storage
return this.createWorkspaceStorage(newWorkspaceStoragePath).init();
});
});
});
// Copy current storage over to new workspace storage
await copy(this.workspaceStoragePath, newWorkspaceStoragePath);
// Recreate and init workspace storage
return this.createWorkspaceStorage(newWorkspaceStoragePath).init();
}
}

View File

@@ -89,15 +89,15 @@ export class TelemetryService implements ITelemetryService {
return this._userOptIn && this._enabled;
}
getTelemetryInfo(): Promise<ITelemetryInfo> {
return this._commonProperties.then(values => {
// well known properties
let sessionId = values['sessionID'];
let instanceId = values['common.instanceId'];
let machineId = values['common.machineId'];
async getTelemetryInfo(): Promise<ITelemetryInfo> {
const values = await this._commonProperties;
return { sessionId, instanceId, machineId };
});
// well known properties
let sessionId = values['sessionID'];
let instanceId = values['common.instanceId'];
let machineId = values['common.machineId'];
return { sessionId, instanceId, machineId };
}
dispose(): void {

View File

@@ -10,8 +10,9 @@ import { readFile } from 'vs/base/node/pfs';
// {{SQL CARBON EDIT}}
import product from 'vs/platform/product/node/product';
const productObject = product;
export function resolveCommonProperties(commit: string | undefined, version: string | undefined, machineId: string | undefined, installSourcePath: string): Promise<{ [name: string]: string | undefined; }> {
export async function resolveCommonProperties(commit: string | undefined, version: string | undefined, machineId: string | undefined, installSourcePath: string, product?: string): Promise<{ [name: string]: string | undefined; }> {
const result: { [name: string]: string | undefined; } = Object.create(null);
// {{SQL CARBON EDIT}}
@@ -36,8 +37,8 @@ export function resolveCommonProperties(commit: string | undefined, version: str
result['common.nodeArch'] = process.arch;
// __GDPR__COMMON__ "common.product" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
// {{SQL CARBON EDIT}}
result['common.product'] = product.nameShort || 'desktop';
result['common.application.name'] = product.nameLong;
result['common.product'] = productObject.nameShort || 'desktop';
result['common.application.name'] = productObject.nameLong;
// dynamic properties which value differs on each call
let seq = 0;
@@ -65,13 +66,14 @@ export function resolveCommonProperties(commit: string | undefined, version: str
result['common.snap'] = 'true';
}
return readFile(installSourcePath, 'utf8').then(contents => {
try {
const contents = await readFile(installSourcePath, 'utf8');
// __GDPR__COMMON__ "common.source" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
result['common.source'] = contents.slice(0, 30);
} catch (error) {
// ignore error
}
return result;
}, error => {
return result;
});
return result;
}

View File

@@ -3,20 +3,18 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import product from 'vs/platform/product/node/product';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
export function addGAParameters(telemetryService: ITelemetryService, environmentService: IEnvironmentService, uri: URI, origin: string, experiment = '1'): Promise<URI> {
export async function addGAParameters(telemetryService: ITelemetryService, environmentService: IEnvironmentService, uri: URI, origin: string, experiment = '1'): Promise<URI> {
if (environmentService.isBuilt && !environmentService.isExtensionDevelopment && !environmentService.args['disable-telemetry'] && !!product.enableTelemetry) {
if (uri.scheme === 'https' && uri.authority === 'code.visualstudio.com') {
return telemetryService.getTelemetryInfo()
.then(info => {
return uri.with({ query: `${uri.query ? uri.query + '&' : ''}utm_source=VsCode&utm_medium=${encodeURIComponent(origin)}&utm_campaign=${encodeURIComponent(info.instanceId)}&utm_content=${encodeURIComponent(experiment)}` });
});
const info = await telemetryService.getTelemetryInfo();
return uri.with({ query: `${uri.query ? uri.query + '&' : ''}utm_source=VsCode&utm_medium=${encodeURIComponent(origin)}&utm_campaign=${encodeURIComponent(info.instanceId)}&utm_content=${encodeURIComponent(experiment)}` });
}
}
return Promise.resolve(uri);
return uri;
}

View File

@@ -14,35 +14,38 @@ export const lastSessionDateStorageKey = 'telemetry.lastSessionDate';
// {{ SQL CARBON EDIT }}
import product from 'vs/platform/product/node/product';
export function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, installSourcePath: string): Promise<{ [name: string]: string | undefined }> {
return resolveCommonProperties(commit, version, machineId, installSourcePath).then(result => {
const instanceId = storageService.get(instanceStorageKey, StorageScope.GLOBAL)!;
const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.GLOBAL)!;
const lastSessionDate = storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL)!;
export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, installSourcePath: string): Promise<{ [name: string]: string | undefined }> {
const result = await resolveCommonProperties(commit, version, machineId, installSourcePath);
const instanceId = storageService.get(instanceStorageKey, StorageScope.GLOBAL)!;
const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.GLOBAL)!;
const lastSessionDate = storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL)!;
// __GDPR__COMMON__ "common.version.shell" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
result['common.version.shell'] = process.versions && process.versions['electron'];
// __GDPR__COMMON__ "common.version.renderer" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
result['common.version.renderer'] = process.versions && process.versions['chrome'];
// {{SQL CARBON EDIT}}
result['common.application.name'] = product.nameLong;
// {{SQL CARBON EDIT}}
result['common.userId'] = '';
// __GDPR__COMMON__ "common.version.shell" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
// result['common.version.shell'] = process.versions && process.versions['electron'];
// __GDPR__COMMON__ "common.version.renderer" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
// result['common.version.renderer'] = process.versions && process.versions['chrome'];
// __GDPR__COMMON__ "common.firstSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
// result['common.firstSessionDate'] = firstSessionDate;
// __GDPR__COMMON__ "common.lastSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
// result['common.lastSessionDate'] = lastSessionDate || '';
// __GDPR__COMMON__ "common.isNewSession" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
// result['common.isNewSession'] = !lastSessionDate ? '1' : '0';
// __GDPR__COMMON__ "common.instanceId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
// result['common.instanceId'] = instanceId;
// {{SQL CARBON EDIT}}
// // __GDPR__COMMON__ "common.firstSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
// result['common.firstSessionDate'] = firstSessionDate;
// // __GDPR__COMMON__ "common.lastSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
// result['common.lastSessionDate'] = lastSessionDate || '';
// // __GDPR__COMMON__ "common.isNewSession" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
// result['common.isNewSession'] = !lastSessionDate ? '1' : '0';
// // __GDPR__COMMON__ "common.instanceId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
// result['common.instanceId'] = instanceId;
// __GDPR__COMMON__ "common.version.shell" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
result['common.version.shell'] = process.versions && process.versions['electron'];
// __GDPR__COMMON__ "common.version.renderer" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
result['common.version.renderer'] = process.versions && process.versions['chrome'];
// {{SQL CARBON EDIT}}
result['common.application.name'] = product.nameLong;
// {{SQL CARBON EDIT}}
result['common.userId'] = '';
// {{SQL CARBON EDIT}}
setUsageDates(storageService);
return result;
});
// {{SQL CARBON EDIT}}
setUsageDates(storageService);
return result;
}
// {{SQL CARBON EDIT}}

View File

@@ -74,13 +74,13 @@ export class WindowsService implements IWindowsService {
return this.channel.call('closeWorkspace', windowId);
}
enterWorkspace(windowId: number, path: URI): Promise<IEnterWorkspaceResult | undefined> {
return this.channel.call('enterWorkspace', [windowId, path]).then((result: IEnterWorkspaceResult) => {
if (result) {
result.workspace = reviveWorkspaceIdentifier(result.workspace);
}
return result;
});
async enterWorkspace(windowId: number, path: URI): Promise<IEnterWorkspaceResult | undefined> {
const result: IEnterWorkspaceResult = await this.channel.call('enterWorkspace', [windowId, path]);
if (result) {
result.workspace = reviveWorkspaceIdentifier(result.workspace);
}
return result;
}
toggleFullScreen(windowId: number): Promise<void> {
@@ -103,13 +103,12 @@ export class WindowsService implements IWindowsService {
return this.channel.call('clearRecentlyOpened');
}
getRecentlyOpened(windowId: number): Promise<IRecentlyOpened> {
return this.channel.call('getRecentlyOpened', windowId)
.then((recentlyOpened: IRecentlyOpened) => {
recentlyOpened.workspaces.forEach(recent => isRecentWorkspace(recent) ? recent.workspace = reviveWorkspaceIdentifier(recent.workspace) : recent.folderUri = URI.revive(recent.folderUri));
recentlyOpened.files.forEach(recent => recent.fileUri = URI.revive(recent.fileUri));
return recentlyOpened;
});
async getRecentlyOpened(windowId: number): Promise<IRecentlyOpened> {
const recentlyOpened: IRecentlyOpened = await this.channel.call('getRecentlyOpened', windowId);
recentlyOpened.workspaces.forEach(recent => isRecentWorkspace(recent) ? recent.workspace = reviveWorkspaceIdentifier(recent.workspace) : recent.folderUri = URI.revive(recent.folderUri));
recentlyOpened.files.forEach(recent => recent.fileUri = URI.revive(recent.fileUri));
return recentlyOpened;
}
newWindowTab(): Promise<void> {
@@ -196,18 +195,26 @@ export class WindowsService implements IWindowsService {
return this.channel.call('openNewWindow', options);
}
getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]> {
return this.channel.call<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]>('getWindows').then(result => {
for (const win of result) {
if (win.folderUri) {
win.folderUri = URI.revive(win.folderUri);
}
if (win.workspace) {
win.workspace = reviveWorkspaceIdentifier(win.workspace);
}
async getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]> {
const result = await this.channel.call<{
id: number;
workspace?: IWorkspaceIdentifier;
folderUri?: ISingleFolderWorkspaceIdentifier;
title: string;
filename?: string;
}[]>('getWindows');
for (const win of result) {
if (win.folderUri) {
win.folderUri = URI.revive(win.folderUri);
}
return result;
});
if (win.workspace) {
win.workspace = reviveWorkspaceIdentifier(win.workspace);
}
}
return result;
}
getWindowCount(): Promise<number> {

View File

@@ -103,13 +103,14 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain
return isEqualOrParent(path, this.environmentService.untitledWorkspacesHome);
}
createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise<IWorkspaceIdentifier> {
async createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise<IWorkspaceIdentifier> {
const { workspace, storedWorkspace } = this.newUntitledWorkspace(folders, remoteAuthority);
const configPath = workspace.configPath.fsPath;
return mkdirp(dirname(configPath)).then(() => {
return writeFile(configPath, JSON.stringify(storedWorkspace, null, '\t')).then(() => workspace);
});
await mkdirp(dirname(configPath));
await writeFile(configPath, JSON.stringify(storedWorkspace, null, '\t'));
return workspace;
}
createUntitledWorkspaceSync(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): IWorkspaceIdentifier {