mirror of
https://github.com/Microsoft/vscode
synced 2024-10-06 03:17:00 +00:00
support application scoped extensions (#152975)
* support application scoped extensions * fix tests
This commit is contained in:
parent
619ab6d1ba
commit
1e5e1a02e8
|
@ -710,7 +710,7 @@ export class CodeApplication extends Disposable {
|
|||
mainProcessElectronServer.registerChannel(LOCAL_FILE_SYSTEM_CHANNEL_NAME, fileSystemProviderChannel);
|
||||
sharedProcessClient.then(client => client.registerChannel(LOCAL_FILE_SYSTEM_CHANNEL_NAME, fileSystemProviderChannel));
|
||||
|
||||
// Profiles
|
||||
// User Data Profiles
|
||||
const userDataProfilesService = ProxyChannel.fromService(accessor.get(IUserDataProfilesMainService));
|
||||
mainProcessElectronServer.registerChannel('userDataProfiles', userDataProfilesService);
|
||||
sharedProcessClient.then(client => client.registerChannel('userDataProfiles', userDataProfilesService));
|
||||
|
|
|
@ -18,10 +18,12 @@ import {
|
|||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { areSameExtensions, ExtensionKey, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, getMaliciousExtensionsSet } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService';
|
||||
import { ExtensionType, IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionType, IExtensionManifest, isApplicationScopedExtension, TargetPlatform } from 'vs/platform/extensions/common/extensions';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
|
||||
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
|
||||
|
||||
export interface IInstallExtensionTask {
|
||||
readonly identifier: IExtensionIdentifier;
|
||||
|
@ -65,6 +67,8 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
|
|||
private readonly participants: IExtensionManagementParticipant[] = [];
|
||||
|
||||
constructor(
|
||||
@IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService,
|
||||
@IUriIdentityService private readonly uriIdenityService: IUriIdentityService,
|
||||
@IExtensionGalleryService protected readonly galleryService: IExtensionGalleryService,
|
||||
@IExtensionsProfileScannerService protected readonly extensionsProfileScannerService: IExtensionsProfileScannerService,
|
||||
@ITelemetryService protected readonly telemetryService: ITelemetryService,
|
||||
|
@ -142,10 +146,8 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
|
|||
const installExtensionTask = this.installingExtensions.get(ExtensionKey.create(extension).toString());
|
||||
if (installExtensionTask) {
|
||||
this.logService.info('Extensions is already requested to install', extension.identifier.id);
|
||||
const { local, metadata } = await installExtensionTask.waitUntilTaskIsFinished();
|
||||
if (options.profileLocation) {
|
||||
await this.extensionsProfileScannerService.addExtensionsToProfile([[local, metadata]], options.profileLocation);
|
||||
}
|
||||
const waitUntilTaskIsFinishedTask = this.createWaitUntilInstallExtensionTaskIsFinishedTask(installExtensionTask, options);
|
||||
const { local } = await waitUntilTaskIsFinishedTask.waitUntilTaskIsFinished();
|
||||
return local;
|
||||
}
|
||||
options = { ...options, installOnlyNewlyAddedFromExtensionPack: true /* always true for gallery extensions */ };
|
||||
|
@ -153,7 +155,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
|
|||
|
||||
const allInstallExtensionTasks: { task: IInstallExtensionTask; manifest: IExtensionManifest }[] = [];
|
||||
const installResults: (InstallExtensionResult & { local: ILocalExtension })[] = [];
|
||||
const installExtensionTask = this.createDefaultInstallExtensionTask(manifest, extension, options);
|
||||
const installExtensionTask = this.createInstallExtensionTask(manifest, extension, options);
|
||||
if (!URI.isUri(extension)) {
|
||||
this.installingExtensions.set(ExtensionKey.create(extension).toString(), installExtensionTask);
|
||||
}
|
||||
|
@ -174,7 +176,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
|
|||
if (this.installingExtensions.has(key)) {
|
||||
this.logService.info('Extension is already requested to install', gallery.identifier.id);
|
||||
} else {
|
||||
const task = this.createDefaultInstallExtensionTask(manifest, gallery, { ...options, donotIncludePackAndDependencies: true });
|
||||
const task = this.createInstallExtensionTask(manifest, gallery, { ...options, donotIncludePackAndDependencies: true });
|
||||
this.installingExtensions.set(key, task);
|
||||
this._onInstallExtension.fire({ identifier: task.identifier, source: gallery });
|
||||
this.logService.info('Installing extension:', task.identifier.id);
|
||||
|
@ -219,10 +221,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
|
|||
await this.joinAllSettled(extensionsToInstall.map(async ({ task }) => {
|
||||
const startTime = new Date().getTime();
|
||||
try {
|
||||
const { local, metadata } = await task.run();
|
||||
if (options.profileLocation) {
|
||||
await this.extensionsProfileScannerService.addExtensionsToProfile([[local, metadata]], options.profileLocation);
|
||||
}
|
||||
const { local } = await task.run();
|
||||
await this.joinAllSettled(this.participants.map(participant => participant.postInstall(local, task.source, options, CancellationToken.None)));
|
||||
if (!URI.isUri(task.source)) {
|
||||
const isUpdate = task.operation === InstallOperation.Update;
|
||||
|
@ -593,8 +592,23 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
|
|||
}
|
||||
}
|
||||
|
||||
private createInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: ServerInstallOptions & ServerInstallVSIXOptions): IInstallExtensionTask {
|
||||
const installTask = this.createDefaultInstallExtensionTask(manifest, extension, options);
|
||||
return options.profileLocation && this.userDataProfilesService.defaultProfile.extensionsResource ? new InstallExtensionInProfileTask(installTask, options.profileLocation, this.userDataProfilesService.defaultProfile.extensionsResource, this.extensionsProfileScannerService) : installTask;
|
||||
}
|
||||
|
||||
private createWaitUntilInstallExtensionTaskIsFinishedTask(installTask: IInstallExtensionTask, options: ServerInstallOptions & ServerInstallVSIXOptions): IInstallExtensionTask {
|
||||
if (!options.profileLocation || !this.userDataProfilesService.defaultProfile.extensionsResource) {
|
||||
return installTask;
|
||||
}
|
||||
if (installTask instanceof InstallExtensionInProfileTask && this.uriIdenityService.extUri.isEqual(installTask.profileLocation, options.profileLocation)) {
|
||||
return installTask;
|
||||
}
|
||||
return new InstallExtensionInProfileTask(installTask, options.profileLocation, this.userDataProfilesService.defaultProfile.extensionsResource, this.extensionsProfileScannerService);
|
||||
}
|
||||
|
||||
private createUninstallExtensionTask(extension: ILocalExtension, options: UninstallExtensionTaskOptions, profile?: URI): IUninstallExtensionTask {
|
||||
return profile ? new UninstallExtensionFromProfileTask(extension, profile, this.extensionsProfileScannerService) : this.createDefaultUninstallExtensionTask(extension, options);
|
||||
return profile && this.userDataProfilesService.defaultProfile.extensionsResource ? new UninstallExtensionFromProfileTask(extension, profile, this.userDataProfilesService, this.extensionsProfileScannerService) : this.createDefaultUninstallExtensionTask(extension, options);
|
||||
}
|
||||
|
||||
abstract getTargetPlatform(): Promise<TargetPlatform>;
|
||||
|
@ -707,18 +721,66 @@ export abstract class AbstractExtensionTask<T> {
|
|||
protected abstract doRun(token: CancellationToken): Promise<T>;
|
||||
}
|
||||
|
||||
export class UninstallExtensionFromProfileTask extends AbstractExtensionTask<void> implements IUninstallExtensionTask {
|
||||
class InstallExtensionInProfileTask implements IInstallExtensionTask {
|
||||
|
||||
readonly identifier = this.task.identifier;
|
||||
readonly source = this.task.source;
|
||||
readonly operation = this.task.operation;
|
||||
|
||||
private readonly promise: Promise<{ local: ILocalExtension; metadata: Metadata }>;
|
||||
|
||||
constructor(
|
||||
private readonly task: IInstallExtensionTask,
|
||||
readonly profileLocation: URI,
|
||||
private readonly defaultProfileLocation: URI,
|
||||
private readonly extensionsProfileScannerService: IExtensionsProfileScannerService,
|
||||
) {
|
||||
this.promise = this.waitAndAddExtensionToProfile();
|
||||
}
|
||||
|
||||
private async waitAndAddExtensionToProfile(): Promise<{ local: ILocalExtension; metadata: Metadata }> {
|
||||
const result = await this.task.waitUntilTaskIsFinished();
|
||||
let profileLocation = this.profileLocation;
|
||||
if (isApplicationScopedExtension(result.local.manifest)) {
|
||||
profileLocation = this.defaultProfileLocation;
|
||||
result.metadata = { ...result.metadata, isApplicationScoped: true };
|
||||
}
|
||||
await this.extensionsProfileScannerService.addExtensionsToProfile([[result.local, result.metadata]], profileLocation);
|
||||
return result;
|
||||
}
|
||||
|
||||
async run(): Promise<{ local: ILocalExtension; metadata: Metadata }> {
|
||||
await this.task.run();
|
||||
return this.promise;
|
||||
}
|
||||
|
||||
waitUntilTaskIsFinished(): Promise<{ local: ILocalExtension; metadata: Metadata }> {
|
||||
return this.promise;
|
||||
}
|
||||
|
||||
cancel(): void {
|
||||
return this.task.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
class UninstallExtensionFromProfileTask extends AbstractExtensionTask<void> implements IUninstallExtensionTask {
|
||||
|
||||
constructor(
|
||||
readonly extension: ILocalExtension,
|
||||
private readonly profileLocation: URI,
|
||||
private readonly userDataProfilesService: IUserDataProfilesService,
|
||||
private readonly extensionsProfileScannerService: IExtensionsProfileScannerService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async doRun(token: CancellationToken): Promise<void> {
|
||||
await this.extensionsProfileScannerService.removeExtensionFromProfile(this.extension.identifier, this.profileLocation);
|
||||
const promises: Promise<any>[] = [];
|
||||
promises.push(this.extensionsProfileScannerService.removeExtensionFromProfile(this.extension.identifier, this.profileLocation));
|
||||
if (isApplicationScopedExtension(this.extension.manifest) && this.userDataProfilesService.defaultProfile.extensionsResource) {
|
||||
promises.push(this.extensionsProfileScannerService.removeExtensionFromProfile(this.extension.identifier, this.userDataProfilesService.defaultProfile.extensionsResource));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -238,7 +238,7 @@ export interface IGalleryMetadata {
|
|||
targetPlatform?: TargetPlatform;
|
||||
}
|
||||
|
||||
export type Metadata = Partial<IGalleryMetadata & { isMachineScoped: boolean; isBuiltin: boolean; isSystem: boolean; updated: boolean; preRelease: boolean; installedTimestamp: number }>;
|
||||
export type Metadata = Partial<IGalleryMetadata & { isApplicationScoped: boolean; isMachineScoped: boolean; isBuiltin: boolean; isSystem: boolean; updated: boolean; preRelease: boolean; installedTimestamp: number }>;
|
||||
|
||||
export interface ILocalExtension extends IExtension {
|
||||
isMachineScoped: boolean;
|
||||
|
|
|
@ -18,13 +18,13 @@ import { ILogService } from 'vs/platform/log/common/log';
|
|||
interface IStoredProfileExtension {
|
||||
readonly identifier: IExtensionIdentifier;
|
||||
readonly location: UriComponents;
|
||||
readonly metadata: Metadata;
|
||||
readonly metadata?: Metadata;
|
||||
}
|
||||
|
||||
export interface IScannedProfileExtension {
|
||||
readonly identifier: IExtensionIdentifier;
|
||||
readonly location: URI;
|
||||
readonly metadata: Metadata;
|
||||
readonly metadata?: Metadata;
|
||||
}
|
||||
|
||||
export const IExtensionsProfileScannerService = createDecorator<IExtensionsProfileScannerService>('IExtensionsProfileScannerService');
|
||||
|
@ -94,12 +94,12 @@ export class ExtensionsProfileScannerService extends Disposable implements IExte
|
|||
// Update
|
||||
if (updateFn) {
|
||||
extensions = updateFn(extensions);
|
||||
const storedWebExtensions: IStoredProfileExtension[] = extensions.map(e => ({
|
||||
const storedProfileExtensions: IStoredProfileExtension[] = extensions.map(e => ({
|
||||
identifier: e.identifier,
|
||||
location: e.location.toJSON(),
|
||||
metadata: e.metadata
|
||||
}));
|
||||
await this.fileService.writeFile(file, VSBuffer.fromString(JSON.stringify(storedWebExtensions)));
|
||||
await this.fileService.writeFile(file, VSBuffer.fromString(JSON.stringify(storedProfileExtensions)));
|
||||
}
|
||||
|
||||
return extensions;
|
||||
|
|
|
@ -32,7 +32,8 @@ import { ILogService } from 'vs/platform/log/common/log';
|
|||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService';
|
||||
import { IExtensionsProfileScannerService, IScannedProfileExtension } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService';
|
||||
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
|
||||
|
||||
export type IScannedExtensionManifest = IRelaxedExtensionManifest & { __metadata?: Metadata };
|
||||
|
||||
|
@ -147,6 +148,7 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem
|
|||
readonly userExtensionsLocation: URI,
|
||||
private readonly extensionsControlLocation: URI,
|
||||
private readonly cacheLocation: URI,
|
||||
@IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService,
|
||||
@IExtensionsProfileScannerService protected readonly extensionsProfileScannerService: IExtensionsProfileScannerService,
|
||||
@IFileService protected readonly fileService: IFileService,
|
||||
@ILogService protected readonly logService: ILogService,
|
||||
|
@ -378,18 +380,14 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem
|
|||
|
||||
private async createExtensionScannerInput(location: URI, profile: boolean, type: ExtensionType, excludeObsolete: boolean, language: string | undefined, validate: boolean = true): Promise<ExtensionScannerInput> {
|
||||
const translations = await this.getTranslations(language ?? platform.language);
|
||||
let mtime: number | undefined;
|
||||
try {
|
||||
const folderStat = await this.fileService.stat(location);
|
||||
if (typeof folderStat.mtime === 'number') {
|
||||
mtime = folderStat.mtime;
|
||||
}
|
||||
} catch (err) {
|
||||
// That's ok...
|
||||
}
|
||||
const mtime = await this.getMtime(location);
|
||||
const applicationExtensionsLocation = this.userDataProfilesService.defaultProfile.extensionsResource;
|
||||
const applicationExtensionsLocationMtime = applicationExtensionsLocation ? await this.getMtime(applicationExtensionsLocation) : undefined;
|
||||
return new ExtensionScannerInput(
|
||||
location,
|
||||
mtime,
|
||||
applicationExtensionsLocation,
|
||||
applicationExtensionsLocationMtime,
|
||||
profile,
|
||||
type,
|
||||
excludeObsolete,
|
||||
|
@ -403,6 +401,18 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem
|
|||
);
|
||||
}
|
||||
|
||||
private async getMtime(location: URI): Promise<number | undefined> {
|
||||
try {
|
||||
const stat = await this.fileService.stat(location);
|
||||
if (typeof stat.mtime === 'number') {
|
||||
return stat.mtime;
|
||||
}
|
||||
} catch (err) {
|
||||
// That's ok...
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ExtensionScannerInput {
|
||||
|
@ -410,6 +420,8 @@ class ExtensionScannerInput {
|
|||
constructor(
|
||||
public readonly location: URI,
|
||||
public readonly mtime: number | undefined,
|
||||
public readonly applicationExtensionslocation: URI | undefined,
|
||||
public readonly applicationExtensionslocationMtime: number | undefined,
|
||||
public readonly profile: boolean,
|
||||
public readonly type: ExtensionType,
|
||||
public readonly excludeObsolete: boolean,
|
||||
|
@ -437,6 +449,8 @@ class ExtensionScannerInput {
|
|||
return (
|
||||
isEqual(a.location, b.location)
|
||||
&& a.mtime === b.mtime
|
||||
&& isEqual(a.applicationExtensionslocation, b.applicationExtensionslocation)
|
||||
&& a.applicationExtensionslocationMtime === b.applicationExtensionslocationMtime
|
||||
&& a.profile === b.profile
|
||||
&& a.type === b.type
|
||||
&& a.excludeObsolete === b.excludeObsolete
|
||||
|
@ -495,21 +509,36 @@ class ExtensionsScanner extends Disposable {
|
|||
if (input.type === ExtensionType.User && basename(c.resource).indexOf('.') === 0) {
|
||||
return null;
|
||||
}
|
||||
const extensionScannerInput = new ExtensionScannerInput(c.resource, input.mtime, input.profile, input.type, input.excludeObsolete, input.validate, input.productVersion, input.productDate, input.productCommit, input.devMode, input.language, input.translations);
|
||||
const extensionScannerInput = new ExtensionScannerInput(c.resource, input.mtime, input.applicationExtensionslocation, input.applicationExtensionslocationMtime, input.profile, input.type, input.excludeObsolete, input.validate, input.productVersion, input.productDate, input.productCommit, input.devMode, input.language, input.translations);
|
||||
return this.scanExtension(extensionScannerInput);
|
||||
}));
|
||||
return coalesce(extensions);
|
||||
}
|
||||
|
||||
private async scanExtensionsFromProfile(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
|
||||
const scannedProfileExtensions = await this.extensionsProfileScannerService.scanProfileExtensions(input.location);
|
||||
const profileExtensions = await this.scanExtensionsFromProfileResource(input.location, () => true, input);
|
||||
const applicationExtensions = await this.scanApplicationExtensions(input);
|
||||
return [...profileExtensions, ...applicationExtensions];
|
||||
}
|
||||
|
||||
private async scanApplicationExtensions(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
|
||||
return input.applicationExtensionslocation
|
||||
? this.scanExtensionsFromProfileResource(input.applicationExtensionslocation, (e) => !!e.metadata?.isApplicationScoped, input)
|
||||
: [];
|
||||
}
|
||||
|
||||
private async scanExtensionsFromProfileResource(profileResource: URI, filter: (extensionInfo: IScannedProfileExtension) => boolean, input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
|
||||
const scannedProfileExtensions = await this.extensionsProfileScannerService.scanProfileExtensions(profileResource);
|
||||
if (!scannedProfileExtensions.length) {
|
||||
return [];
|
||||
}
|
||||
const extensions = await Promise.all<IRelaxedScannedExtension | null>(
|
||||
scannedProfileExtensions.map(async extensionInfo => {
|
||||
const extensionScannerInput = new ExtensionScannerInput(extensionInfo.location, input.mtime, input.profile, input.type, input.excludeObsolete, input.validate, input.productVersion, input.productDate, input.productCommit, input.devMode, input.language, input.translations);
|
||||
return this.scanExtension(extensionScannerInput);
|
||||
if (filter(extensionInfo)) {
|
||||
const extensionScannerInput = new ExtensionScannerInput(extensionInfo.location, input.mtime, input.applicationExtensionslocation, input.applicationExtensionslocationMtime, input.profile, input.type, input.excludeObsolete, input.validate, input.productVersion, input.productDate, input.productCommit, input.devMode, input.language, input.translations);
|
||||
return this.scanExtension(extensionScannerInput, extensionInfo.metadata);
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
return coalesce(extensions);
|
||||
}
|
||||
|
@ -910,6 +939,7 @@ export class NativeExtensionsScannerService extends AbstractExtensionsScannerSer
|
|||
userExtensionsLocation: URI,
|
||||
userHome: URI,
|
||||
userDataPath: URI,
|
||||
userDataProfilesService: IUserDataProfilesService,
|
||||
extensionsProfileScannerService: IExtensionsProfileScannerService,
|
||||
fileService: IFileService,
|
||||
logService: ILogService,
|
||||
|
@ -921,7 +951,7 @@ export class NativeExtensionsScannerService extends AbstractExtensionsScannerSer
|
|||
userExtensionsLocation,
|
||||
joinPath(userHome, '.vscode-oss-dev', 'extensions', 'control.json'),
|
||||
joinPath(userDataPath, MANIFEST_CACHE_FOLDER),
|
||||
extensionsProfileScannerService, fileService, logService, environmentService, productService);
|
||||
userDataProfilesService, extensionsProfileScannerService, fileService, logService, environmentService, productService);
|
||||
this.translationsPromise = (async () => {
|
||||
if (platform.translationsConfigFile) {
|
||||
try {
|
||||
|
|
|
@ -11,10 +11,12 @@ import { IFileService } from 'vs/platform/files/common/files';
|
|||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
|
||||
|
||||
export class ExtensionsScannerService extends NativeExtensionsScannerService implements IExtensionsScannerService {
|
||||
|
||||
constructor(
|
||||
@IUserDataProfilesService userDataProfilesService: IUserDataProfilesService,
|
||||
@IExtensionsProfileScannerService extensionsProfileScannerService: IExtensionsProfileScannerService,
|
||||
@IFileService fileService: IFileService,
|
||||
@ILogService logService: ILogService,
|
||||
|
@ -26,7 +28,7 @@ export class ExtensionsScannerService extends NativeExtensionsScannerService imp
|
|||
URI.file(environmentService.extensionsPath),
|
||||
environmentService.userHome,
|
||||
URI.file(environmentService.userDataPath),
|
||||
extensionsProfileScannerService, fileService, logService, environmentService, productService);
|
||||
userDataProfilesService, extensionsProfileScannerService, fileService, logService, environmentService, productService);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import { ILogService } from 'vs/platform/log/common/log';
|
|||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
|
||||
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
|
||||
|
||||
interface InstallableExtension {
|
||||
zipPath: string;
|
||||
|
@ -68,8 +69,9 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi
|
|||
@IFileService private readonly fileService: IFileService,
|
||||
@IProductService productService: IProductService,
|
||||
@IUriIdentityService uriIdentityService: IUriIdentityService,
|
||||
@IUserDataProfilesService userDataProfilesService: IUserDataProfilesService,
|
||||
) {
|
||||
super(galleryService, extensionsProfileScannerService, telemetryService, logService, productService);
|
||||
super(userDataProfilesService, uriIdentityService, galleryService, extensionsProfileScannerService, telemetryService, logService, productService);
|
||||
const extensionLifecycle = this._register(instantiationService.createInstance(ExtensionsLifecycle));
|
||||
this.extensionsScanner = this._register(instantiationService.createInstance(ExtensionsScanner, extension => extensionLifecycle.postUninstall(extension)));
|
||||
this.manifestCache = this._register(new ExtensionsManifestCache(environmentService, this));
|
||||
|
|
|
@ -10,10 +10,12 @@ import { IExtensionsScannerService, NativeExtensionsScannerService, } from 'vs/p
|
|||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
|
||||
|
||||
export class ExtensionsScannerService extends NativeExtensionsScannerService implements IExtensionsScannerService {
|
||||
|
||||
constructor(
|
||||
@IUserDataProfilesService userDataProfilesService: IUserDataProfilesService,
|
||||
@IExtensionsProfileScannerService extensionsProfileScannerService: IExtensionsProfileScannerService,
|
||||
@IFileService fileService: IFileService,
|
||||
@ILogService logService: ILogService,
|
||||
|
@ -25,7 +27,7 @@ export class ExtensionsScannerService extends NativeExtensionsScannerService imp
|
|||
URI.file(environmentService.extensionsPath),
|
||||
environmentService.userHome,
|
||||
URI.file(environmentService.userDataPath),
|
||||
extensionsProfileScannerService, fileService, logService, environmentService, productService);
|
||||
userDataProfilesService, extensionsProfileScannerService, fileService, logService, environmentService, productService);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFil
|
|||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IUserDataProfilesService, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
|
||||
|
||||
let translations: Translations = Object.create(null);
|
||||
const ROOT = URI.file('/ROOT');
|
||||
|
@ -24,6 +25,7 @@ const ROOT = URI.file('/ROOT');
|
|||
class ExtensionsScannerService extends AbstractExtensionsScannerService implements IExtensionsScannerService {
|
||||
|
||||
constructor(
|
||||
@IUserDataProfilesService userDataProfilesService: IUserDataProfilesService,
|
||||
@IExtensionsProfileScannerService extensionsProfileScannerService: IExtensionsProfileScannerService,
|
||||
@IFileService fileService: IFileService,
|
||||
@ILogService logService: ILogService,
|
||||
|
@ -35,7 +37,7 @@ class ExtensionsScannerService extends AbstractExtensionsScannerService implemen
|
|||
URI.file(nativeEnvironmentService.extensionsPath),
|
||||
joinPath(nativeEnvironmentService.userHome, '.vscode-oss-dev', 'extensions', 'control.json'),
|
||||
joinPath(ROOT, MANIFEST_CACHE_FOLDER),
|
||||
extensionsProfileScannerService, fileService, logService, nativeEnvironmentService, productService);
|
||||
userDataProfilesService, extensionsProfileScannerService, fileService, logService, nativeEnvironmentService, productService);
|
||||
}
|
||||
|
||||
protected async getTranslations(language: string): Promise<Translations> {
|
||||
|
@ -60,13 +62,15 @@ suite('NativeExtensionsScanerService Test', () => {
|
|||
instantiationService.stub(IFileService, fileService);
|
||||
const systemExtensionsLocation = joinPath(ROOT, 'system');
|
||||
const userExtensionsLocation = joinPath(ROOT, 'extensions');
|
||||
instantiationService.stub(INativeEnvironmentService, {
|
||||
const environmentService = instantiationService.stub(INativeEnvironmentService, {
|
||||
userHome: ROOT,
|
||||
userRoamingDataHome: ROOT,
|
||||
builtinExtensionsPath: systemExtensionsLocation.fsPath,
|
||||
extensionsPath: userExtensionsLocation.fsPath,
|
||||
});
|
||||
instantiationService.stub(IProductService, { version: '1.66.0' });
|
||||
instantiationService.stub(IExtensionsProfileScannerService, new ExtensionsProfileScannerService(fileService, logService));
|
||||
instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(environmentService, fileService, logService));
|
||||
await fileService.createFolder(systemExtensionsLocation);
|
||||
await fileService.createFolder(userExtensionsLocation);
|
||||
});
|
||||
|
|
|
@ -393,6 +393,10 @@ export interface IRelaxedExtensionDescription extends IRelaxedExtensionManifest
|
|||
|
||||
export type IExtensionDescription = Readonly<IRelaxedExtensionDescription>;
|
||||
|
||||
export function isApplicationScopedExtension(manifest: IExtensionManifest): boolean {
|
||||
return isLanguagePackExtension(manifest);
|
||||
}
|
||||
|
||||
export function isLanguagePackExtension(manifest: IExtensionManifest): boolean {
|
||||
return manifest.contributes && manifest.contributes.localizations ? manifest.contributes.localizations.length > 0 : false;
|
||||
}
|
||||
|
|
|
@ -12,11 +12,13 @@ import { MANIFEST_CACHE_FOLDER } from 'vs/platform/extensions/common/extensions'
|
|||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
|
||||
import { getNLSConfiguration, InternalNLSConfiguration } from 'vs/server/node/remoteLanguagePacks';
|
||||
|
||||
export class ExtensionsScannerService extends AbstractExtensionsScannerService implements IExtensionsScannerService {
|
||||
|
||||
constructor(
|
||||
@IUserDataProfilesService userDataProfilesService: IUserDataProfilesService,
|
||||
@IExtensionsProfileScannerService extensionsProfileScannerService: IExtensionsProfileScannerService,
|
||||
@IFileService fileService: IFileService,
|
||||
@ILogService logService: ILogService,
|
||||
|
@ -28,7 +30,7 @@ export class ExtensionsScannerService extends AbstractExtensionsScannerService i
|
|||
URI.file(nativeEnvironmentService.extensionsPath),
|
||||
joinPath(nativeEnvironmentService.userHome, '.vscode-oss-dev', 'extensions', 'control.json'),
|
||||
joinPath(URI.file(nativeEnvironmentService.userDataPath), MANIFEST_CACHE_FOLDER),
|
||||
extensionsProfileScannerService, fileService, logService, nativeEnvironmentService, productService);
|
||||
userDataProfilesService, extensionsProfileScannerService, fileService, logService, nativeEnvironmentService, productService);
|
||||
}
|
||||
|
||||
protected async getTranslations(language: string): Promise<Translations> {
|
||||
|
|
|
@ -71,7 +71,7 @@ import { ExtensionHostStatusService, IExtensionHostStatusService } from 'vs/serv
|
|||
import { IExtensionsScannerService } from 'vs/platform/extensionManagement/common/extensionsScannerService';
|
||||
import { ExtensionsScannerService } from 'vs/server/node/extensionsScannerService';
|
||||
import { ExtensionsProfileScannerService, IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService';
|
||||
import { UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
|
||||
import { IUserDataProfilesService, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
|
||||
import { NullPolicyService } from 'vs/platform/policy/common/policy';
|
||||
|
||||
const eventPrefix = 'monacoworkbench';
|
||||
|
@ -110,8 +110,11 @@ export async function setupServerServices(connectionToken: ServerConnectionToken
|
|||
services.set(IFileService, fileService);
|
||||
fileService.registerProvider(Schemas.file, disposables.add(new DiskFileSystemProvider(logService)));
|
||||
|
||||
// Configuration
|
||||
// User Data Profiles
|
||||
const userDataProfilesService = new UserDataProfilesService(environmentService, fileService, logService);
|
||||
services.set(IUserDataProfilesService, userDataProfilesService);
|
||||
|
||||
// Configuration
|
||||
const configurationService = new ConfigurationService(environmentService.machineSettingsResource, fileService, new NullPolicyService(), logService);
|
||||
services.set(IConfigurationService, configurationService);
|
||||
await configurationService.initialize();
|
||||
|
|
|
@ -17,6 +17,8 @@ import { IExtensionManifestPropertiesService } from 'vs/workbench/services/exten
|
|||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { isBoolean, isUndefined } from 'vs/base/common/types';
|
||||
import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService';
|
||||
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
|
||||
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
|
||||
|
||||
export class WebExtensionManagementService extends AbstractExtensionManagementService implements IExtensionManagementService, IProfileAwareExtensionManagementService {
|
||||
|
||||
|
@ -31,9 +33,11 @@ export class WebExtensionManagementService extends AbstractExtensionManagementSe
|
|||
@IWebExtensionsScannerService private readonly webExtensionsScannerService: IWebExtensionsScannerService,
|
||||
@IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService,
|
||||
@IExtensionsProfileScannerService extensionsProfileScannerService: IExtensionsProfileScannerService,
|
||||
@IProductService productService: IProductService
|
||||
@IProductService productService: IProductService,
|
||||
@IUserDataProfilesService userDataProfilesService: IUserDataProfilesService,
|
||||
@IUriIdentityService uriIdentityService: IUriIdentityService,
|
||||
) {
|
||||
super(extensionGalleryService, extensionsProfileScannerService, telemetryService, logService, productService);
|
||||
super(userDataProfilesService, uriIdentityService, extensionGalleryService, extensionsProfileScannerService, telemetryService, logService, productService);
|
||||
}
|
||||
|
||||
async getTargetPlatform(): Promise<TargetPlatform> {
|
||||
|
|
Loading…
Reference in a new issue