@codingame/monaco-vscode-extensions-service-override
Version:
VSCode public API plugged on the monaco editor - extensions service-override
399 lines (396 loc) • 19.5 kB
JavaScript
import { __decorate, __param } from 'vscode/external/tslib/tslib.es6.js';
import { CancellationToken } from 'vscode/vscode/vs/base/common/cancellation';
import { getErrorMessage, isCancellationError } from 'vscode/vscode/vs/base/common/errors';
import { Schemas } from 'vscode/vscode/vs/base/common/network';
import { basename } from 'vscode/vscode/vs/base/common/resources';
import { semverExports } from 'vscode/external/vscode-semver/semver.js';
import { URI } from 'vscode/vscode/vs/base/common/uri';
import { localize } from 'vscode/vscode/vs/nls';
import { InstallOperation, EXTENSION_IDENTIFIER_REGEX } from 'vscode/vscode/vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionManagementService, IExtensionGalleryService } from 'vscode/vscode/vs/platform/extensionManagement/common/extensionManagement.service';
import { getIdAndVersion, areSameExtensions, getGalleryExtensionId, getExtensionId } from 'vscode/vscode/vs/platform/extensionManagement/common/extensionManagementUtil';
import { ExtensionType, EXTENSION_CATEGORIES } from 'vscode/vscode/vs/platform/extensions/common/extensions';
const notFound = (id) => ( localize(9800, "Extension '{0}' not found.", id));
const useId = ( localize(
9801,
"Make sure you use the full extension ID, including the publisher, e.g.: {0}",
'ms-dotnettools.csharp'
));
let ExtensionManagementCLI = class ExtensionManagementCLI {
constructor(logger, extensionManagementService, extensionGalleryService) {
this.logger = logger;
this.extensionManagementService = extensionManagementService;
this.extensionGalleryService = extensionGalleryService;
}
get location() {
return undefined;
}
async listExtensions(showVersions, category, profileLocation) {
let extensions = await this.extensionManagementService.getInstalled(ExtensionType.User, profileLocation);
const categories = ( (EXTENSION_CATEGORIES.map(c => c.toLowerCase())));
if (category && category !== '') {
if (categories.indexOf(category.toLowerCase()) < 0) {
this.logger.info('Invalid category please enter a valid category. To list valid categories run --category without a category specified');
return;
}
extensions = extensions.filter(e => {
if (e.manifest.categories) {
const lowerCaseCategories = ( (e.manifest.categories.map(c => c.toLowerCase())));
return lowerCaseCategories.indexOf(category.toLowerCase()) > -1;
}
return false;
});
}
else if (category === '') {
this.logger.info('Possible Categories: ');
categories.forEach(category => {
this.logger.info(category);
});
return;
}
if (this.location) {
this.logger.info(( localize(9802, "Extensions installed on {0}:", this.location)));
}
extensions = extensions.sort((e1, e2) => e1.identifier.id.localeCompare(e2.identifier.id));
let lastId = undefined;
for (const extension of extensions) {
if (lastId !== extension.identifier.id) {
lastId = extension.identifier.id;
this.logger.info(showVersions ? `${lastId}@${extension.manifest.version}` : lastId);
}
}
}
async installExtensions(extensions, builtinExtensions, installOptions, force) {
const failed = [];
try {
if (extensions.length) {
this.logger.info(this.location ? ( localize(9803, "Installing extensions on {0}...", this.location)) : ( localize(9804, "Installing extensions...")));
}
const installVSIXInfos = [];
const installExtensionInfos = [];
const addInstallExtensionInfo = (id, version, isBuiltin) => {
installExtensionInfos.push({ id, version: version !== 'prerelease' ? version : undefined, installOptions: { ...installOptions, isBuiltin, installPreReleaseVersion: version === 'prerelease' || installOptions.installPreReleaseVersion } });
};
for (const extension of extensions) {
if (extension instanceof URI) {
installVSIXInfos.push({ vsix: extension, installOptions });
}
else {
const [id, version] = getIdAndVersion(extension);
addInstallExtensionInfo(id, version, false);
}
}
for (const extension of builtinExtensions) {
if (extension instanceof URI) {
installVSIXInfos.push({ vsix: extension, installOptions: { ...installOptions, isBuiltin: true, donotIncludePackAndDependencies: true } });
}
else {
const [id, version] = getIdAndVersion(extension);
addInstallExtensionInfo(id, version, true);
}
}
const installed = await this.extensionManagementService.getInstalled(undefined, installOptions.profileLocation);
if (installVSIXInfos.length) {
await Promise.all(( (installVSIXInfos.map(async ({ vsix, installOptions }) => {
try {
await this.installVSIX(vsix, installOptions, force, installed);
}
catch (err) {
this.logger.error(err);
failed.push(( (vsix.toString())));
}
}))));
}
if (installExtensionInfos.length) {
const failedGalleryExtensions = await this.installGalleryExtensions(installExtensionInfos, installed, force);
failed.push(...failedGalleryExtensions);
}
}
catch (error) {
this.logger.error(( localize(9805, "Error while installing extensions: {0}", getErrorMessage(error))));
throw error;
}
if (failed.length) {
throw ( (new Error(localize(9806, "Failed Installing Extensions: {0}", failed.join(', ')))));
}
}
async updateExtensions(profileLocation) {
const installedExtensions = await this.extensionManagementService.getInstalled(ExtensionType.User, profileLocation);
const installedExtensionsQuery = [];
for (const extension of installedExtensions) {
if (!!extension.identifier.uuid) {
installedExtensionsQuery.push({ ...extension.identifier, preRelease: extension.preRelease });
}
}
this.logger.trace(( localize(
9807,
"Fetching latest versions for {0} extensions",
installedExtensionsQuery.length
)));
const availableVersions = await this.extensionGalleryService.getExtensions(installedExtensionsQuery, { compatible: true }, CancellationToken.None);
const extensionsToUpdate = [];
for (const newVersion of availableVersions) {
for (const oldVersion of installedExtensions) {
if (areSameExtensions(oldVersion.identifier, newVersion.identifier) && semverExports.gt(newVersion.version, oldVersion.manifest.version)) {
extensionsToUpdate.push({
extension: newVersion,
options: { operation: InstallOperation.Update, installPreReleaseVersion: oldVersion.preRelease, profileLocation, isApplicationScoped: oldVersion.isApplicationScoped }
});
}
}
}
if (!extensionsToUpdate.length) {
this.logger.info(( localize(9808, "No extension to update")));
return;
}
this.logger.info(( localize(
9809,
"Updating extensions: {0}",
( (extensionsToUpdate.map(ext => ext.extension.identifier.id))).join(', ')
)));
const installationResult = await this.extensionManagementService.installGalleryExtensions(extensionsToUpdate);
for (const extensionResult of installationResult) {
if (extensionResult.error) {
this.logger.error(( localize(
9810,
"Error while updating extension {0}: {1}",
extensionResult.identifier.id,
getErrorMessage(extensionResult.error)
)));
}
else {
this.logger.info(( localize(
9811,
"Extension '{0}' v{1} was successfully updated.",
extensionResult.identifier.id,
extensionResult.local?.manifest.version
)));
}
}
}
async installGalleryExtensions(installExtensionInfos, installed, force) {
installExtensionInfos = installExtensionInfos.filter(({ id, version }) => {
const installedExtension = installed.find(i => areSameExtensions(i.identifier, { id }));
if (installedExtension) {
if (!force && (!version || (version === 'prerelease' && installedExtension.preRelease))) {
this.logger.info(( localize(
9812,
"Extension '{0}' v{1} is already installed. Use '--force' option to update to latest version or provide '@<version>' to install a specific version, for example: '{2}@1.2.3'.",
id,
installedExtension.manifest.version,
id
)));
return false;
}
if (version && installedExtension.manifest.version === version) {
this.logger.info(( localize(9813, "Extension '{0}' is already installed.", `${id}@${version}`)));
return false;
}
}
return true;
});
if (!installExtensionInfos.length) {
return [];
}
const failed = [];
const extensionsToInstall = [];
const galleryExtensions = await this.getGalleryExtensions(installExtensionInfos);
await Promise.all(( (installExtensionInfos.map(async ({ id, version, installOptions }) => {
const gallery = galleryExtensions.get(id.toLowerCase());
if (!gallery) {
this.logger.error(`${notFound(version ? `${id}@${version}` : id)}\n${useId}`);
failed.push(id);
return;
}
try {
const manifest = await this.extensionGalleryService.getManifest(gallery, CancellationToken.None);
if (manifest && !this.validateExtensionKind(manifest)) {
return;
}
}
catch (err) {
this.logger.error(err.message || err.stack || err);
failed.push(id);
return;
}
const installedExtension = installed.find(e => areSameExtensions(e.identifier, gallery.identifier));
if (installedExtension) {
if (gallery.version === installedExtension.manifest.version) {
this.logger.info(( localize(
9813,
"Extension '{0}' is already installed.",
version ? `${id}@${version}` : id
)));
return;
}
this.logger.info(( localize(
9814,
"Updating the extension '{0}' to the version {1}",
id,
gallery.version
)));
}
if (installOptions.isBuiltin) {
this.logger.info(version ? ( localize(9815, "Installing builtin extension '{0}' v{1}...", id, version)) : ( localize(9816, "Installing builtin extension '{0}'...", id)));
}
else {
this.logger.info(version ? ( localize(9817, "Installing extension '{0}' v{1}...", id, version)) : ( localize(9818, "Installing extension '{0}'...", id)));
}
extensionsToInstall.push({
extension: gallery,
options: { ...installOptions, installGivenVersion: !!version, isApplicationScoped: installOptions.isApplicationScoped || installedExtension?.isApplicationScoped },
});
}))));
if (extensionsToInstall.length) {
const installationResult = await this.extensionManagementService.installGalleryExtensions(extensionsToInstall);
for (const extensionResult of installationResult) {
if (extensionResult.error) {
this.logger.error(( localize(
9819,
"Error while installing extension {0}: {1}",
extensionResult.identifier.id,
getErrorMessage(extensionResult.error)
)));
failed.push(extensionResult.identifier.id);
}
else {
this.logger.info(( localize(
9820,
"Extension '{0}' v{1} was successfully installed.",
extensionResult.identifier.id,
extensionResult.local?.manifest.version
)));
}
}
}
return failed;
}
async installVSIX(vsix, installOptions, force, installedExtensions) {
const manifest = await this.extensionManagementService.getManifest(vsix);
if (!manifest) {
throw ( (new Error('Invalid vsix')));
}
const valid = await this.validateVSIX(manifest, force, installOptions.profileLocation, installedExtensions);
if (valid) {
try {
await this.extensionManagementService.install(vsix, { ...installOptions, installGivenVersion: true });
this.logger.info(( localize(9821, "Extension '{0}' was successfully installed.", basename(vsix))));
}
catch (error) {
if (isCancellationError(error)) {
this.logger.info(( localize(9822, "Cancelled installing extension '{0}'.", basename(vsix))));
}
else {
throw error;
}
}
}
}
async getGalleryExtensions(extensions) {
const galleryExtensions = ( (new Map()));
const preRelease = ( (extensions.some(e => e.installOptions.installPreReleaseVersion)));
const targetPlatform = await this.extensionManagementService.getTargetPlatform();
const extensionInfos = [];
for (const extension of extensions) {
if (EXTENSION_IDENTIFIER_REGEX.test(extension.id)) {
extensionInfos.push({ ...extension, preRelease });
}
}
if (extensionInfos.length) {
const result = await this.extensionGalleryService.getExtensions(extensionInfos, { targetPlatform }, CancellationToken.None);
for (const extension of result) {
galleryExtensions.set(extension.identifier.id.toLowerCase(), extension);
}
}
return galleryExtensions;
}
validateExtensionKind(_manifest) {
return true;
}
async validateVSIX(manifest, force, profileLocation, installedExtensions) {
if (!force) {
const extensionIdentifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };
const newer = installedExtensions.find(local => areSameExtensions(extensionIdentifier, local.identifier) && semverExports.gt(local.manifest.version, manifest.version));
if (newer) {
this.logger.info(( localize(
9823,
"A newer version of extension '{0}' v{1} is already installed. Use '--force' option to downgrade to older version.",
newer.identifier.id,
newer.manifest.version,
manifest.version
)));
return false;
}
}
return this.validateExtensionKind(manifest);
}
async uninstallExtensions(extensions, force, profileLocation) {
const getId = async (extensionDescription) => {
if (extensionDescription instanceof URI) {
const manifest = await this.extensionManagementService.getManifest(extensionDescription);
return getExtensionId(manifest.publisher, manifest.name);
}
return extensionDescription;
};
for (const extension of extensions) {
const id = await getId(extension);
const installed = await this.extensionManagementService.getInstalled(undefined, profileLocation);
const extensionsToUninstall = installed.filter(e => areSameExtensions(e.identifier, { id }));
if (!extensionsToUninstall.length) {
throw ( (new Error(`${this.notInstalled(id)}\n${useId}`)));
}
if (( (extensionsToUninstall.some(e => e.type === ExtensionType.System)))) {
this.logger.info(( localize(
9824,
"Extension '{0}' is a Built-in extension and cannot be uninstalled",
id
)));
return;
}
if (!force && ( (extensionsToUninstall.some(e => e.isBuiltin)))) {
this.logger.info(( localize(
9825,
"Extension '{0}' is marked as a Built-in extension by user. Please use '--force' option to uninstall it.",
id
)));
return;
}
this.logger.info(( localize(9826, "Uninstalling {0}...", id)));
for (const extensionToUninstall of extensionsToUninstall) {
await this.extensionManagementService.uninstall(extensionToUninstall, { profileLocation });
}
if (this.location) {
this.logger.info(( localize(
9827,
"Extension '{0}' was successfully uninstalled from {1}!",
id,
this.location
)));
}
else {
this.logger.info(( localize(9828, "Extension '{0}' was successfully uninstalled!", id)));
}
}
}
async locateExtension(extensions) {
const installed = await this.extensionManagementService.getInstalled();
extensions.forEach(e => {
installed.forEach(i => {
if (i.identifier.id === e) {
if (i.location.scheme === Schemas.file) {
this.logger.info(i.location.fsPath);
return;
}
}
});
});
}
notInstalled(id) {
return this.location ? ( localize(9829, "Extension '{0}' is not installed on {1}.", id, this.location)) : ( localize(9830, "Extension '{0}' is not installed.", id));
}
};
ExtensionManagementCLI = ( (__decorate([
( (__param(1, IExtensionManagementService))),
( (__param(2, IExtensionGalleryService)))
], ExtensionManagementCLI)));
export { ExtensionManagementCLI };