Skip to content

Commit e9d6c6a

Browse files
authored
* fix #232043 * fix compilation error * fix compilation * fix compilation * fix compilation * fix compilation * fix compilation
1 parent 9a129c0 commit e9d6c6a

File tree

10 files changed

+97
-4
lines changed

10 files changed

+97
-4
lines changed

cli/src/bin/code/legacy_args.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::collections::HashMap;
77

88
use cli::commands::args::{
99
CliCore, Commands, DesktopCodeOptions, ExtensionArgs, ExtensionSubcommand,
10-
InstallExtensionArgs, ListExtensionArgs, UninstallExtensionArgs,
10+
InstallExtensionArgs, ListExtensionArgs, UninstallExtensionArgs, DownloadExtensionArgs,
1111
};
1212

1313
/// Tries to parse the argv using the legacy CLI interface, looking for its
@@ -64,6 +64,7 @@ pub fn try_parse_legacy(
6464
// Now translate them to subcommands.
6565
// --list-extensions -> ext list
6666
// --update-extensions -> update
67+
// --download-extension -> ext download <id>
6768
// --install-extension=id -> ext install <id>
6869
// --uninstall-extension=id -> ext uninstall <id>
6970
// --status -> status
@@ -79,6 +80,17 @@ pub fn try_parse_legacy(
7980
})),
8081
..Default::default()
8182
})
83+
} else if let Some(exts) = args.get("download-extension") {
84+
Some(CliCore {
85+
subcommand: Some(Commands::Extension(ExtensionArgs {
86+
subcommand: ExtensionSubcommand::Download(DownloadExtensionArgs {
87+
id: exts.to_vec(),
88+
location: get_first_arg_value("location"),
89+
}),
90+
desktop_code_options,
91+
})),
92+
..Default::default()
93+
})
8294
} else if let Some(exts) = args.remove("install-extension") {
8395
Some(CliCore {
8496
subcommand: Some(Commands::Extension(ExtensionArgs {

cli/src/commands/args.rs

+27
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ pub enum ExtensionSubcommand {
272272
Uninstall(UninstallExtensionArgs),
273273
/// Update the installed extensions.
274274
Update,
275+
/// Download an extension.
276+
Download(DownloadExtensionArgs),
275277
}
276278

277279
impl ExtensionSubcommand {
@@ -305,6 +307,16 @@ impl ExtensionSubcommand {
305307
ExtensionSubcommand::Update => {
306308
target.push("--update-extensions".to_string());
307309
}
310+
ExtensionSubcommand::Download(args) => {
311+
for id in args.id.iter() {
312+
target.push(format!("--download-extension={id}"));
313+
}
314+
if let Some(location) = &args.location {
315+
if !location.is_empty() {
316+
target.push(format!("--location={location}"));
317+
}
318+
}
319+
}
308320
}
309321
}
310322
}
@@ -347,6 +359,21 @@ pub struct UninstallExtensionArgs {
347359
pub id: Vec<String>,
348360
}
349361

362+
#[derive(Args, Debug, Clone)]
363+
pub struct DownloadExtensionArgs {
364+
/// Id of the extension to download. The identifier of an
365+
/// extension is '${publisher}.${name}'. Should provide '--location' to specify the location to download the VSIX.
366+
/// To download a specific version provide '@${version}'.
367+
/// For example: '[email protected]'.
368+
#[clap(name = "ext-id")]
369+
pub id: Vec<String>,
370+
371+
/// Specify the location to download the VSIX.
372+
#[clap(long, value_name = "location")]
373+
pub location: Option<String>,
374+
375+
}
376+
350377
#[derive(Args, Debug, Clone)]
351378
pub struct VersionArgs {
352379
#[clap(subcommand)]

resources/completions/bash/code

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ _@@APPNAME@@()
4949
--list-extensions --show-versions --install-extension
5050
--uninstall-extension --enable-proposed-api --verbose --log -s
5151
--status -p --performance --prof-startup --disable-extensions
52-
--disable-extension --inspect-extensions --update-extensions
52+
--disable-extension --inspect-extensions --update-extensions --download-extension
5353
--inspect-brk-extensions --disable-gpu' -- "$cur") )
5454
[[ $COMPREPLY == *= ]] && compopt -o nospace
5555
return

resources/completions/zsh/_code

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ arguments=(
2020
'--category[filters installed extension list by category, when using --list-extensions]'
2121
'--show-versions[show versions of installed extensions, when using --list-extensions]'
2222
'--install-extension[install an extension]:id or path:_files -g "*.vsix(-.)"'
23-
'--uninstall-extension[uninstall an extension]:id or path:_files -g "*.vsix(-.)"'
23+
'--uninstall-extension[uninstall an extension]:id'
2424
'--update-extensions[update the installed extensions]'
25+
'--download-extension[download an extension]:id'
2526
'--enable-proposed-api[enables proposed API features for extensions]::extension id: '
2627
'--verbose[print verbose output (implies --wait)]'
2728
'--log[log level to use]:level [info]:(critical error warn info debug trace off)'

src/vs/code/node/cli.ts

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ function shouldSpawnCliProcess(argv: NativeParsedArgs): boolean {
3333
return !!argv['install-source']
3434
|| !!argv['list-extensions']
3535
|| !!argv['install-extension']
36+
|| !!argv['download-extension']
3637
|| !!argv['uninstall-extension']
3738
|| !!argv['update-extensions']
3839
|| !!argv['locate-extension']

src/vs/code/node/cliProcessMain.ts

+8
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,14 @@ class CliMain extends Disposable {
282282
return instantiationService.createInstance(ExtensionManagementCLI, new ConsoleLogger(LogLevel.Info, false)).listExtensions(!!this.argv['show-versions'], this.argv['category'], profileLocation);
283283
}
284284

285+
// Download Extensions
286+
else if (this.argv['download-extension']) {
287+
if (!this.argv['location']) {
288+
throw new Error('The location argument is required to download an extension.');
289+
}
290+
return instantiationService.createInstance(ExtensionManagementCLI, new ConsoleLogger(LogLevel.Info, false)).downloadExtensions(this.argv['download-extension'], URI.parse(this.argv['location']));
291+
}
292+
285293
// Install Extension
286294
else if (this.argv['install-extension'] || this.argv['install-builtin-extension']) {
287295
const installOptions: InstallOptions = { isMachineScoped: !!this.argv['do-not-sync'], installPreReleaseVersion: !!this.argv['pre-release'], profileLocation };

src/vs/platform/environment/common/argv.ts

+2
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ export interface NativeParsedArgs {
7575
'disable-extensions'?: boolean;
7676
'disable-extension'?: string[]; // undefined or array of 1 or more
7777
'list-extensions'?: boolean;
78+
'download-extension'?: string[];
79+
'location'?: string;
7880
'show-versions'?: boolean;
7981
'category'?: string;
8082
'install-extension'?: string[]; // undefined or array of 1 or more

src/vs/platform/environment/node/argv.ts

+2
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ export const OPTIONS: OptionDescriptions<Required<NativeParsedArgs>> = {
9797
'list-extensions': { type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") },
9898
'show-versions': { type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extensions.") },
9999
'category': { type: 'string', allowEmptyValue: true, cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extensions."), args: 'category' },
100+
'download-extension': { type: 'string[]', cat: 'e', args: 'ext-id', description: localize('downloadExtension', "Downloads the extension VSIX that can be installable. The argument is an identifier of an extension that is '${publisher}.${name}'. To download a specific version provide '@${version}'. For example: '[email protected]'. Should provide '--location' to specify the location to download the VSIX.") },
100101
'install-extension': { type: 'string[]', cat: 'e', args: 'ext-id | path', description: localize('installExtension', "Installs or updates an extension. The argument is either an extension id or a path to a VSIX. The identifier of an extension is '${publisher}.${name}'. Use '--force' argument to update to latest version. To install a specific version provide '@${version}'. For example: '[email protected]'.") },
101102
'pre-release': { type: 'boolean', cat: 'e', description: localize('install prerelease', "Installs the pre-release version of the extension, when using --install-extension") },
102103
'uninstall-extension': { type: 'string[]', cat: 'e', args: 'ext-id', description: localize('uninstallExtension', "Uninstalls an extension.") },
@@ -163,6 +164,7 @@ export const OPTIONS: OptionDescriptions<Required<NativeParsedArgs>> = {
163164
'file-chmod': { type: 'boolean' },
164165
'install-builtin-extension': { type: 'string[]' },
165166
'force': { type: 'boolean' },
167+
'location': { type: 'string' },
166168
'do-not-sync': { type: 'boolean' },
167169
'trace': { type: 'boolean' },
168170
'trace-category-filter': { type: 'string' },

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

+38
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { EXTENSION_IDENTIFIER_REGEX, IExtensionGalleryService, IExtensionInfo, I
1414
import { areSameExtensions, getExtensionId, getGalleryExtensionId, getIdAndVersion } from './extensionManagementUtil.js';
1515
import { ExtensionType, EXTENSION_CATEGORIES, IExtensionManifest } from '../../extensions/common/extensions.js';
1616
import { ILogger } from '../../log/common/log.js';
17+
import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.js';
1718

1819

1920
const notFound = (id: string) => localize('notFound', "Extension '{0}' not found.", id);
@@ -28,6 +29,7 @@ export class ExtensionManagementCLI {
2829
protected readonly logger: ILogger,
2930
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
3031
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
32+
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
3133
) { }
3234

3335
protected get location(): string | undefined {
@@ -70,6 +72,42 @@ export class ExtensionManagementCLI {
7072
}
7173
}
7274

75+
public async downloadExtensions(extensions: string[], target: URI): Promise<void> {
76+
if (!extensions.length) {
77+
return;
78+
}
79+
80+
this.logger.info(localize('downloadingExtensions', "Downloading extensions..."));
81+
82+
const extensionsInfo: IExtensionInfo[] = [];
83+
for (const extension of extensions) {
84+
const [id, version] = getIdAndVersion(extension);
85+
extensionsInfo.push({ id, version: version !== 'prerelease' ? version : undefined, preRelease: version === 'prerelease' });
86+
}
87+
88+
try {
89+
const galleryExtensions = await this.extensionGalleryService.getExtensions(extensionsInfo, CancellationToken.None);
90+
const targetPlatform = await this.extensionManagementService.getTargetPlatform();
91+
await Promise.allSettled(extensionsInfo.map(async extensionInfo => {
92+
const galleryExtension = galleryExtensions.find(e => areSameExtensions(e.identifier, { id: extensionInfo.id }));
93+
if (!galleryExtension) {
94+
this.logger.error(`${notFound(extensionInfo.id)}\n${useId}`);
95+
return;
96+
}
97+
const compatible = await this.extensionGalleryService.getCompatibleExtension(galleryExtension, !!extensionInfo.hasPreRelease, targetPlatform);
98+
try {
99+
await this.extensionGalleryService.download(compatible ?? galleryExtension, this.uriIdentityService.extUri.joinPath(target, `${galleryExtension.identifier.id}-${galleryExtension.version}.vsix`), InstallOperation.None);
100+
this.logger.info(localize('successDownload', "Extension '{0}' was successfully downloaded.", extensionInfo.id));
101+
} catch (error) {
102+
this.logger.error(localize('error while downloading extension', "Error while downloading extension '{0}': {1}", extensionInfo.id, getErrorMessage(error)));
103+
}
104+
}));
105+
} catch (error) {
106+
this.logger.error(localize('error while downloading extensions', "Error while downloading extensions: {0}", getErrorMessage(error)));
107+
throw error;
108+
}
109+
}
110+
73111
public async installExtensions(extensions: (string | URI)[], builtinExtensions: (string | URI)[], installOptions: InstallOptions, force: boolean): Promise<void> {
74112
const failed: string[] = [];
75113

src/vs/workbench/api/browser/mainThreadCLICommands.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { ServiceCollection } from '../../../platform/instantiation/common/servic
1818
import { ILabelService } from '../../../platform/label/common/label.js';
1919
import { AbstractMessageLogger, ILogger, LogLevel } from '../../../platform/log/common/log.js';
2020
import { IOpenerService } from '../../../platform/opener/common/opener.js';
21+
import { IUriIdentityService } from '../../../platform/uriIdentity/common/uriIdentity.js';
2122
import { IOpenWindowOptions, IWindowOpenable } from '../../../platform/window/common/window.js';
2223
import { IWorkbenchEnvironmentService } from '../../services/environment/common/environmentService.js';
2324
import { IExtensionManagementServerService } from '../../services/extensionManagement/common/extensionManagement.js';
@@ -103,11 +104,12 @@ class RemoteExtensionManagementCLI extends ExtensionManagementCLI {
103104
logger: ILogger,
104105
@IExtensionManagementService extensionManagementService: IExtensionManagementService,
105106
@IExtensionGalleryService extensionGalleryService: IExtensionGalleryService,
107+
@IUriIdentityService uriIdentityService: IUriIdentityService,
106108
@ILabelService labelService: ILabelService,
107109
@IWorkbenchEnvironmentService envService: IWorkbenchEnvironmentService,
108110
@IExtensionManifestPropertiesService private readonly _extensionManifestPropertiesService: IExtensionManifestPropertiesService,
109111
) {
110-
super(logger, extensionManagementService, extensionGalleryService);
112+
super(logger, extensionManagementService, extensionGalleryService, uriIdentityService);
111113

112114
const remoteAuthority = envService.remoteAuthority;
113115
this._location = remoteAuthority ? labelService.getHostLabel(Schemas.vscodeRemote, remoteAuthority) : undefined;

0 commit comments

Comments
 (0)