mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 13:00:58 +00:00
fixes #42229
This commit is contained in:
parent
8c938b14ee
commit
b51d61e362
|
@ -10,7 +10,7 @@ import { Readable } from 'stream';
|
|||
import { nfcall, ninvoke, SimpleThrottler } from 'vs/base/common/async';
|
||||
import { mkdirp, rimraf } from 'vs/base/node/pfs';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { open as openZip, Entry, ZipFile } from 'yauzl';
|
||||
import { open as _openZip, Entry, ZipFile } from 'yauzl';
|
||||
|
||||
export interface IExtractOptions {
|
||||
overwrite?: boolean;
|
||||
|
@ -26,6 +26,29 @@ interface IOptions {
|
|||
sourcePathRegex: RegExp;
|
||||
}
|
||||
|
||||
export enum ExtractErrorType {
|
||||
Undefined,
|
||||
CorruptZip
|
||||
}
|
||||
|
||||
export class ExtractError extends Error {
|
||||
|
||||
readonly type: ExtractErrorType;
|
||||
readonly cause: Error;
|
||||
|
||||
constructor(type: ExtractErrorType, cause: Error) {
|
||||
let message = cause.message;
|
||||
|
||||
switch (type) {
|
||||
case ExtractErrorType.CorruptZip: message = `Corrupt ZIP: ${message}`; break;
|
||||
}
|
||||
|
||||
super(message);
|
||||
this.type = type;
|
||||
this.cause = cause;
|
||||
}
|
||||
}
|
||||
|
||||
function modeFromEntry(entry: Entry) {
|
||||
let attr = entry.externalFileAttributes >> 16 || 33188;
|
||||
|
||||
|
@ -34,6 +57,18 @@ function modeFromEntry(entry: Entry) {
|
|||
.reduce((a, b) => a + b, attr & 61440 /* S_IFMT */);
|
||||
}
|
||||
|
||||
function toExtractError(err: Error): ExtractError {
|
||||
let type = ExtractErrorType.CorruptZip;
|
||||
|
||||
console.log('WHAT');
|
||||
|
||||
if (/end of central directory record signature not found/.test(err.message)) {
|
||||
type = ExtractErrorType.CorruptZip;
|
||||
}
|
||||
|
||||
return new ExtractError(type, err);
|
||||
}
|
||||
|
||||
function extractEntry(stream: Readable, fileName: string, mode: number, targetPath: string, options: IOptions): TPromise<void> {
|
||||
const dirName = path.dirname(fileName);
|
||||
const targetDirName = path.join(targetPath, dirName);
|
||||
|
@ -74,13 +109,18 @@ function extractZip(zipfile: ZipFile, targetPath: string, options: IOptions): TP
|
|||
|
||||
last = throttler.queue(() => stream.then(stream => extractEntry(stream, fileName, mode, targetPath, options)));
|
||||
});
|
||||
});
|
||||
}).then(null, err => TPromise.wrapError(toExtractError(err)));
|
||||
}
|
||||
|
||||
function openZip(zipFile: string): TPromise<ZipFile> {
|
||||
return nfcall<ZipFile>(_openZip, zipFile)
|
||||
.then(null, err => TPromise.wrapError(toExtractError(err)));
|
||||
}
|
||||
|
||||
export function extract(zipPath: string, targetPath: string, options: IExtractOptions = {}): TPromise<void> {
|
||||
const sourcePathRegex = new RegExp(options.sourcePath ? `^${options.sourcePath}` : '');
|
||||
|
||||
let promise = nfcall<ZipFile>(openZip, zipPath);
|
||||
let promise = openZip(zipPath);
|
||||
|
||||
if (options.overwrite) {
|
||||
promise = promise.then(zipfile => rimraf(targetPath).then(() => zipfile));
|
||||
|
@ -90,7 +130,7 @@ export function extract(zipPath: string, targetPath: string, options: IExtractOp
|
|||
}
|
||||
|
||||
function read(zipPath: string, filePath: string): TPromise<Readable> {
|
||||
return nfcall(openZip, zipPath).then((zipfile: ZipFile) => {
|
||||
return openZip(zipPath).then(zipfile => {
|
||||
return new TPromise<Readable>((c, e) => {
|
||||
zipfile.on('entry', (entry: Entry) => {
|
||||
if (entry.fileName === filePath) {
|
||||
|
|
|
@ -26,7 +26,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
|
|||
import { Query } from 'vs/workbench/parts/extensions/common/extensionQuery';
|
||||
import { IFileService, IContent } from 'vs/platform/files/common/files';
|
||||
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { IExtensionService, IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
|
||||
|
@ -42,7 +42,38 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
|||
import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IChoiceService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IQuickOpenService, IPickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
|
||||
class DownloadExtensionAction extends Action {
|
||||
|
||||
constructor(
|
||||
private extension: IExtension,
|
||||
@IOpenerService private openerService: IOpenerService,
|
||||
@INotificationService private notificationService: INotificationService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService
|
||||
) {
|
||||
super('extensions.download', localize('download', "Download Manually"), '', true);
|
||||
}
|
||||
|
||||
run(): TPromise<void> {
|
||||
return this.openerService.open(URI.parse(this.extension.downloadUrl)).then(() => {
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Info,
|
||||
message: localize('install vsix', 'Once downloaded, please manually install the downloaded VSIX of \'{0}\'.', this.extension.id),
|
||||
actions: {
|
||||
primary: [
|
||||
this.instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL)
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class InstallAction extends Action {
|
||||
|
||||
|
@ -58,7 +89,9 @@ export class InstallAction extends Action {
|
|||
set extension(extension: IExtension) { this._extension = extension; this.update(); }
|
||||
|
||||
constructor(
|
||||
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
|
||||
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@INotificationService private notificationService: INotificationService
|
||||
) {
|
||||
super('extensions.install', InstallAction.InstallLabel, InstallAction.Class, false);
|
||||
|
||||
|
@ -89,7 +122,27 @@ export class InstallAction extends Action {
|
|||
|
||||
run(): TPromise<any> {
|
||||
this.extensionsWorkbenchService.open(this.extension);
|
||||
return this.extensionsWorkbenchService.install(this.extension);
|
||||
|
||||
return this.install(this.extension);
|
||||
}
|
||||
|
||||
private install(extension: IExtension): TPromise<void> {
|
||||
return this.extensionsWorkbenchService.install(extension).then(null, err => {
|
||||
if (!extension.downloadUrl) {
|
||||
return this.notificationService.error(err);
|
||||
}
|
||||
|
||||
console.error(err);
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: localize('failedToInstall', "Failed to install \'{0}\'.", extension.id),
|
||||
actions: {
|
||||
primary: [
|
||||
this.instantiationService.createInstance(DownloadExtensionAction, extension)
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
@ -251,7 +304,9 @@ export class UpdateAction extends Action {
|
|||
set extension(extension: IExtension) { this._extension = extension; this.update(); }
|
||||
|
||||
constructor(
|
||||
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
|
||||
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@INotificationService private notificationService: INotificationService
|
||||
) {
|
||||
super('extensions.update', UpdateAction.Label, UpdateAction.DisabledClass, false);
|
||||
|
||||
|
@ -283,7 +338,26 @@ export class UpdateAction extends Action {
|
|||
}
|
||||
|
||||
run(): TPromise<any> {
|
||||
return this.extensionsWorkbenchService.install(this.extension);
|
||||
return this.install(this.extension);
|
||||
}
|
||||
|
||||
private install(extension: IExtension): TPromise<void> {
|
||||
return this.extensionsWorkbenchService.install(extension).then(null, err => {
|
||||
if (!extension.downloadUrl) {
|
||||
return this.notificationService.error(err);
|
||||
}
|
||||
|
||||
console.error(err);
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: localize('failedToInstall', "Failed to install \'{0}\'.", extension.id),
|
||||
actions: {
|
||||
primary: [
|
||||
this.instantiationService.createInstance(DownloadExtensionAction, extension)
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
@ -757,7 +831,9 @@ export class UpdateAllAction extends Action {
|
|||
constructor(
|
||||
id = UpdateAllAction.ID,
|
||||
label = UpdateAllAction.LABEL,
|
||||
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
|
||||
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@INotificationService private notificationService: INotificationService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService
|
||||
) {
|
||||
super(id, label, '', false);
|
||||
|
||||
|
@ -774,7 +850,26 @@ export class UpdateAllAction extends Action {
|
|||
}
|
||||
|
||||
run(): TPromise<any> {
|
||||
return TPromise.join(this.outdated.map(e => this.extensionsWorkbenchService.install(e)));
|
||||
return TPromise.join(this.outdated.map(e => this.install(e)));
|
||||
}
|
||||
|
||||
private install(extension: IExtension): TPromise<void> {
|
||||
return this.extensionsWorkbenchService.install(extension).then(null, err => {
|
||||
if (!extension.downloadUrl) {
|
||||
return this.notificationService.error(err);
|
||||
}
|
||||
|
||||
console.error(err);
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: localize('failedToInstall', "Failed to install \'{0}\'.", extension.id),
|
||||
actions: {
|
||||
primary: [
|
||||
this.instantiationService.createInstance(DownloadExtensionAction, extension)
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
@ -1109,7 +1204,8 @@ export class InstallWorkspaceRecommendedExtensionsAction extends Action {
|
|||
@IViewletService private viewletService: IViewletService,
|
||||
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IExtensionTipsService private extensionTipsService: IExtensionTipsService,
|
||||
@INotificationService private notificationService: INotificationService
|
||||
@INotificationService private notificationService: INotificationService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService
|
||||
) {
|
||||
super(id, label, 'extension-action');
|
||||
this.extensionsWorkbenchService.onChange(() => this.update(), this, this.disposables);
|
||||
|
@ -1154,18 +1250,37 @@ export class InstallWorkspaceRecommendedExtensionsAction extends Action {
|
|||
extensionsWithDependencies.push(e);
|
||||
return TPromise.as(null);
|
||||
} else {
|
||||
return this.extensionsWorkbenchService.install(e);
|
||||
return this.install(e);
|
||||
}
|
||||
}));
|
||||
}
|
||||
return TPromise.join(installPromises).then(() => {
|
||||
return TPromise.join(extensionsWithDependencies.map(e => this.extensionsWorkbenchService.install(e)));
|
||||
return TPromise.join(extensionsWithDependencies.map(e => this.install(e)));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private install(extension: IExtension): TPromise<void> {
|
||||
return this.extensionsWorkbenchService.install(extension).then(null, err => {
|
||||
if (!extension.downloadUrl) {
|
||||
return this.notificationService.error(err);
|
||||
}
|
||||
|
||||
console.error(err);
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: localize('failedToInstall', "Failed to install \'{0}\'.", extension.id),
|
||||
actions: {
|
||||
primary: [
|
||||
this.instantiationService.createInstance(DownloadExtensionAction, extension)
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
super.dispose();
|
||||
|
@ -1184,7 +1299,8 @@ export class InstallRecommendedExtensionAction extends Action {
|
|||
extensionId: string,
|
||||
@IViewletService private viewletService: IViewletService,
|
||||
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@INotificationService private notificationService: INotificationService
|
||||
@INotificationService private notificationService: INotificationService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService
|
||||
) {
|
||||
super(InstallRecommendedExtensionAction.ID, InstallRecommendedExtensionAction.LABEL, null);
|
||||
this.extensionId = extensionId;
|
||||
|
@ -1210,11 +1326,30 @@ export class InstallRecommendedExtensionAction extends Action {
|
|||
viewlet.focus();
|
||||
|
||||
return this.extensionsWorkbenchService.queryGallery({ names: [this.extensionId], source: 'install-recommendation' }).then(pager => {
|
||||
return (pager && pager.firstPage && pager.firstPage.length) ? this.extensionsWorkbenchService.install(pager.firstPage[0]) : TPromise.as(null);
|
||||
return (pager && pager.firstPage && pager.firstPage.length) ? this.install(pager.firstPage[0]) : TPromise.as(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private install(extension: IExtension): TPromise<void> {
|
||||
return this.extensionsWorkbenchService.install(extension).then(null, err => {
|
||||
if (!extension.downloadUrl) {
|
||||
return this.notificationService.error(err);
|
||||
}
|
||||
|
||||
console.error(err);
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: localize('failedToInstall', "Failed to install \'{0}\'.", extension.id),
|
||||
actions: {
|
||||
primary: [
|
||||
this.instantiationService.createInstance(DownloadExtensionAction, extension)
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
super.dispose();
|
||||
|
@ -1706,6 +1841,137 @@ export class EnableAllWorkpsaceAction extends Action {
|
|||
}
|
||||
}
|
||||
|
||||
export class OpenExtensionsFolderAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.openExtensionsFolder';
|
||||
static LABEL = localize('openExtensionsFolder', "Open Extensions Folder");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IWindowsService private windowsService: IWindowsService,
|
||||
@IFileService private fileService: IFileService,
|
||||
@IEnvironmentService private environmentService: IEnvironmentService
|
||||
) {
|
||||
super(id, label, null, true);
|
||||
}
|
||||
|
||||
run(): TPromise<void> {
|
||||
const extensionsHome = this.environmentService.extensionsPath;
|
||||
|
||||
return this.fileService.resolveFile(URI.file(extensionsHome)).then(file => {
|
||||
let itemToShow: string;
|
||||
if (file.children && file.children.length > 0) {
|
||||
itemToShow = file.children[0].resource.fsPath;
|
||||
} else {
|
||||
itemToShow = paths.normalize(extensionsHome, true);
|
||||
}
|
||||
|
||||
return this.windowsService.showItemInFolder(itemToShow);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class InstallVSIXAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.installVSIX';
|
||||
static LABEL = localize('installVSIX', "Install from VSIX...");
|
||||
|
||||
constructor(
|
||||
id = InstallVSIXAction.ID,
|
||||
label = InstallVSIXAction.LABEL,
|
||||
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IChoiceService private choiceService: IChoiceService,
|
||||
@IWindowService private windowsService: IWindowService
|
||||
) {
|
||||
super(id, label, 'extension-action install-vsix', true);
|
||||
}
|
||||
|
||||
run(): TPromise<any> {
|
||||
return this.windowsService.showOpenDialog({
|
||||
title: localize('installFromVSIX', "Install from VSIX"),
|
||||
filters: [{ name: 'VSIX Extensions', extensions: ['vsix'] }],
|
||||
properties: ['openFile'],
|
||||
buttonLabel: mnemonicButtonLabel(localize({ key: 'installButton', comment: ['&& denotes a mnemonic'] }, "&&Install"))
|
||||
}).then(result => {
|
||||
if (!result) {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
return TPromise.join(result.map(vsix => this.extensionsWorkbenchService.install(vsix))).then(() => {
|
||||
return this.choiceService.choose(Severity.Info, localize('InstallVSIXAction.success', "Successfully installed the extension. Reload to enable it."), [localize('InstallVSIXAction.reloadNow', "Reload Now")]).then(choice => {
|
||||
if (choice === 0) {
|
||||
return this.windowsService.reloadWindow();
|
||||
}
|
||||
|
||||
return TPromise.as(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ReinstallAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.reinstall';
|
||||
static LABEL = localize('reinstall', "Reinstall Extension...");
|
||||
|
||||
constructor(
|
||||
id: string = ReinstallAction.ID, label: string = ReinstallAction.LABEL,
|
||||
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IQuickOpenService private quickOpenService: IQuickOpenService,
|
||||
@INotificationService private notificationService: INotificationService,
|
||||
@IWindowService private windowService: IWindowService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
get enabled(): boolean {
|
||||
return this.extensionsWorkbenchService.local.filter(l => l.type === LocalExtensionType.User && l.local).length > 0;
|
||||
}
|
||||
|
||||
run(): TPromise<any> {
|
||||
return this.quickOpenService.pick(this.getEntries(), { placeHolder: localize('selectExtension', "Select Extension to Reinstall") });
|
||||
}
|
||||
|
||||
private getEntries(): TPromise<IPickOpenEntry[]> {
|
||||
return this.extensionsWorkbenchService.queryLocal()
|
||||
.then(local => {
|
||||
const entries: IPickOpenEntry[] = local
|
||||
.filter(extension => extension.type === LocalExtensionType.User)
|
||||
.map(extension => {
|
||||
return <IPickOpenEntry>{
|
||||
id: extension.id,
|
||||
label: extension.displayName,
|
||||
description: extension.id,
|
||||
run: () => this.reinstallExtension(extension),
|
||||
};
|
||||
});
|
||||
return entries;
|
||||
});
|
||||
}
|
||||
|
||||
private reinstallExtension(extension: IExtension): TPromise<void> {
|
||||
return this.extensionsWorkbenchService.reinstall(extension)
|
||||
.then(() => {
|
||||
this.notificationService.notify({
|
||||
message: localize('ReinstallAction.success', "Successfully reinstalled the extension."),
|
||||
severity: Severity.Info,
|
||||
actions: {
|
||||
primary: [<IAction>{
|
||||
id: 'reload',
|
||||
label: localize('ReinstallAction.reloadNow', "Reload Now"),
|
||||
enabled: true,
|
||||
run: () => this.windowService.reloadWindow(),
|
||||
dispose: () => null
|
||||
}]
|
||||
}
|
||||
});
|
||||
}, error => this.notificationService.error(error));
|
||||
}
|
||||
}
|
||||
|
||||
CommandsRegistry.registerCommand('workbench.extensions.action.showExtensionsForLanguage', function (accessor: ServicesAccessor, fileExtension: string) {
|
||||
const viewletService = accessor.get(IViewletService);
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ export interface IExtension {
|
|||
latestVersion: string;
|
||||
description: string;
|
||||
url: string;
|
||||
downloadUrl: string;
|
||||
repository: string;
|
||||
iconUrl: string;
|
||||
iconUrlFallback: string;
|
||||
|
|
|
@ -22,9 +22,8 @@ import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/e
|
|||
import {
|
||||
OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowRecommendedKeymapExtensionsAction, ShowPopularExtensionsAction,
|
||||
ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, ShowBuiltInExtensionsAction, UpdateAllAction,
|
||||
EnableAllAction, EnableAllWorkpsaceAction, DisableAllAction, DisableAllWorkpsaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, ShowAzureExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction, ConfigureRecommendedExtensionsCommandsContributor
|
||||
EnableAllAction, EnableAllWorkpsaceAction, DisableAllAction, DisableAllWorkpsaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, ShowAzureExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction, ConfigureRecommendedExtensionsCommandsContributor, OpenExtensionsFolderAction, InstallVSIXAction, ReinstallAction
|
||||
} from 'vs/workbench/parts/extensions/browser/extensionsActions';
|
||||
import { OpenExtensionsFolderAction, InstallVSIXAction, ReinstallAction } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions';
|
||||
import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput';
|
||||
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet';
|
||||
import { ExtensionEditor } from 'vs/workbench/parts/extensions/browser/extensionEditor';
|
||||
|
|
|
@ -29,10 +29,9 @@ import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, ExtensionS
|
|||
import {
|
||||
ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowDisabledExtensionsAction,
|
||||
ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction,
|
||||
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction
|
||||
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction
|
||||
} from 'vs/workbench/parts/extensions/browser/extensionsActions';
|
||||
import { LocalExtensionType, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { InstallVSIXAction } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions';
|
||||
import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput';
|
||||
import { ExtensionsListView, InstalledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInExtensionsView } from './extensionsViews';
|
||||
import { OpenGlobalSettingsAction } from 'vs/workbench/parts/preferences/browser/preferencesActions';
|
||||
|
|
|
@ -117,6 +117,14 @@ class Extension implements IExtension {
|
|||
return `${product.extensionsGallery.itemUrl}?itemName=${this.publisher}.${this.name}`;
|
||||
}
|
||||
|
||||
get downloadUrl(): string {
|
||||
if (!product.extensionsGallery) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return `${product.extensionsGallery.serviceUrl}/publishers/${this.publisher}/vsextensions/${this.name}/${this.latestVersion}/vspackage`;
|
||||
}
|
||||
|
||||
get iconUrl(): string {
|
||||
return this.galleryIconUrl || this.localIconUrl || this.defaultIconUrl;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue