Merge from vscode 3c6f6af7347d38e87bc6406024e8dcf9e9bce229 (#8962)

* Merge from vscode 3c6f6af7347d38e87bc6406024e8dcf9e9bce229

* skip failing tests

* update mac build image
This commit is contained in:
Anthony Dresser
2020-01-27 15:28:17 -08:00
committed by Karl Burtram
parent 0eaee18dc4
commit fefe1454de
481 changed files with 12764 additions and 7836 deletions

View File

@@ -0,0 +1,157 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event, Emitter } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { IExtensionIdentifier, IGlobalExtensionEnablementService, DISABLED_EXTENSIONS_STORAGE_PATH } from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
import { isUndefinedOrNull } from 'vs/base/common/types';
export class GlobalExtensionEnablementService extends Disposable implements IGlobalExtensionEnablementService {
_serviceBrand: undefined;
private _onDidChangeEnablement = new Emitter<readonly IExtensionIdentifier[]>();
readonly onDidChangeEnablement: Event<readonly IExtensionIdentifier[]> = this._onDidChangeEnablement.event;
private readonly storageManger: StorageManager;
constructor(
@IStorageService storageService: IStorageService,
) {
super();
this.storageManger = this._register(new StorageManager(storageService));
this._register(this.storageManger.onDidChange(extensions => this._onDidChangeEnablement.fire(extensions)));
}
async enableExtension(extension: IExtensionIdentifier): Promise<boolean> {
if (this._removeFromDisabledExtensions(extension)) {
return true;
}
return false;
}
async disableExtension(extension: IExtensionIdentifier): Promise<boolean> {
if (this._addToDisabledExtensions(extension)) {
return true;
}
return false;
}
getDisabledExtensions(): IExtensionIdentifier[] {
return this._getExtensions(DISABLED_EXTENSIONS_STORAGE_PATH);
}
async getDisabledExtensionsAsync(): Promise<IExtensionIdentifier[]> {
return this.getDisabledExtensions();
}
private _addToDisabledExtensions(identifier: IExtensionIdentifier): boolean {
let disabledExtensions = this.getDisabledExtensions();
if (disabledExtensions.every(e => !areSameExtensions(e, identifier))) {
disabledExtensions.push(identifier);
this._setDisabledExtensions(disabledExtensions);
return true;
}
return false;
}
private _removeFromDisabledExtensions(identifier: IExtensionIdentifier): boolean {
let disabledExtensions = this.getDisabledExtensions();
for (let index = 0; index < disabledExtensions.length; index++) {
const disabledExtension = disabledExtensions[index];
if (areSameExtensions(disabledExtension, identifier)) {
disabledExtensions.splice(index, 1);
this._setDisabledExtensions(disabledExtensions);
return true;
}
}
return false;
}
private _setDisabledExtensions(disabledExtensions: IExtensionIdentifier[]): void {
this._setExtensions(DISABLED_EXTENSIONS_STORAGE_PATH, disabledExtensions);
}
private _getExtensions(storageId: string): IExtensionIdentifier[] {
return this.storageManger.get(storageId, StorageScope.GLOBAL);
}
private _setExtensions(storageId: string, extensions: IExtensionIdentifier[]): void {
this.storageManger.set(storageId, extensions, StorageScope.GLOBAL);
}
}
export class StorageManager extends Disposable {
private storage: { [key: string]: string } = Object.create(null);
private _onDidChange: Emitter<IExtensionIdentifier[]> = this._register(new Emitter<IExtensionIdentifier[]>());
readonly onDidChange: Event<IExtensionIdentifier[]> = this._onDidChange.event;
constructor(private storageService: IStorageService) {
super();
this._register(storageService.onDidChangeStorage(e => this.onDidStorageChange(e)));
}
get(key: string, scope: StorageScope): IExtensionIdentifier[] {
let value: string;
if (scope === StorageScope.GLOBAL) {
if (isUndefinedOrNull(this.storage[key])) {
this.storage[key] = this._get(key, scope);
}
value = this.storage[key];
} else {
value = this._get(key, scope);
}
return JSON.parse(value);
}
set(key: string, value: IExtensionIdentifier[], scope: StorageScope): void {
let newValue: string = JSON.stringify(value.map(({ id, uuid }) => (<IExtensionIdentifier>{ id, uuid })));
const oldValue = this._get(key, scope);
if (oldValue !== newValue) {
if (scope === StorageScope.GLOBAL) {
if (value.length) {
this.storage[key] = newValue;
} else {
delete this.storage[key];
}
}
this._set(key, value.length ? newValue : undefined, scope);
}
}
private onDidStorageChange(workspaceStorageChangeEvent: IWorkspaceStorageChangeEvent): void {
if (workspaceStorageChangeEvent.scope === StorageScope.GLOBAL) {
if (!isUndefinedOrNull(this.storage[workspaceStorageChangeEvent.key])) {
const newValue = this._get(workspaceStorageChangeEvent.key, workspaceStorageChangeEvent.scope);
if (newValue !== this.storage[workspaceStorageChangeEvent.key]) {
const oldValues = this.get(workspaceStorageChangeEvent.key, workspaceStorageChangeEvent.scope);
delete this.storage[workspaceStorageChangeEvent.key];
const newValues = this.get(workspaceStorageChangeEvent.key, workspaceStorageChangeEvent.scope);
const added = oldValues.filter(oldValue => !newValues.some(newValue => areSameExtensions(oldValue, newValue)));
const removed = newValues.filter(newValue => !oldValues.some(oldValue => areSameExtensions(oldValue, newValue)));
if (added.length || removed.length) {
this._onDidChange.fire([...added, ...removed]);
}
}
}
}
}
private _get(key: string, scope: StorageScope): string {
return this.storageService.get(key, scope, '[]');
}
private _set(key: string, value: string | undefined, scope: StorageScope): void {
if (value) {
this.storageService.store(key, value, scope);
} else {
this.storageService.remove(key, scope);
}
}
}

View File

@@ -211,6 +211,22 @@ export interface IExtensionManagementService {
updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): Promise<ILocalExtension>;
}
export const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/disabled';
export const ENABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/enabled';
export const IGlobalExtensionEnablementService = createDecorator<IGlobalExtensionEnablementService>('IGlobalExtensionEnablementService');
export interface IGlobalExtensionEnablementService {
_serviceBrand: undefined;
readonly onDidChangeEnablement: Event<readonly IExtensionIdentifier[]>;
getDisabledExtensions(): IExtensionIdentifier[];
enableExtension(extension: IExtensionIdentifier): Promise<boolean>;
disableExtension(extension: IExtensionIdentifier): Promise<boolean>;
// Async method until storage service is available in shared process
getDisabledExtensionsAsync(): Promise<IExtensionIdentifier[]>;
}
export const ExtensionsLabel = localize('extensions', "Extensions");
export const ExtensionsChannelId = 'extensions';
export const PreferencesLabel = localize('preferences', "Preferences");

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { Event } from 'vs/base/common/event';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc';
@@ -130,3 +130,53 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer
return Promise.resolve(this.channel.call('getExtensionsReport'));
}
}
export class GlobalExtensionEnablementServiceChannel implements IServerChannel {
constructor(private readonly service: IGlobalExtensionEnablementService) { }
listen(_: unknown, event: string): Event<any> {
switch (event) {
case 'onDidChangeEnablement': return this.service.onDidChangeEnablement;
}
throw new Error(`Event not found: ${event}`);
}
call(context: any, command: string, args?: any): Promise<any> {
switch (command) {
case 'getDisabledExtensionsAsync': return Promise.resolve(this.service.getDisabledExtensions());
case 'enableExtension': return this.service.enableExtension(args[0]);
case 'disableExtension': return this.service.disableExtension(args[0]);
}
throw new Error('Invalid call');
}
}
export class GlobalExtensionEnablementServiceClient implements IGlobalExtensionEnablementService {
_serviceBrand: undefined;
get onDidChangeEnablement(): Event<IExtensionIdentifier[]> { return this.channel.listen('onDidChangeEnablement'); }
constructor(private readonly channel: IChannel) {
}
getDisabledExtensionsAsync(): Promise<IExtensionIdentifier[]> {
return this.channel.call('getDisabledExtensionsAsync');
}
enableExtension(extension: IExtensionIdentifier): Promise<boolean> {
return this.channel.call('enableExtension', [extension]);
}
disableExtension(extension: IExtensionIdentifier): Promise<boolean> {
return this.channel.call('disableExtension', [extension]);
}
getDisabledExtensions(): IExtensionIdentifier[] {
throw new Error('not supported');
}
}

View File

@@ -120,4 +120,25 @@ export function getMaliciousExtensionsSet(report: IReportedExtension[]): Set<str
}
return result;
}
}
export interface IBuiltInExtension {
name: string;
version: string;
repo: string;
forQualities?: ReadonlyArray<string>;
metadata: any;
}
/**
* Parses the built-in extension JSON data and filters it down to the
* extensions built into this product quality.
*/
export function parseBuiltInExtensions(rawJson: string, productQuality: string | undefined) {
const parsed: IBuiltInExtension[] = JSON.parse(rawJson);
if (!productQuality) {
return parsed;
}
return parsed.filter(ext => ext.forQualities?.indexOf?.(productQuality) !== -1);
}

View File

@@ -21,7 +21,7 @@ import {
INSTALL_ERROR_MALICIOUS,
INSTALL_ERROR_INCOMPATIBLE
} from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions, getGalleryExtensionId, groupByExtension, getMaliciousExtensionsSet, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { areSameExtensions, getGalleryExtensionId, groupByExtension, getMaliciousExtensionsSet, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, ExtensionIdentifierWithVersion, parseBuiltInExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { localizeManifest } from '../common/extensionNls';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { Limiter, createCancelablePromise, CancelablePromise, Queue } from 'vs/base/common/async';
@@ -45,6 +45,7 @@ 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 } from 'vs/platform/extensions/common/extensions';
import { IProductService } from 'vs/platform/product/common/productService';
const ERROR_SCANNING_SYS_EXTENSIONS = 'scanningSystem';
const ERROR_SCANNING_USER_EXTENSIONS = 'scanningUser';
@@ -132,6 +133,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
@ILogService private readonly logService: ILogService,
@optional(IDownloadService) private downloadService: IDownloadService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IProductService private readonly productService: IProductService,
) {
super();
this.systemExtensionsPath = environmentService.builtinExtensionsPath;
@@ -971,10 +973,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
private getDevSystemExtensionsList(): Promise<string[]> {
return pfs.readFile(this.devSystemExtensionsFilePath, 'utf8')
.then<string[]>(raw => {
const parsed: { name: string }[] = JSON.parse(raw);
return parsed.map(({ name }) => name);
});
.then(data => parseBuiltInExtensions(data, this.productService.quality).map(ext => ext.name));
}
private toNonCancellablePromise<T>(promise: Promise<T>): Promise<T> {