Skip to content

Commit 7c39b50

Browse files
authored
also store extension manifests when storing extensions (microsoft#166237)
1 parent 925b4ff commit 7c39b50

File tree

1 file changed

+72
-53
lines changed

1 file changed

+72
-53
lines changed

src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts

Lines changed: 72 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ interface IStoredWebExtension {
5858
readonly identifier: IExtensionIdentifier;
5959
readonly version: string;
6060
readonly location: UriComponents;
61+
readonly manifest?: string;
6162
readonly readmeUri?: UriComponents;
6263
readonly changelogUri?: UriComponents;
6364
// deprecated in favor of packageNLSUris & fallbackPackageNLSUri
@@ -71,6 +72,7 @@ interface IWebExtension {
7172
identifier: IExtensionIdentifier;
7273
version: string;
7374
location: URI;
75+
manifest?: IExtensionManifest;
7476
readmeUri?: URI;
7577
changelogUri?: URI;
7678
// deprecated in favor of packageNLSUris & fallbackPackageNLSUri
@@ -425,16 +427,12 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
425427
}
426428

427429
async scanExtensionManifest(extensionLocation: URI): Promise<IExtensionManifest | null> {
428-
const packageJSONUri = joinPath(extensionLocation, 'package.json');
429430
try {
430-
const content = await this.extensionResourceLoaderService.readExtensionResource(packageJSONUri);
431-
if (content) {
432-
return JSON.parse(content);
433-
}
431+
return await this.getExtensionManifest(extensionLocation);
434432
} catch (error) {
435-
this.logService.warn(`Error while fetching package.json from ${packageJSONUri.toString()}`, getErrorMessage(error));
433+
this.logService.warn(`Error while fetching manifest from ${extensionLocation.toString()}`, getErrorMessage(error));
434+
return null;
436435
}
437-
return null;
438436
}
439437

440438
async addExtensionFromGallery(galleryExtension: IGalleryExtension, metadata: Metadata, profileLocation: URI): Promise<IScannedExtension> {
@@ -593,18 +591,13 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
593591
}
594592

595593
private async toWebExtension(extensionLocation: URI, identifier?: IExtensionIdentifier, packageNLSUris?: Map<string, URI>, bundleNLSUris?: Map<string, URI>, fallbackPackageNLSUri?: URI | null, readmeUri?: URI, changelogUri?: URI, metadata?: Metadata): Promise<IWebExtension> {
596-
let packageJSONContent;
594+
let manifest: IExtensionManifest;
597595
try {
598-
packageJSONContent = await this.extensionResourceLoaderService.readExtensionResource(joinPath(extensionLocation, 'package.json'));
596+
manifest = await this.getExtensionManifest(extensionLocation);
599597
} catch (error) {
600-
throw new Error(`Cannot find the package.json from the location '${extensionLocation.toString()}'. ${getErrorMessage(error)}`);
598+
throw new Error(`Error while fetching manifest from the location '${extensionLocation.toString()}'. ${getErrorMessage(error)}`);
601599
}
602600

603-
if (!packageJSONContent) {
604-
throw new Error(`Error while fetching package.json for extension '${extensionLocation.toString()}'. Server returned no content`);
605-
}
606-
607-
const manifest = JSON.parse(packageJSONContent);
608601
if (!this.extensionManifestPropertiesService.canExecuteOnWeb(manifest)) {
609602
throw new Error(localize('not a web extension', "Cannot add '{0}' because this extension is not a web extension.", manifest.displayName || manifest.name));
610603
}
@@ -618,7 +611,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
618611
}
619612
}
620613

621-
if (bundleNLSUris === undefined) {
614+
if (bundleNLSUris === undefined && manifest.browser) {
622615
const englishStringsUri = joinPath(
623616
this.uriIdentityService.extUri.dirname(joinPath(extensionLocation, manifest.browser)),
624617
'nls.metadata.json'
@@ -637,6 +630,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
637630
identifier: { id: getGalleryExtensionId(manifest.publisher, manifest.name), uuid: identifier?.uuid },
638631
version: manifest.version,
639632
location: extensionLocation,
633+
manifest,
640634
readmeUri,
641635
changelogUri,
642636
packageNLSUris,
@@ -647,25 +641,14 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
647641
}
648642

649643
private async toScannedExtension(webExtension: IWebExtension, isBuiltin: boolean, type: ExtensionType = ExtensionType.User): Promise<IScannedExtension> {
650-
const url = joinPath(webExtension.location, 'package.json');
651-
652644
const validations: [Severity, string][] = [];
653-
let content: string | undefined;
654-
try {
655-
content = await this.extensionResourceLoaderService.readExtensionResource(url);
656-
if (!content) {
657-
validations.push([Severity.Error, `Error while fetching package.json from the location '${url}'. Server returned no content`]);
658-
}
659-
} catch (error) {
660-
validations.push([Severity.Error, `Error while fetching package.json from the location '${url}'. ${getErrorMessage(error)}`]);
661-
}
645+
let manifest: IExtensionManifest | undefined = webExtension.manifest;
662646

663-
let manifest: IExtensionManifest | null = null;
664-
if (content) {
647+
if (!manifest) {
665648
try {
666-
manifest = JSON.parse(content);
649+
manifest = await this.getExtensionManifest(webExtension.location);
667650
} catch (error) {
668-
validations.push([Severity.Error, `Error while parsing package.json. ${getErrorMessage(error)}`]);
651+
validations.push([Severity.Error, `Error while fetching manifest from the location '${webExtension.location}'. ${getErrorMessage(error)}`]);
669652
}
670653
}
671654

@@ -764,6 +747,12 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
764747
return this._migratePackageNLSUrisPromise;
765748
}
766749

750+
private async getExtensionManifest(location: URI): Promise<IExtensionManifest> {
751+
const url = joinPath(location, 'package.json');
752+
const content = await this.extensionResourceLoaderService.readExtensionResource(url);
753+
return JSON.parse(content);
754+
}
755+
767756
private async readInstalledExtensions(profileLocation: URI): Promise<IWebExtension[]> {
768757
if (this.uriIdentityService.extUri.isEqual(profileLocation, this.userDataProfilesService.defaultProfile.extensionsResource)) {
769758
await this.migratePackageNLSUris();
@@ -817,6 +806,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
817806
identifier: e.identifier,
818807
version: e.version,
819808
location: URI.revive(e.location),
809+
manifest: e.manifest ? JSON.parse(e.manifest) : undefined,
820810
readmeUri: URI.revive(e.readmeUri),
821811
changelogUri: URI.revive(e.changelogUri),
822812
packageNLSUris,
@@ -825,6 +815,13 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
825815
metadata: e.metadata,
826816
});
827817
}
818+
819+
try {
820+
webExtensions = await this.migrateWebExtensions(webExtensions, file);
821+
} catch (error) {
822+
this.logService.error(`Error while migrating scanned extensions in ${file.toString()}`, getErrorMessage(error));
823+
}
824+
828825
} catch (error) {
829826
/* Ignore */
830827
if ((<FileOperationError>error).fileOperationResult !== FileOperationResult.FILE_NOT_FOUND) {
@@ -834,37 +831,59 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
834831

835832
// Update
836833
if (updateFn) {
837-
webExtensions = updateFn(webExtensions);
838-
function toStringDictionary(dictionary: Map<string, URI> | undefined): IStringDictionary<UriComponents> | undefined {
839-
if (!dictionary) {
840-
return undefined;
841-
}
842-
const result: IStringDictionary<UriComponents> = Object.create(null);
843-
dictionary.forEach((value, key) => result[key] = value.toJSON());
844-
return result;
845-
}
846-
const storedWebExtensions: IStoredWebExtension[] = webExtensions.map(e => ({
847-
identifier: e.identifier,
848-
version: e.version,
849-
location: e.location.toJSON(),
850-
readmeUri: e.readmeUri?.toJSON(),
851-
changelogUri: e.changelogUri?.toJSON(),
852-
packageNLSUris: toStringDictionary(e.packageNLSUris),
853-
fallbackPackageNLSUri: e.fallbackPackageNLSUri?.toJSON(),
854-
metadata: e.metadata
855-
}));
856-
await this.fileService.writeFile(file, VSBuffer.fromString(JSON.stringify(storedWebExtensions)));
834+
await this.storeWebExtensions(webExtensions = updateFn(webExtensions), file);
857835
}
858836

859837
return webExtensions;
860838
});
861839
}
862840

841+
private async migrateWebExtensions(webExtensions: IWebExtension[], file: URI): Promise<IWebExtension[]> {
842+
let update = false;
843+
webExtensions = await Promise.all(webExtensions.map(async webExtension => {
844+
if (!webExtension.manifest) {
845+
try {
846+
webExtension.manifest = await this.getExtensionManifest(webExtension.location);
847+
update = true;
848+
} catch (error) {
849+
this.logService.error(`Error while updating manifest of an extension in ${file.toString()}`, webExtension.identifier.id, getErrorMessage(error));
850+
}
851+
}
852+
return webExtension;
853+
}));
854+
if (update) {
855+
await this.storeWebExtensions(webExtensions, file);
856+
}
857+
return webExtensions;
858+
}
859+
860+
private async storeWebExtensions(webExtensions: IWebExtension[], file: URI): Promise<void> {
861+
function toStringDictionary(dictionary: Map<string, URI> | undefined): IStringDictionary<UriComponents> | undefined {
862+
if (!dictionary) {
863+
return undefined;
864+
}
865+
const result: IStringDictionary<UriComponents> = Object.create(null);
866+
dictionary.forEach((value, key) => result[key] = value.toJSON());
867+
return result;
868+
}
869+
const storedWebExtensions: IStoredWebExtension[] = webExtensions.map(e => ({
870+
identifier: e.identifier,
871+
version: e.version,
872+
manifest: e.manifest ? JSON.stringify(e.manifest) : undefined,
873+
location: e.location.toJSON(),
874+
readmeUri: e.readmeUri?.toJSON(),
875+
changelogUri: e.changelogUri?.toJSON(),
876+
packageNLSUris: toStringDictionary(e.packageNLSUris),
877+
fallbackPackageNLSUri: e.fallbackPackageNLSUri?.toJSON(),
878+
metadata: e.metadata
879+
}));
880+
await this.fileService.writeFile(file, VSBuffer.fromString(JSON.stringify(storedWebExtensions)));
881+
}
882+
863883
private getResourceAccessQueue(file: URI): Queue<IWebExtension[]> {
864884
let resourceQueue = this.resourcesAccessQueueMap.get(file);
865885
if (!resourceQueue) {
866-
resourceQueue = new Queue<IWebExtension[]>();
867-
this.resourcesAccessQueueMap.set(file, resourceQueue);
886+
this.resourcesAccessQueueMap.set(file, resourceQueue = new Queue<IWebExtension[]>());
868887
}
869888
return resourceQueue;
870889
}

0 commit comments

Comments
 (0)