extensionsScannerService.ts ×50

Frontier kind: Code frontier

unlabeled · c_7a719444741c

30 tests · 16223 LOC · 82 files · introduces 0 tests · 322 LOC · 2 files

Introduces — evidence that enters the hierarchy at this concept

Code
52 ranges322 lines · 2 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
2079 ranges16223 lines · 82 files · Browse complete extent
All tests (intent)
30 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

2 files ranked by introduced lines: 322 introduced LOC across 52 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/extensionManagement/common/extensionsScannerService.ts 306 introduced LOC · 50 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extensionsScannerService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { coalesce } from '../../../base/common/arrays.js';
7 > import { ThrottledDelayer } from '../../../base/common/async.js';
8 > import * as objects from '../../../base/common/objects.js';
9 > import { VSBuffer } from '../../../base/common/buffer.js';
10 > import { getErrorMessage } from '../../../base/common/errors.js';
11 > import { getNodeType, parse, ParseError } from '../../../base/common/json.js';
12 > import { getParseErrorMessage } from '../../../base/common/jsonErrorMessages.js';
13 > import { Disposable } from '../../../base/common/lifecycle.js';
14 > import { FileAccess, Schemas } from '../../../base/common/network.js';
15 > import * as path from '../../../base/common/path.js';
16 > import * as platform from '../../../base/common/platform.js';
17 > import { basename, isEqual, joinPath } from '../../../base/common/resources.js';
18 > import * as semver from '../../../base/common/semver/semver.js';
19 > import Severity from '../../../base/common/severity.js';
20 > import { URI } from '../../../base/common/uri.js';
21 > import { localize } from '../../../nls.js';
22 > import { IEnvironmentService } from '../../environment/common/environment.js';
23 > import { IProductVersion, Metadata } from './extensionManagement.js';
24 > import { areSameExtensions, computeTargetPlatform, getExtensionId, getGalleryExtensionId } from './extensionManagementUtil.js';
25 > import { ExtensionType, ExtensionIdentifier, IExtensionManifest, TargetPlatform, IExtensionIdentifier, IRelaxedExtensionManifest, UNDEFINED_PUBLISHER, IExtensionDescription, BUILTIN_MANIFEST_CACHE_FILE, USER_MANIFEST_CACHE_FILE, ExtensionIdentifierMap, parseEnabledApiProposalNames } from '../../extensions/common/extensions.js';
26 > import { validateExtensionManifest } from '../../extensions/common/extensionValidator.js';
27 > import { FileOperationResult, IFileService, toFileOperationResult } from '../../files/common/files.js';
28 > import { createDecorator, IInstantiationService } from '../../instantiation/common/instantiation.js';
29 > import { ILogService } from '../../log/common/log.js';
30 > import { IProductService } from '../../product/common/productService.js';
31 > import { Emitter, Event } from '../../../base/common/event.js';
32 > import { revive } from '../../../base/common/marshalling.js';
33 > import { ExtensionsProfileScanningError, ExtensionsProfileScanningErrorCode, IExtensionsProfileScannerService, IProfileExtensionsScanOptions, IScannedProfileExtension } from './extensionsProfileScannerService.js';
34 > import { IUserDataProfile, IUserDataProfilesService } from '../../userDataProfile/common/userDataProfile.js';
35 > import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.js';
36 > import { localizeManifest } from './extensionNls.js';
37 >
38 > export type ManifestMetadata = Partial<{
39 > targetPlatform: TargetPlatform;
40 > installedTimestamp: number;
41 > size: number;
42 > }>;
43 >
44 > export type IScannedExtensionManifest = IRelaxedExtensionManifest & { __metadata?: ManifestMetadata };
45 >
46 > interface IRelaxedScannedExtension {
47 > type: ExtensionType;
48 > isBuiltin: boolean;
49 > identifier: IExtensionIdentifier;
50 > manifest: IRelaxedExtensionManifest;
51 > location: URI;
52 > targetPlatform: TargetPlatform;
53 > publisherDisplayName?: string;
54 > metadata: Metadata | undefined;
55 > isValid: boolean;
56 > validations: readonly [Severity, string][];
57 > preRelease: boolean;
58 > forceAutoUpdate: boolean;
59 > }
60 >
61 > export type IScannedExtension = Readonly<IRelaxedScannedExtension> & { manifest: IExtensionManifest };
62 >
63 > export interface Translations {
64 > [id: string]: string;
65 > }
66 >
67 > export namespace Translations {
68 > export function equals(a: Translations, b: Translations): boolean {
69 if (a === b) {
70 return true;
87 return bKeys.size === 0;
88 }
90 >
91 > interface MessageBag {
92 > [key: string]: string | { message: string; comment: string[] };
93 > }
94 >
95 > interface TranslationBundle {
96 > contents: {
97 > package: MessageBag;
98 > };
99 > }
100 >
101 > interface LocalizedMessages {
102 > values: MessageBag | undefined;
103 > default: URI | null;
104 > }
105 >
106 > interface IBuiltInExtensionControl {
107 > [name: string]: 'marketplace' | 'disabled' | string;
108 > }
109 >
110 function getProductBuiltInExtensionsEnabledWithAutoUpdates(productService: IProductService, environmentService: IEnvironmentService): Set<string> {
111 const result = new Set<string>();
119 return result;
120 }
122 > export type SystemExtensionsScanOptions = {
123 > readonly checkControlFile?: boolean;
124 > readonly language?: string;
125 > };
126 >
127 > export type UserExtensionsScanOptions = {
128 > readonly profileLocation: URI;
129 > readonly includeInvalid?: boolean;
130 > readonly language?: string;
131 > readonly useCache?: boolean;
132 > readonly productVersion?: IProductVersion;
133 > };
134 >
135 > export type ScanOptions = {
136 > readonly includeInvalid?: boolean;
137 > readonly language?: string;
138 > };
139 >
140 > export const IExtensionsScannerService = createDecorator<IExtensionsScannerService>('IExtensionsScannerService');
141 > export interface IExtensionsScannerService {
142 > readonly _serviceBrand: undefined;
143 >
144 > readonly systemExtensionsLocation: URI;
145 > readonly userExtensionsLocation: URI;
146 > readonly onDidChangeCache: Event<ExtensionType>;
147 >
148 > scanAllExtensions(systemScanOptions: SystemExtensionsScanOptions, userScanOptions: UserExtensionsScanOptions): Promise<IScannedExtension[]>;
149 > scanSystemExtensions(scanOptions: SystemExtensionsScanOptions): Promise<IScannedExtension[]>;
150 > scanUserExtensions(scanOptions: UserExtensionsScanOptions): Promise<IScannedExtension[]>;
151 > scanAllUserExtensions(): Promise<IScannedExtension[]>;
152 >
153 > scanExtensionsUnderDevelopment(existingExtensions: IScannedExtension[], scanOptions: ScanOptions): Promise<IScannedExtension[]>;
154 > scanExistingExtension(extensionLocation: URI, extensionType: ExtensionType, scanOptions: ScanOptions): Promise<IScannedExtension | null>;
155 > scanMultipleExtensions(extensionLocations: URI[], extensionType: ExtensionType, scanOptions: ScanOptions): Promise<IScannedExtension[]>;
156 > scanOneOrMultipleExtensions(extensionLocation: URI, extensionType: ExtensionType, scanOptions: ScanOptions): Promise<IScannedExtension[]>;
157 >
158 > updateManifestMetadata(extensionLocation: URI, metadata: ManifestMetadata): Promise<void>;
159 > initializeDefaultProfileExtensions(): Promise<void>;
160 > }
161 >
162 > export abstract class AbstractExtensionsScannerService extends Disposable implements IExtensionsScannerService {
163 >
164 > readonly _serviceBrand: undefined;
165 >
166 > protected abstract getTranslations(language: string): Promise<Translations>;
167 >
168 > private readonly _onDidChangeCache = this._register(new Emitter<ExtensionType>());
169 > readonly onDidChangeCache = this._onDidChangeCache.event;
170 >
171 > private readonly systemExtensionsCachedScanner: CachedExtensionsScanner;
172 > private readonly userExtensionsCachedScanner: CachedExtensionsScanner;
173 > private readonly extensionsScanner: ExtensionsScanner;
174 >
175 > constructor(
176 readonly systemExtensionsLocation: URI,
177 readonly userExtensionsLocation: URI,
196 this._register(this.userExtensionsCachedScanner.onDidChangeCache(() => this._onDidChangeCache.fire(ExtensionType.User)));
197 }
199 > private _targetPlatformPromise: Promise<TargetPlatform> | undefined;
200 > private getTargetPlatform(): Promise<TargetPlatform> {
201 if (!this._targetPlatformPromise) {
202 this._targetPlatformPromise = computeTargetPlatform(this.fileService, this.logService);
204 return this._targetPlatformPromise;
205 }
207 > async scanAllExtensions(systemScanOptions: SystemExtensionsScanOptions, userScanOptions: UserExtensionsScanOptions): Promise<IScannedExtension[]> {
208 const [system, user] = await Promise.all([
209 this.scanSystemExtensions(systemScanOptions),
212 return this.dedupExtensions(system, user, [], await this.getTargetPlatform(), true);
213 }
215 > async scanSystemExtensions(scanOptions: SystemExtensionsScanOptions): Promise<IScannedExtension[]> {
216 const promises: Promise<IRelaxedScannedExtension[]>[] = [];
217 promises.push(this.scanDefaultSystemExtensions(scanOptions.language));
227 return this.applyScanOptions(allSystemExtensions, ExtensionType.System, { pickLatest: false });
228 }
230 > async scanUserExtensions(scanOptions: UserExtensionsScanOptions): Promise<IScannedExtension[]> {
231 this.logService.trace('Started scanning user extensions', scanOptions.profileLocation);
232 const profileScanOptions: IProfileExtensionsScanOptions | undefined = this.uriIdentityService.extUri.isEqual(scanOptions.profileLocation, this.userDataProfilesService.defaultProfile.extensionsResource) ? { bailOutWhenFileNotFound: true } : undefined;
248 return extensions;
249 }
251 > async scanAllUserExtensions(scanOptions: { includeAllVersions?: boolean; includeInvalid: boolean } = { includeInvalid: true, includeAllVersions: true }): Promise<IScannedExtension[]> {
252 const extensionsScannerInput = await this.createExtensionScannerInput(this.userExtensionsLocation, false, ExtensionType.User, undefined, true, undefined, this.getProductVersion());
253 const extensions = await this.extensionsScanner.scanExtensions(extensionsScannerInput);
254 return this.applyScanOptions(extensions, ExtensionType.User, { includeAllVersions: scanOptions.includeAllVersions, includeInvalid: scanOptions.includeInvalid });
255 }
257 > async scanExtensionsUnderDevelopment(existingExtensions: IScannedExtension[], scanOptions: ScanOptions): Promise<IScannedExtension[]> {
258 if (this.environmentService.isExtensionDevelopment && this.environmentService.extensionDevelopmentLocationURI) {
259 const extensions = (await Promise.all(this.environmentService.extensionDevelopmentLocationURI.filter(extLoc => extLoc.scheme === Schemas.file)
273 return [];
274 }
276 > async scanExistingExtension(extensionLocation: URI, extensionType: ExtensionType, scanOptions: ScanOptions): Promise<IScannedExtension | null> {
277 const extensionsScannerInput = await this.createExtensionScannerInput(extensionLocation, false, extensionType, scanOptions.language, true, undefined, this.getProductVersion());
278 const extension = await this.extensionsScanner.scanExtension(extensionsScannerInput);
285 return extension;
286 }
288 > async scanOneOrMultipleExtensions(extensionLocation: URI, extensionType: ExtensionType, scanOptions: ScanOptions): Promise<IScannedExtension[]> {
289 const extensionsScannerInput = await this.createExtensionScannerInput(extensionLocation, false, extensionType, scanOptions.language, true, undefined, this.getProductVersion());
290 const extensions = await this.extensionsScanner.scanOneOrMultipleExtensions(extensionsScannerInput);
291 return this.applyScanOptions(extensions, extensionType, { includeInvalid: scanOptions.includeInvalid, pickLatest: true });
292 }
294 > async scanMultipleExtensions(extensionLocations: URI[], extensionType: ExtensionType, scanOptions: ScanOptions): Promise<IScannedExtension[]> {
295 const extensions: IRelaxedScannedExtension[] = [];
296 await Promise.all(extensionLocations.map(async extensionLocation => {
300 return this.applyScanOptions(extensions, extensionType, { includeInvalid: scanOptions.includeInvalid, pickLatest: true });
301 }
303 > async updateManifestMetadata(extensionLocation: URI, metaData: ManifestMetadata): Promise<void> {
304 const manifestLocation = joinPath(extensionLocation, 'package.json');
305 const content = (await this.fileService.readFile(manifestLocation)).value.toString();
309 await this.fileService.writeFile(joinPath(extensionLocation, 'package.json'), VSBuffer.fromString(JSON.stringify(manifest, null, '\t')));
310 }
312 > async initializeDefaultProfileExtensions(): Promise<void> {
313 try {
314 await this.extensionsProfileScannerService.scanProfileExtensions(this.userDataProfilesService.defaultProfile.extensionsResource, { bailOutWhenFileNotFound: true });
321 }
322 }
324 > private initializeDefaultProfileExtensionsPromise: Promise<void> | undefined = undefined;
325 > private async doInitializeDefaultProfileExtensions(): Promise<void> {
326 if (!this.initializeDefaultProfileExtensionsPromise) {
327 this.initializeDefaultProfileExtensionsPromise = (async () => {
350 return this.initializeDefaultProfileExtensionsPromise;
351 }
353 > private async applyScanOptions(extensions: IRelaxedScannedExtension[], type: ExtensionType | 'development', scanOptions: { includeAllVersions?: boolean; includeInvalid?: boolean; pickLatest?: boolean } = {}): Promise<IRelaxedScannedExtension[]> {
354 if (!scanOptions.includeAllVersions) {
355 extensions = this.dedupExtensions(type === ExtensionType.System ? extensions : undefined, type === ExtensionType.User ? extensions : undefined, type === 'development' ? extensions : undefined, await this.getTargetPlatform(), !!scanOptions.pickLatest);
370 });
371 }
373 > private dedupExtensions(system: IScannedExtension[] | undefined, user: IScannedExtension[] | undefined, development: IScannedExtension[] | undefined, targetPlatform: TargetPlatform, pickLatest: boolean): IScannedExtension[] {
374 const pick = (existing: IScannedExtension, extension: IScannedExtension, isDevelopment: boolean): boolean => {
375 if (!isDevelopment && !(existing.isBuiltin || extension.isBuiltin)) {
438 return [...result.values()];
439 }
441 > private async scanDefaultSystemExtensions(language: string | undefined): Promise<IRelaxedScannedExtension[]> {
442 this.logService.trace('Started scanning system extensions');
443 const extensionsScannerInput = await this.createExtensionScannerInput(this.systemExtensionsLocation, false, ExtensionType.System, language, true, undefined, this.getProductVersion());
447 return result;
448 }
450 > private async scanDevSystemExtensions(language: string | undefined, checkControlFile: boolean): Promise<IRelaxedScannedExtension[]> {
451 const devSystemExtensionsList = this.environmentService.isBuilt ? [] : this.productService.builtInExtensions;
452 if (!devSystemExtensionsList?.length) {
475 return coalesce(result);
476 }
478 > private async getBuiltInExtensionControl(): Promise<IBuiltInExtensionControl> {
479 try {
480 const content = await this.fileService.readFile(this.extensionsControlLocation);
484 }
485 }
487 > private async createExtensionScannerInput(location: URI, profile: boolean, type: ExtensionType, language: string | undefined, validate: boolean, profileScanOptions: IProfileExtensionsScanOptions | undefined, productVersion: IProductVersion): Promise<ExtensionScannerInput> {
488 const translations = await this.getTranslations(language ?? platform.language);
489 const mtime = await this.getMtime(location);
507 );
508 }
510 > private async getMtime(location: URI): Promise<number | undefined> {
511 try {
512 const stat = await this.fileService.stat(location);
519 return undefined;
520 }
522 > private getProductVersion(): IProductVersion {
523 return {
524 version: this.productService.version,
526 };
527 }
529 > }
530 >
531 > export class ExtensionScannerInput {
532 >
533 > constructor(
534 > public readonly location: URI,
535 > public readonly mtime: number | undefined,
536 > public readonly applicationExtensionslocation: URI | undefined,
537 > public readonly applicationExtensionslocationMtime: number | undefined,
538 > public readonly profile: boolean,
539 > public readonly profileScanOptions: IProfileExtensionsScanOptions | undefined,
540 > public readonly type: ExtensionType,
541 > public readonly validate: boolean,
542 > public readonly productVersion: string,
543 > public readonly productDate: string | undefined,
544 > public readonly productCommit: string | undefined,
545 > public readonly devMode: boolean,
546 > public readonly language: string | undefined,
547 > public readonly translations: Translations
548 > ) {
549 > // Keep empty!! (JSON.parse)
550 > }
551 >
552 > public static createNlsConfiguration(input: ExtensionScannerInput): NlsConfiguration {
553 return {
554 language: input.language,
558 };
559 }
561 > public static equals(a: ExtensionScannerInput, b: ExtensionScannerInput): boolean {
562 return (
563 isEqual(a.location, b.location)
577 );
578 }
580 >
581 > type NlsConfiguration = {
582 > language: string | undefined;
583 > pseudo: boolean;
584 > devMode: boolean;
585 > translations: Translations;
586 > };
587 >
588 > class ExtensionsScanner extends Disposable {
589 >
590 > private readonly productQuality: string | undefined;
591 > private readonly productBuiltInExtensionsEnabledWithAutoUpdates: Set<string>;
592 >
593 > constructor(
594 @IExtensionsProfileScannerService protected readonly extensionsProfileScannerService: IExtensionsProfileScannerService,
595 @IUriIdentityService protected readonly uriIdentityService: IUriIdentityService,
603 this.productBuiltInExtensionsEnabledWithAutoUpdates = getProductBuiltInExtensionsEnabledWithAutoUpdates(productService, environmentService);
604 }
606 > async scanExtensions(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
607 return input.profile
608 ? this.scanExtensionsFromProfile(input)
609 : this.scanExtensionsFromLocation(input);
610 }
612 > private async scanExtensionsFromLocation(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
613 const stat = await this.fileService.resolve(input.location);
614 if (!stat.children?.length) {
631 .sort((a, b) => a.location.path < b.location.path ? -1 : 1);
632 }
634 > private async scanExtensionsFromProfile(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
635 let profileExtensions = await this.scanExtensionsFromProfileResource(input.location, () => true, input);
636 if (input.applicationExtensionslocation && !this.uriIdentityService.extUri.isEqual(input.location, input.applicationExtensionslocation)) {
641 return profileExtensions;
642 }
644 > private async scanExtensionsFromProfileResource(profileResource: URI, filter: (extensionInfo: IScannedProfileExtension) => boolean, input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
645 const scannedProfileExtensions = await this.extensionsProfileScannerService.scanProfileExtensions(profileResource, input.profileScanOptions);
646 if (!scannedProfileExtensions.length) {
657 return coalesce(extensions);
658 }
660 > async scanOneOrMultipleExtensions(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
661 try {
662 if (await this.fileService.exists(joinPath(input.location, 'package.json'))) {
671 }
672 }
674 > async scanExtension(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension | null>;
675 > async scanExtension(input: ExtensionScannerInput, scannedProfileExtension: IScannedProfileExtension): Promise<IRelaxedScannedExtension>;
676 > async scanExtension(input: ExtensionScannerInput, scannedProfileExtension?: IScannedProfileExtension): Promise<IRelaxedScannedExtension | null> {
677 const validations: [Severity, string][] = [];
678 let isValid = true;
751 return extension;
752 }
754 > validate(extension: IRelaxedScannedExtension, input: ExtensionScannerInput): IRelaxedScannedExtension {
755 let isValid = extension.isValid;
756 const validations = validateExtensionManifest(input.productVersion, input.productDate, input.location, extension.manifest, extension.isBuiltin);
765 return extension;
766 }
768 > private async scanExtensionManifest(extensionLocation: URI): Promise<IScannedExtensionManifest> {
769 const manifestLocation = joinPath(extensionLocation, 'package.json');
770 let content;
796 return manifest;
797 }
799 > private async translateManifest(extensionLocation: URI, extensionManifest: IExtensionManifest, nlsConfiguration: NlsConfiguration): Promise<IExtensionManifest> {
800 const localizedMessages = await this.getLocalizedMessages(extensionLocation, extensionManifest, nlsConfiguration);
801 if (localizedMessages) {
821 return extensionManifest;
822 }
824 > private async getLocalizedMessages(extensionLocation: URI, extensionManifest: IExtensionManifest, nlsConfiguration: NlsConfiguration): Promise<LocalizedMessages | undefined> {
825 const defaultPackageNLS = joinPath(extensionLocation, 'package.nls.json');
826 const reportErrors = (localized: URI | null, errors: ParseError[]): void => {
886 }
887 }
889 > /**
890 > * Parses original message bundle, returns null if the original message bundle is null.
891 > */
892 > private async resolveOriginalMessageBundle(originalMessageBundle: URI | null, errors: ParseError[]): Promise<{ [key: string]: string } | undefined> {
893 if (originalMessageBundle) {
894 try {
901 return;
902 }
904 > /**
905 > * Finds localized message bundle and the original (unlocalized) one.
906 > * If the localized file is not present, returns null for the original and marks original as localized.
907 > */
908 > private findMessageBundles(extensionLocation: URI, nlsConfiguration: NlsConfiguration): Promise<{ localized: URI; original: URI | null }> {
909 return new Promise<{ localized: URI; original: URI | null }>((c, e) => {
910 const loop = (locale: string): void => {
929 });
930 }
932 > private formatMessage(extensionLocation: URI, message: string): string {
933 return `[${extensionLocation.path}]: ${message}`;
934 }
936 > }
937 >
938 > interface IExtensionCacheData {
939 > input: ExtensionScannerInput;
940 > result: IRelaxedScannedExtension[];
941 > }
942 >
943 > class CachedExtensionsScanner extends ExtensionsScanner {
944 >
945 > private input: ExtensionScannerInput | undefined;
946 > private readonly cacheValidatorThrottler: ThrottledDelayer<void> = this._register(new ThrottledDelayer(3000));
947 >
948 > private readonly _onDidChangeCache = this._register(new Emitter<void>());
949 > readonly onDidChangeCache = this._onDidChangeCache.event;
950 >
951 > constructor(
952 private readonly currentProfile: IUserDataProfile,
953 @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService,
961 super(extensionsProfileScannerService, uriIdentityService, fileService, productService, environmentService, logService);
962 }
964 > override async scanExtensions(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
965 const cacheFile = this.getCacheFile(input);
966 const cacheContents = await this.readExtensionCache(cacheFile);
979 return result;
980 }
982 > private async readExtensionCache(cacheFile: URI): Promise<IExtensionCacheData | null> {
983 try {
984 const cacheRawContents = await this.fileService.readFile(cacheFile);
992 return null;
993 }
995 > private async writeExtensionCache(cacheFile: URI, cacheContents: IExtensionCacheData): Promise<void> {
996 try {
997 await this.fileService.writeFile(cacheFile, VSBuffer.fromString(JSON.stringify(cacheContents)));
1000 }
1001 }
1003 > private async validateCache(): Promise<void> {
1004 if (!this.input) {
1005 // Input has been unset by the time we get here, so skip validation
1030 }
1031 }
1033 > private getCacheFile(input: ExtensionScannerInput): URI {
1034 const profile = this.getProfile(input);
1035 return this.uriIdentityService.extUri.joinPath(profile.cacheHome, input.type === ExtensionType.System ? BUILTIN_MANIFEST_CACHE_FILE : USER_MANIFEST_CACHE_FILE);
1036 }
1038 > private getProfile(input: ExtensionScannerInput): IUserDataProfile {
1039 if (input.type === ExtensionType.System) {
1040 return this.userDataProfilesService.defaultProfile;
1048 return this.userDataProfilesService.profiles.find(p => this.uriIdentityService.extUri.isEqual(input.location, p.extensionsResource)) ?? this.currentProfile;
1049 }
1051 > }
1052 >
1053 > export function toExtensionDescription(extension: IScannedExtension, isUnderDevelopment: boolean): IExtensionDescription {
1054 const id = getExtensionId(extension.manifest.publisher, extension.manifest.name);
1055 return {
1067 };
1068 }
1070 > export class NativeExtensionsScannerService extends AbstractExtensionsScannerService implements IExtensionsScannerService {
1071 >
1072 > private readonly translationsPromise: Promise<Translations>;
1073 >
1074 > constructor(
1075 systemExtensionsLocation: URI,
1076 userExtensionsLocation: URI,
src/vs/platform/extensionManagement/node/extensionsProfileScannerService.ts 16 introduced LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extensionsProfileScannerService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ILogService } from '../../log/common/log.js';
7 > import { IUserDataProfilesService } from '../../userDataProfile/common/userDataProfile.js';
8 > import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.js';
9 > import { AbstractExtensionsProfileScannerService } from '../common/extensionsProfileScannerService.js';
10 > import { IFileService } from '../../files/common/files.js';
11 > import { INativeEnvironmentService } from '../../environment/common/environment.js';
12 > import { URI } from '../../../base/common/uri.js';
13 >
14 > export class ExtensionsProfileScannerService extends AbstractExtensionsProfileScannerService {
15 > constructor(
16 @INativeEnvironmentService environmentService: INativeEnvironmentService,
17 @IFileService fileService: IFileService,
22 super(URI.file(environmentService.extensionsPath), fileService, userDataProfilesService, uriIdentityService, logService);
23 }