support application scoped extensions (#152975)

* support application scoped extensions

* fix tests
This commit is contained in:
Sandeep Somavarapu 2022-06-23 23:04:34 +02:00 committed by GitHub
parent 619ab6d1ba
commit 1e5e1a02e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 160 additions and 45 deletions

View file

@ -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));

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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 {

View file

@ -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);
}
}

View file

@ -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));

View file

@ -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);
}
}

View file

@ -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);
});

View file

@ -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;
}

View file

@ -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> {

View file

@ -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();

View file

@ -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> {