Skip to content

Commit 66c63cc

Browse files
committed
review feedback
1 parent 387563c commit 66c63cc

File tree

8 files changed

+211
-338
lines changed

8 files changed

+211
-338
lines changed

src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ class SharedProcessMain extends Disposable {
314314
// Extension Management
315315
services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService, undefined, true));
316316
services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService, undefined, true));
317-
services.set(IExtensionSignatureVerificationService, new SyncDescriptor(ExtensionSignatureVerificationService));
317+
services.set(IExtensionSignatureVerificationService, new SyncDescriptor(ExtensionSignatureVerificationService, undefined, true));
318318
services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService, undefined, true));
319319

320320
// Extension Gallery

src/vs/code/node/cliProcessMain.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ class CliMain extends Disposable {
182182
// Extensions
183183
services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService, undefined, true));
184184
services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService, undefined, true));
185-
services.set(IExtensionSignatureVerificationService, new SyncDescriptor(ExtensionSignatureVerificationService));
185+
services.set(IExtensionSignatureVerificationService, new SyncDescriptor(ExtensionSignatureVerificationService, undefined, true));
186186
services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService, undefined, true));
187187
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryServiceWithNoStorageService, undefined, true));
188188

src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export interface IInstallExtensionTask {
2828
readonly identifier: IExtensionIdentifier;
2929
readonly source: IGalleryExtension | URI;
3030
readonly operation: InstallOperation;
31-
wasVerified?: boolean;
31+
readonly wasVerified?: boolean;
3232
run(): Promise<{ local: ILocalExtension; metadata: Metadata }>;
3333
waitUntilTaskIsFinished(): Promise<{ local: ILocalExtension; metadata: Metadata }>;
3434
cancel(): void;

src/vs/platform/extensionManagement/common/extensionGalleryService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ function toExtension(galleryExtension: IRawGalleryExtension, version: IRawGaller
507507
download: getDownloadAsset(version),
508508
icon: getVersionAsset(version, AssetType.Icon),
509509
signature: getVersionAsset(version, AssetType.Signature),
510-
coreTranslations: getCoreTranslationAssets(version),
510+
coreTranslations: getCoreTranslationAssets(version)
511511
};
512512

513513
return {
@@ -1036,7 +1036,7 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi
10361036

10371037
async downloadSignatureArchive(extension: IGalleryExtension, location: URI): Promise<void> {
10381038
if (!extension.assets.signature) {
1039-
return;
1039+
throw new Error('No signature asset found');
10401040
}
10411041

10421042
this.logService.trace('ExtensionGalleryService#downloadSignatureArchive', extension.identifier.id);

src/vs/platform/extensionManagement/node/extensionDownloader.ts

Lines changed: 49 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { Promises } from 'vs/base/common/async';
77
import { getErrorMessage } from 'vs/base/common/errors';
8-
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
8+
import { Disposable } from 'vs/base/common/lifecycle';
99
import { isWindows } from 'vs/base/common/platform';
1010
import { joinPath } from 'vs/base/common/resources';
1111
import * as semver from 'vs/base/common/semver/semver';
@@ -18,19 +18,14 @@ import { ExtensionKey, groupByExtension } from 'vs/platform/extensionManagement/
1818
import { IFileService, IFileStatWithMetadata } from 'vs/platform/files/common/files';
1919
import { ILogService } from 'vs/platform/log/common/log';
2020

21-
export interface IExtensionsDownloader extends IDisposable {
22-
delete(location: URI): Promise<void>;
23-
downloadExtension(extension: IGalleryExtension, operation: InstallOperation): Promise<{ extensionLocation: URI; signatureArchiveLocation?: URI }>;
24-
}
21+
export class ExtensionsDownloader extends Disposable {
2522

26-
export class ExtensionsDownloader extends Disposable implements IExtensionsDownloader {
23+
private static readonly SignatureArchiveExtension = '.sigzip';
2724

2825
readonly extensionsDownloadDir: URI;
2926
private readonly cache: number;
3027
private readonly cleanUpPromise: Promise<void>;
3128

32-
private static readonly SignatureArchiveExtension = '.sigzip';
33-
3429
constructor(
3530
@INativeEnvironmentService environmentService: INativeEnvironmentService,
3631
@IFileService private readonly fileService: IFileService,
@@ -43,44 +38,46 @@ export class ExtensionsDownloader extends Disposable implements IExtensionsDownl
4338
this.cleanUpPromise = this.cleanUp();
4439
}
4540

46-
async downloadExtension(extension: IGalleryExtension, operation: InstallOperation): Promise<{ extensionLocation: URI; signatureArchiveLocation?: URI }> {
41+
async downloadVSIX(extension: IGalleryExtension, operation: InstallOperation): Promise<URI> {
4742
await this.cleanUpPromise;
48-
const vsixName = this.getName(extension);
49-
const extensionLocation = joinPath(this.extensionsDownloadDir, vsixName);
50-
let signatureArchiveLocation: URI | undefined;
5143

52-
await this.downloadFile(extensionLocation, extension, operation, 'vsix', this.extensionGalleryService.download);
53-
54-
if (extension.assets.signature) {
55-
signatureArchiveLocation = ExtensionsDownloader.getSignatureArchiveLocation(extensionLocation);
44+
const location = joinPath(this.extensionsDownloadDir, this.getName(extension));
45+
await this.downloadFile(extension, location, location => this.extensionGalleryService.download(extension, location, operation));
46+
return location;
47+
}
5648

57-
await this.downloadFile(signatureArchiveLocation, extension, operation, 'signature archive', this.extensionGalleryService.downloadSignatureArchive);
58-
}
49+
async downloadSignatureArchive(extension: IGalleryExtension): Promise<URI> {
50+
await this.cleanUpPromise;
5951

60-
return { extensionLocation, signatureArchiveLocation };
52+
const location = joinPath(this.extensionsDownloadDir, `${this.getName(extension)}${ExtensionsDownloader.SignatureArchiveExtension}`);
53+
await this.downloadFile(extension, location, location => this.extensionGalleryService.downloadSignatureArchive(extension, location));
54+
return location;
6155
}
6256

63-
private async downloadFile(location: URI, extension: IGalleryExtension, operation: InstallOperation, fileType: string, download: (extension: IGalleryExtension, location: URI, operation: InstallOperation) => Promise<void>) {
64-
if (!await this.fileService.exists(location)) {
65-
// Download to temporary location first only if file does not exist
66-
const tempLocation = joinPath(this.extensionsDownloadDir, `.${generateUuid()}`);
67-
if (!await this.fileService.exists(tempLocation)) {
68-
await download(extension, tempLocation, operation);
69-
}
57+
private async downloadFile(extension: IGalleryExtension, location: URI, downloadFn: (location: URI) => Promise<void>): Promise<void> {
58+
// Do not download if exists
59+
if (await this.fileService.exists(location)) {
60+
return;
61+
}
62+
63+
// Download to temporary location first only if file does not exist
64+
const tempLocation = joinPath(this.extensionsDownloadDir, `.${generateUuid()}`);
65+
if (!await this.fileService.exists(tempLocation)) {
66+
await downloadFn(tempLocation);
67+
}
7068

69+
try {
70+
// Rename temp location to original
71+
await this.rename(tempLocation, location, Date.now() + (2 * 60 * 1000) /* Retry for 2 minutes */);
72+
} catch (error) {
7173
try {
72-
// Rename temp location to original
73-
await this.rename(tempLocation, location, Date.now() + (2 * 60 * 1000) /* Retry for 2 minutes */);
74-
} catch (error) {
75-
try {
76-
await this.fileService.del(tempLocation);
77-
} catch (e) { /* ignore */ }
78-
if (error.code === 'ENOTEMPTY') {
79-
this.logService.info(`Rename failed because ${fileType} was downloaded by another source. So ignoring renaming.`, extension.identifier.id);
80-
} else {
81-
this.logService.info(`Rename failed because of ${getErrorMessage(error)}. Deleted the ${fileType} from downloaded location`, tempLocation.path);
82-
throw error;
83-
}
74+
await this.fileService.del(tempLocation);
75+
} catch (e) { /* ignore */ }
76+
if (error.code === 'ENOTEMPTY') {
77+
this.logService.info(`Rename failed because the file was downloaded by another source. So ignoring renaming.`, extension.identifier.id, location.path);
78+
} else {
79+
this.logService.info(`Rename failed because of ${getErrorMessage(error)}. Deleted the file from downloaded location`, tempLocation.path);
80+
throw error;
8481
}
8582
}
8683
}
@@ -111,24 +108,21 @@ export class ExtensionsDownloader extends Disposable implements IExtensionsDownl
111108
const folderStat = await this.fileService.resolve(this.extensionsDownloadDir, { resolveMetadata: true });
112109
if (folderStat.children) {
113110
const toDelete: URI[] = [];
114-
const all: [ExtensionKey, IFileStatWithMetadata][] = [];
115-
const signatureArchives = new Set<string>();
111+
const vsixs: [ExtensionKey, IFileStatWithMetadata][] = [];
112+
const signatureArchives: URI[] = [];
116113

117114
for (const stat of folderStat.children) {
118-
const name = stat.name;
119-
120-
if (ExtensionsDownloader.isSignatureArchive(name)) {
121-
const extensionPath = ExtensionsDownloader.getExtensionPath(name);
122-
signatureArchives.add(extensionPath);
123-
continue;
124-
}
125-
126-
const extension = ExtensionKey.parse(name);
127-
if (extension) {
128-
all.push([extension, stat]);
115+
if (stat.name.endsWith(ExtensionsDownloader.SignatureArchiveExtension)) {
116+
signatureArchives.push(stat.resource);
117+
} else {
118+
const extension = ExtensionKey.parse(stat.name);
119+
if (extension) {
120+
vsixs.push([extension, stat]);
121+
}
129122
}
130123
}
131-
const byExtension = groupByExtension(all, ([extension]) => extension);
124+
125+
const byExtension = groupByExtension(vsixs, ([extension]) => extension);
132126
const distinct: IFileStatWithMetadata[] = [];
133127
for (const p of byExtension) {
134128
p.sort((a, b) => semver.rcompare(a[0].version, b[0].version));
@@ -137,40 +131,18 @@ export class ExtensionsDownloader extends Disposable implements IExtensionsDownl
137131
}
138132
distinct.sort((a, b) => a.mtime - b.mtime); // sort by modified time
139133
toDelete.push(...distinct.slice(0, Math.max(0, distinct.length - this.cache)).map(s => s.resource)); // Retain minimum cacheSize and delete the rest
134+
toDelete.push(...signatureArchives); // Delete all signature archives
140135

141136
await Promises.settled(toDelete.map(resource => {
142-
this.logService.trace('Deleting vsix from cache', resource.path);
143-
144-
let promise = Promise.resolve();
145-
146-
if (signatureArchives.has(resource.fsPath)) {
147-
const signatureArchiveLocation = ExtensionsDownloader.getSignatureArchiveLocation(resource);
148-
149-
promise = promise.then(() => this.fileService.del(signatureArchiveLocation));
150-
}
151-
152-
promise = promise.then(() => this.fileService.del(resource));
153-
154-
return promise;
137+
this.logService.trace('Deleting from cache', resource.path);
138+
return this.fileService.del(resource);
155139
}));
156140
}
157141
} catch (e) {
158142
this.logService.error(e);
159143
}
160144
}
161145

162-
private static getExtensionPath(signatureArchivePath: string): string {
163-
return signatureArchivePath.substring(0, signatureArchivePath.length - ExtensionsDownloader.SignatureArchiveExtension.length);
164-
}
165-
166-
private static getSignatureArchiveLocation(extensionLocation: URI): URI {
167-
return URI.file(extensionLocation.fsPath + ExtensionsDownloader.SignatureArchiveExtension);
168-
}
169-
170-
private static isSignatureArchive(name: string): boolean {
171-
return name.endsWith(ExtensionsDownloader.SignatureArchiveExtension);
172-
}
173-
174146
private getName(extension: IGalleryExtension): string {
175147
return this.cache ? ExtensionKey.create(extension).toString().toLowerCase() : generateUuid();
176148
}

0 commit comments

Comments
 (0)