diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 714d8b37d52..6921d965742 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -268,23 +268,23 @@ class CliMain extends Disposable { // List Extensions if (this.argv['list-extensions']) { - return instantiationService.createInstance(ExtensionManagementCLI).listExtensions(!!this.argv['show-versions'], this.argv['category'], profileLocation); + return instantiationService.createInstance(ExtensionManagementCLI, new ConsoleLogger(LogLevel.Info, false)).listExtensions(!!this.argv['show-versions'], this.argv['category'], profileLocation); } // Install Extension else if (this.argv['install-extension'] || this.argv['install-builtin-extension']) { const installOptions: InstallOptions = { isMachineScoped: !!this.argv['do-not-sync'], installPreReleaseVersion: !!this.argv['pre-release'], profileLocation }; - return instantiationService.createInstance(ExtensionManagementCLI).installExtensions(this.asExtensionIdOrVSIX(this.argv['install-extension'] || []), this.asExtensionIdOrVSIX(this.argv['install-builtin-extension'] || []), installOptions, !!this.argv['force']); + return instantiationService.createInstance(ExtensionManagementCLI, new ConsoleLogger(LogLevel.Info, false)).installExtensions(this.asExtensionIdOrVSIX(this.argv['install-extension'] || []), this.asExtensionIdOrVSIX(this.argv['install-builtin-extension'] || []), installOptions, !!this.argv['force']); } // Uninstall Extension else if (this.argv['uninstall-extension']) { - return instantiationService.createInstance(ExtensionManagementCLI).uninstallExtensions(this.asExtensionIdOrVSIX(this.argv['uninstall-extension']), !!this.argv['force'], profileLocation); + return instantiationService.createInstance(ExtensionManagementCLI, new ConsoleLogger(LogLevel.Info, false)).uninstallExtensions(this.asExtensionIdOrVSIX(this.argv['uninstall-extension']), !!this.argv['force'], profileLocation); } // Locate Extension else if (this.argv['locate-extension']) { - return instantiationService.createInstance(ExtensionManagementCLI).locateExtension(this.argv['locate-extension']); + return instantiationService.createInstance(ExtensionManagementCLI, new ConsoleLogger(LogLevel.Info, false)).locateExtension(this.argv['locate-extension']); } // Telemetry diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index cf52b3a88d6..c6d2213cbba 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -516,8 +516,3 @@ export interface IExtensionTipsService { export const ExtensionsLabel = localize('extensions', "Extensions"); export const ExtensionsLocalizedLabel = { value: ExtensionsLabel, original: 'Extensions' }; export const PreferencesLocalizedLabel = { value: localize('preferences', "Preferences"), original: 'Preferences' }; - -export interface CLIOutput { - log(s: string): void; - error(s: string): void; -} diff --git a/src/vs/platform/extensionManagement/common/extensionManagementCLI.ts b/src/vs/platform/extensionManagement/common/extensionManagementCLI.ts index e822bd8005f..41d34f980e8 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementCLI.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementCLI.ts @@ -10,9 +10,10 @@ import { basename } from 'vs/base/common/resources'; import { gt } from 'vs/base/common/semver/semver'; import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; -import { CLIOutput, IExtensionGalleryService, IExtensionManagementService, IGalleryExtension, ILocalExtension, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionManagementService, IGalleryExtension, ILocalExtension, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions, getGalleryExtensionId, getIdAndVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { ExtensionType, EXTENSION_CATEGORIES, IExtensionManifest } from 'vs/platform/extensions/common/extensions'; +import { ILogger } from 'vs/platform/log/common/log'; const notFound = (id: string) => localize('notFound', "Extension '{0}' not found.", id); @@ -33,20 +34,21 @@ type InstallExtensionInfo = { id: string; version?: string; installOptions: Inst export class ExtensionManagementCLI { constructor( + protected readonly logger: ILogger, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, - @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService + @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, ) { } protected get location(): string | undefined { return undefined; } - public async listExtensions(showVersions: boolean, category?: string, profileLocation?: URI, output: CLIOutput = console): Promise { + public async listExtensions(showVersions: boolean, category?: string, profileLocation?: URI): Promise { 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) { - output.log('Invalid category please enter a valid category. To list valid categories run --category without a category specified'); + 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 => { @@ -57,14 +59,14 @@ export class ExtensionManagementCLI { return false; }); } else if (category === '') { - output.log('Possible Categories: '); + this.logger.info('Possible Categories: '); categories.forEach(category => { - output.log(category); + this.logger.info(category); }); return; } if (this.location) { - output.log(localize('listFromLocation', "Extensions installed on {0}:", this.location)); + this.logger.info(localize('listFromLocation', "Extensions installed on {0}:", this.location)); } extensions = extensions.sort((e1, e2) => e1.identifier.id.localeCompare(e2.identifier.id)); @@ -72,95 +74,90 @@ export class ExtensionManagementCLI { for (const extension of extensions) { if (lastId !== extension.identifier.id) { lastId = extension.identifier.id; - output.log(getId(extension.manifest, showVersions)); + this.logger.info(getId(extension.manifest, showVersions)); } } } - public async installExtensions(extensions: (string | URI)[], builtinExtensions: (string | URI)[], installOptions: InstallOptions, force: boolean, output: CLIOutput = console): Promise { + public async installExtensions(extensions: (string | URI)[], builtinExtensions: (string | URI)[], installOptions: InstallOptions, force: boolean): Promise { const failed: string[] = []; const installedExtensionsManifests: IExtensionManifest[] = []; if (extensions.length) { - output.log(this.location ? localize('installingExtensionsOnLocation', "Installing extensions on {0}...", this.location) : localize('installingExtensions', "Installing extensions...")); + this.logger.info(this.location ? localize('installingExtensionsOnLocation', "Installing extensions on {0}...", this.location) : localize('installingExtensions', "Installing extensions...")); } - const installed = await this.extensionManagementService.getInstalled(ExtensionType.User, installOptions.profileLocation); - const checkIfNotInstalled = (id: string, version?: string): boolean => { - const installedExtension = installed.find(i => areSameExtensions(i.identifier, { id })); - if (installedExtension) { - if (!force && (!version || (version === 'prerelease' && installedExtension.preRelease))) { - output.log(localize('alreadyInstalled-checkAndUpdate', "Extension '{0}' v{1} is already installed. Use '--force' option to update to latest version or provide '@' to install a specific version, for example: '{2}@1.2.3'.", id, installedExtension.manifest.version, id)); - return false; - } - if (version && installedExtension.manifest.version === version) { - output.log(localize('alreadyInstalled', "Extension '{0}' is already installed.", `${id}@${version}`)); - return false; - } - } - return true; - }; + const installVSIXInfos: InstallVSIXInfo[] = []; + let installExtensionInfos: InstallExtensionInfo[] = []; const addInstallExtensionInfo = (id: string, version: string | undefined, isBuiltin: boolean) => { installExtensionInfos.push({ id, version: version !== 'prerelease' ? version : undefined, installOptions: { ...installOptions, isBuiltin, installPreReleaseVersion: version === 'prerelease' || installOptions.installPreReleaseVersion } }); }; - const installVSIXInfos: InstallVSIXInfo[] = []; - const installExtensionInfos: InstallExtensionInfo[] = []; for (const extension of extensions) { if (extension instanceof URI) { installVSIXInfos.push({ vsix: extension, installOptions }); } else { const [id, version] = getIdAndVersion(extension); - if (checkIfNotInstalled(id, version)) { - addInstallExtensionInfo(id, version, false); - } + addInstallExtensionInfo(id, version, false); } } for (const extension of builtinExtensions) { if (extension instanceof URI) { - installVSIXInfos.push({ vsix: extension, installOptions: { ...installOptions, isBuiltin: true, donotIncludePackAndDependencies: false } }); + installVSIXInfos.push({ vsix: extension, installOptions: { ...installOptions, isBuiltin: true, donotIncludePackAndDependencies: true } }); } else { const [id, version] = getIdAndVersion(extension); - if (checkIfNotInstalled(id, version)) { - addInstallExtensionInfo(id, version, true); - } + addInstallExtensionInfo(id, version, true); } } if (installVSIXInfos.length) { await Promise.all(installVSIXInfos.map(async ({ vsix, installOptions }) => { try { - const manifest = await this.installVSIX(vsix, installOptions, force, output); + const manifest = await this.installVSIX(vsix, installOptions, force); if (manifest) { installedExtensionsManifests.push(manifest); } } catch (err) { - output.error(err.message || err.stack || err); + this.logger.error(err); failed.push(vsix.toString()); } })); } if (installExtensionInfos.length) { - - const galleryExtensions = await this.getGalleryExtensions(installExtensionInfos); - - await Promise.all(installExtensionInfos.map(async extensionInfo => { - const gallery = galleryExtensions.get(extensionInfo.id.toLowerCase()); - if (gallery) { - try { - const manifest = await this.installFromGallery(extensionInfo, gallery, installed, force, output); - if (manifest) { - installedExtensionsManifests.push(manifest); + const installed = await this.extensionManagementService.getInstalled(ExtensionType.User, installOptions.profileLocation); + 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('alreadyInstalled-checkAndUpdate', "Extension '{0}' v{1} is already installed. Use '--force' option to update to latest version or provide '@' 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('alreadyInstalled', "Extension '{0}' is already installed.", `${id}@${version}`)); + return false; + } + } + return true; + }); + if (installExtensionInfos.length) { + const galleryExtensions = await this.getGalleryExtensions(installExtensionInfos); + await Promise.all(installExtensionInfos.map(async extensionInfo => { + const gallery = galleryExtensions.get(extensionInfo.id.toLowerCase()); + if (gallery) { + try { + const manifest = await this.installFromGallery(extensionInfo, gallery, installed); + if (manifest) { + installedExtensionsManifests.push(manifest); + } + } catch (err) { + this.logger.error(err.message || err.stack || err); + failed.push(extensionInfo.id); } - } catch (err) { - output.error(err.message || err.stack || err); + } else { + this.logger.error(`${notFound(extensionInfo.version ? `${extensionInfo.id}@${extensionInfo.version}` : extensionInfo.id)}\n${useId}`); failed.push(extensionInfo.id); } - } else { - output.error(`${notFound(extensionInfo.version ? `${extensionInfo.id}@${extensionInfo.version}` : extensionInfo.id)}\n${useId}`); - failed.push(extensionInfo.id); - } - })); - + })); + } } if (failed.length) { @@ -168,22 +165,22 @@ export class ExtensionManagementCLI { } } - private async installVSIX(vsix: URI, installOptions: InstallOptions, force: boolean, output: CLIOutput): Promise { + private async installVSIX(vsix: URI, installOptions: InstallOptions, force: boolean): Promise { const manifest = await this.extensionManagementService.getManifest(vsix); if (!manifest) { throw new Error('Invalid vsix'); } - const valid = await this.validateVSIX(manifest, force, installOptions.profileLocation, output); + const valid = await this.validateVSIX(manifest, force, installOptions.profileLocation); if (valid) { try { await this.extensionManagementService.install(vsix, installOptions); - output.log(localize('successVsixInstall', "Extension '{0}' was successfully installed.", basename(vsix))); + this.logger.info(localize('successVsixInstall', "Extension '{0}' was successfully installed.", basename(vsix))); return manifest; } catch (error) { if (isCancellationError(error)) { - output.log(localize('cancelVsixInstall', "Cancelled installing extension '{0}'.", basename(vsix))); + this.logger.info(localize('cancelVsixInstall', "Cancelled installing extension '{0}'.", basename(vsix))); return null; } else { throw error; @@ -204,34 +201,34 @@ export class ExtensionManagementCLI { return galleryExtensions; } - private async installFromGallery({ id, version, installOptions }: InstallExtensionInfo, galleryExtension: IGalleryExtension, installed: ILocalExtension[], force: boolean, output: CLIOutput): Promise { + private async installFromGallery({ id, version, installOptions }: InstallExtensionInfo, galleryExtension: IGalleryExtension, installed: ILocalExtension[]): Promise { const manifest = await this.extensionGalleryService.getManifest(galleryExtension, CancellationToken.None); - if (manifest && !this.validateExtensionKind(manifest, output)) { + if (manifest && !this.validateExtensionKind(manifest)) { return null; } const installedExtension = installed.find(e => areSameExtensions(e.identifier, galleryExtension.identifier)); if (installedExtension) { if (galleryExtension.version === installedExtension.manifest.version) { - output.log(localize('alreadyInstalled', "Extension '{0}' is already installed.", version ? `${id}@${version}` : id)); + this.logger.info(localize('alreadyInstalled', "Extension '{0}' is already installed.", version ? `${id}@${version}` : id)); return null; } - output.log(localize('updateMessage', "Updating the extension '{0}' to the version {1}", id, galleryExtension.version)); + this.logger.info(localize('updateMessage', "Updating the extension '{0}' to the version {1}", id, galleryExtension.version)); } try { if (installOptions.isBuiltin) { - output.log(version ? localize('installing builtin with version', "Installing builtin extension '{0}' v{1}...", id, version) : localize('installing builtin ', "Installing builtin extension '{0}'...", id)); + this.logger.info(version ? localize('installing builtin with version', "Installing builtin extension '{0}' v{1}...", id, version) : localize('installing builtin ', "Installing builtin extension '{0}'...", id)); } else { - output.log(version ? localize('installing with version', "Installing extension '{0}' v{1}...", id, version) : localize('installing', "Installing extension '{0}'...", id)); + this.logger.info(version ? localize('installing with version', "Installing extension '{0}' v{1}...", id, version) : localize('installing', "Installing extension '{0}'...", id)); } const local = await this.extensionManagementService.installFromGallery(galleryExtension, { ...installOptions, installGivenVersion: !!version }); - output.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed.", id, local.manifest.version)); + this.logger.info(localize('successInstall', "Extension '{0}' v{1} was successfully installed.", id, local.manifest.version)); return manifest; } catch (error) { if (isCancellationError(error)) { - output.log(localize('cancelInstall', "Cancelled installing extension '{0}'.", id)); + this.logger.info(localize('cancelInstall', "Cancelled installing extension '{0}'.", id)); return null; } else { throw error; @@ -239,24 +236,24 @@ export class ExtensionManagementCLI { } } - protected validateExtensionKind(_manifest: IExtensionManifest, output: CLIOutput): boolean { + protected validateExtensionKind(_manifest: IExtensionManifest): boolean { return true; } - private async validateVSIX(manifest: IExtensionManifest, force: boolean, profileLocation: URI | undefined, output: CLIOutput): Promise { + private async validateVSIX(manifest: IExtensionManifest, force: boolean, profileLocation: URI | undefined): Promise { const extensionIdentifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) }; const installedExtensions = await this.extensionManagementService.getInstalled(ExtensionType.User, profileLocation); const newer = installedExtensions.find(local => areSameExtensions(extensionIdentifier, local.identifier) && gt(local.manifest.version, manifest.version)); if (newer && !force) { - output.log(localize('forceDowngrade', "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)); + this.logger.info(localize('forceDowngrade', "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, output); + return this.validateExtensionKind(manifest); } - public async uninstallExtensions(extensions: (string | URI)[], force: boolean, profileLocation?: URI, output: CLIOutput = console): Promise { + public async uninstallExtensions(extensions: (string | URI)[], force: boolean, profileLocation?: URI): Promise { const getExtensionId = async (extensionDescription: string | URI): Promise => { if (extensionDescription instanceof URI) { const manifest = await this.extensionManagementService.getManifest(extensionDescription); @@ -274,35 +271,35 @@ export class ExtensionManagementCLI { throw new Error(`${this.notInstalled(id)}\n${useId}`); } if (extensionsToUninstall.some(e => e.type === ExtensionType.System)) { - output.log(localize('builtin', "Extension '{0}' is a Built-in extension and cannot be uninstalled", id)); + this.logger.info(localize('builtin', "Extension '{0}' is a Built-in extension and cannot be uninstalled", id)); return; } if (!force && extensionsToUninstall.some(e => e.isBuiltin)) { - output.log(localize('forceUninstall', "Extension '{0}' is marked as a Built-in extension by user. Please use '--force' option to uninstall it.", id)); + this.logger.info(localize('forceUninstall', "Extension '{0}' is marked as a Built-in extension by user. Please use '--force' option to uninstall it.", id)); return; } - output.log(localize('uninstalling', "Uninstalling {0}...", id)); + this.logger.info(localize('uninstalling', "Uninstalling {0}...", id)); for (const extensionToUninstall of extensionsToUninstall) { await this.extensionManagementService.uninstall(extensionToUninstall, { profileLocation }); uninstalledExtensions.push(extensionToUninstall); } if (this.location) { - output.log(localize('successUninstallFromLocation', "Extension '{0}' was successfully uninstalled from {1}!", id, this.location)); + this.logger.info(localize('successUninstallFromLocation', "Extension '{0}' was successfully uninstalled from {1}!", id, this.location)); } else { - output.log(localize('successUninstall', "Extension '{0}' was successfully uninstalled!", id)); + this.logger.info(localize('successUninstall', "Extension '{0}' was successfully uninstalled!", id)); } } } - public async locateExtension(extensions: string[], output: CLIOutput = console): Promise { + public async locateExtension(extensions: string[]): Promise { const installed = await this.extensionManagementService.getInstalled(); extensions.forEach(e => { installed.forEach(i => { if (i.identifier.id === e) { if (i.location.scheme === Schemas.file) { - output.log(i.location.fsPath); + this.logger.info(i.location.fsPath); return; } } diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index b506355657d..2c3fd7e8fd5 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -662,6 +662,11 @@ export class ExtensionsScanner extends Disposable { private async removeUninstalledExtensions(): Promise { const uninstalled = await this.getUninstalledExtensions(); + if (Object.keys(uninstalled).length === 0) { + this.logService.debug(`No uninstalled extensions found.`); + return; + } + this.logService.debug(`Removing uninstalled extensions:`, Object.keys(uninstalled)); const extensions = await this.extensionsScannerService.scanUserExtensions({ includeAllVersions: true, includeUninstalled: true, includeInvalid: true }); // All user extensions diff --git a/src/vs/platform/log/common/log.ts b/src/vs/platform/log/common/log.ts index 59c7ee3c0d9..3a0a4b2a7e9 100644 --- a/src/vs/platform/log/common/log.ts +++ b/src/vs/platform/log/common/log.ts @@ -390,38 +390,58 @@ export class ConsoleMainLogger extends AbstractLogger implements ILogger { export class ConsoleLogger extends AbstractLogger implements ILogger { - constructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) { + constructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL, private readonly useColors: boolean = true) { super(); this.setLevel(logLevel); } trace(message: string, ...args: any[]): void { if (this.checkLogLevel(LogLevel.Trace)) { - console.log('%cTRACE', 'color: #888', message, ...args); + if (this.useColors) { + console.log('%cTRACE', 'color: #888', message, ...args); + } else { + console.log(message, ...args); + } } } debug(message: string, ...args: any[]): void { if (this.checkLogLevel(LogLevel.Debug)) { - console.log('%cDEBUG', 'background: #eee; color: #888', message, ...args); + if (this.useColors) { + console.log('%cDEBUG', 'background: #eee; color: #888', message, ...args); + } else { + console.log(message, ...args); + } } } info(message: string, ...args: any[]): void { if (this.checkLogLevel(LogLevel.Info)) { - console.log('%c INFO', 'color: #33f', message, ...args); + if (this.useColors) { + console.log('%c INFO', 'color: #33f', message, ...args); + } else { + console.log(message, ...args); + } } } warn(message: string | Error, ...args: any[]): void { if (this.checkLogLevel(LogLevel.Warning)) { - console.log('%c WARN', 'color: #993', message, ...args); + if (this.useColors) { + console.log('%c WARN', 'color: #993', message, ...args); + } else { + console.log(message, ...args); + } } } error(message: string, ...args: any[]): void { if (this.checkLogLevel(LogLevel.Error)) { - console.log('%c ERR', 'color: #f33', message, ...args); + if (this.useColors) { + console.log('%c ERR', 'color: #f33', message, ...args); + } else { + console.error(message, ...args); + } } } diff --git a/src/vs/server/node/remoteExtensionHostAgentCli.ts b/src/vs/server/node/remoteExtensionHostAgentCli.ts index e48c18cd28e..756aa324d3a 100644 --- a/src/vs/server/node/remoteExtensionHostAgentCli.ts +++ b/src/vs/server/node/remoteExtensionHostAgentCli.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { getLogLevel, ILoggerService, ILogService } from 'vs/platform/log/common/log'; +import { ConsoleLogger, getLogLevel, ILoggerService, ILogService } from 'vs/platform/log/common/log'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ConfigurationService } from 'vs/platform/configuration/common/configurationService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -68,7 +68,7 @@ class CliMain extends Disposable { await instantiationService.invokeFunction(async accessor => { const logService = accessor.get(ILogService); try { - await this.doRun(instantiationService.createInstance(ExtensionManagementCLI)); + await this.doRun(instantiationService.createInstance(ExtensionManagementCLI, new ConsoleLogger(logService.getLevel(), false))); } catch (error) { logService.error(error); console.error(getErrorMessage(error)); diff --git a/src/vs/server/node/remoteExtensionsScanner.ts b/src/vs/server/node/remoteExtensionsScanner.ts index e4f42ce2c57..077f396466b 100644 --- a/src/vs/server/node/remoteExtensionsScanner.ts +++ b/src/vs/server/node/remoteExtensionsScanner.ts @@ -41,10 +41,14 @@ export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerS ) { const builtinExtensionsToInstall = environmentService.args['install-builtin-extension']; if (builtinExtensionsToInstall) { + _logService.trace('Installing builtin extensions passed via args...'); const installOptions: InstallOptions = { isMachineScoped: !!environmentService.args['do-not-sync'], installPreReleaseVersion: !!environmentService.args['pre-release'] }; performance.mark('code/server/willInstallBuiltinExtensions'); this._whenExtensionsReady = _extensionManagementCLI.installExtensions([], this._asExtensionIdOrVSIX(builtinExtensionsToInstall), installOptions, !!environmentService.args['force']) - .then(() => performance.mark('code/server/didInstallBuiltinExtensions'), error => { + .then(() => { + performance.mark('code/server/didInstallBuiltinExtensions'); + _logService.trace('Finished installing builtin extensions'); + }, error => { _logService.error(error); }); } else { @@ -53,9 +57,12 @@ export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerS const extensionsToInstall = environmentService.args['install-extension']; if (extensionsToInstall) { + _logService.trace('Installing extensions passed via args...'); this._whenExtensionsReady .then(() => _extensionManagementCLI.installExtensions(this._asExtensionIdOrVSIX(extensionsToInstall), [], { isMachineScoped: !!environmentService.args['do-not-sync'], installPreReleaseVersion: !!environmentService.args['pre-release'] }, !!environmentService.args['force'])) - .then(null, error => { + .then(() => { + _logService.trace('Finished installing extensions'); + }, error => { _logService.error(error); }); } @@ -174,10 +181,7 @@ export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerS this._logService.trace(`Language Pack ${languagePackId} for language ${language} is not installed. It will be installed now.`); try { - await this._extensionManagementCLI.installExtensions([languagePackId], [], { isMachineScoped: true }, true, { - log: (s) => this._logService.info(s), - error: (s) => this._logService.error(s) - }); + await this._extensionManagementCLI.installExtensions([languagePackId], [], { isMachineScoped: true }, true); } catch (err) { // We tried to install the language pack but failed. We can continue without it thus using the default language. this._logService.error(err); diff --git a/src/vs/server/node/serverServices.ts b/src/vs/server/node/serverServices.ts index 09649061cb1..8f541027962 100644 --- a/src/vs/server/node/serverServices.ts +++ b/src/vs/server/node/serverServices.ts @@ -38,7 +38,7 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; import { NativeLanguagePackService } from 'vs/platform/languagePacks/node/languagePacks'; -import { AbstractLogger, DEFAULT_LOG_LEVEL, getLogLevel, ILoggerService, ILogService, LogLevel } from 'vs/platform/log/common/log'; +import { AbstractLogger, DEFAULT_LOG_LEVEL, getLogLevel, ILoggerService, ILogService, log, LogLevel, LogLevelToString } from 'vs/platform/log/common/log'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment'; @@ -102,6 +102,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken const logService = new LogService(logger, [new ServerLogger(getLogLevel(environmentService))]); services.set(ILogService, logService); setTimeout(() => cleanupOlderLogs(environmentService.logsHome.fsPath).then(null, err => logService.error(err)), 10000); + logService.onDidChangeLogLevel(logLevel => log(logService, logLevel, `Log level changed to ${LogLevelToString(logService.getLevel())}`)); logService.trace(`Remote configuration data at ${REMOTE_DATA_FOLDER}`); logService.trace('process arguments:', environmentService.args); @@ -217,7 +218,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken socketServer.registerChannel(REMOTE_TERMINAL_CHANNEL_NAME, new RemoteTerminalChannel(environmentService, logService, ptyService, productService, extensionManagementService, configurationService)); - const remoteExtensionsScanner = new RemoteExtensionsScannerService(instantiationService.createInstance(ExtensionManagementCLI), environmentService, userDataProfilesService, extensionsScannerService, logService, extensionGalleryService, languagePackService); + const remoteExtensionsScanner = new RemoteExtensionsScannerService(instantiationService.createInstance(ExtensionManagementCLI, logService), environmentService, userDataProfilesService, extensionsScannerService, logService, extensionGalleryService, languagePackService); socketServer.registerChannel(RemoteExtensionsScannerChannelName, new RemoteExtensionsScannerChannel(remoteExtensionsScanner, (ctx: RemoteAgentConnectionContext) => getUriTransformer(ctx.remoteAuthority))); const remoteFileSystemChannel = new RemoteAgentFileSystemProviderChannel(logService, environmentService); @@ -235,7 +236,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken socketServer.registerChannel('credentials', credentialsChannel); // clean up extensions folder - extensionManagementService.cleanUp(); + remoteExtensionsScanner.whenExtensionsReady().then(() => extensionManagementService.cleanUp()); disposables.add(new ErrorTelemetry(accessor.get(ITelemetryService))); diff --git a/src/vs/workbench/api/browser/mainThreadCLICommands.ts b/src/vs/workbench/api/browser/mainThreadCLICommands.ts index 180f9863fab..71bdc29e5c7 100644 --- a/src/vs/workbench/api/browser/mainThreadCLICommands.ts +++ b/src/vs/workbench/api/browser/mainThreadCLICommands.ts @@ -9,16 +9,15 @@ import { isString } from 'vs/base/common/types'; import { URI, UriComponents } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { CLIOutput, IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementCLI } from 'vs/platform/extensionManagement/common/extensionManagementCLI'; import { getExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IExtensionManifest } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ILabelService } from 'vs/platform/label/common/label'; +import { AbstractMessageLogger, ILogger, LogLevel } from 'vs/platform/log/common/log'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { IProductService } from 'vs/platform/product/common/productService'; import { IOpenWindowOptions, IWindowOpenable } from 'vs/platform/window/common/window'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; @@ -61,25 +60,28 @@ CommandsRegistry.registerCommand('_remoteCLI.manageExtensions', async function ( return; } - const cliService = instantiationService.createChild(new ServiceCollection([IExtensionManagementService, remoteExtensionManagementService])).createInstance(RemoteExtensionManagementCLI); - const lines: string[] = []; - const output = { log: lines.push.bind(lines), error: lines.push.bind(lines) }; + const logger = new class extends AbstractMessageLogger { + protected override log(level: LogLevel, message: string): void { + lines.push(message); + } + }(); + const cliService = instantiationService.createChild(new ServiceCollection([IExtensionManagementService, remoteExtensionManagementService])).createInstance(RemoteExtensionManagementCLI, logger); if (args.list) { - await cliService.listExtensions(!!args.list.showVersions, args.list.category, undefined, output); + await cliService.listExtensions(!!args.list.showVersions, args.list.category, undefined); } else { const revive = (inputs: (string | UriComponents)[]) => inputs.map(input => isString(input) ? input : URI.revive(input)); if (Array.isArray(args.install) && args.install.length) { try { - await cliService.installExtensions(revive(args.install), [], { isMachineScoped: true }, !!args.force, output); + await cliService.installExtensions(revive(args.install), [], { isMachineScoped: true }, !!args.force); } catch (e) { lines.push(e.message); } } if (Array.isArray(args.uninstall) && args.uninstall.length) { try { - await cliService.uninstallExtensions(revive(args.uninstall), !!args.force, undefined, output); + await cliService.uninstallExtensions(revive(args.uninstall), !!args.force, undefined); } catch (e) { lines.push(e.message); } @@ -93,15 +95,14 @@ class RemoteExtensionManagementCLI extends ExtensionManagementCLI { private _location: string | undefined; constructor( + logger: ILogger, @IExtensionManagementService extensionManagementService: IExtensionManagementService, - @IProductService productService: IProductService, - @IConfigurationService configurationService: IConfigurationService, @IExtensionGalleryService extensionGalleryService: IExtensionGalleryService, @ILabelService labelService: ILabelService, @IWorkbenchEnvironmentService envService: IWorkbenchEnvironmentService, @IExtensionManifestPropertiesService private readonly _extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { - super(extensionManagementService, extensionGalleryService); + super(logger, extensionManagementService, extensionGalleryService); const remoteAuthority = envService.remoteAuthority; this._location = remoteAuthority ? labelService.getHostLabel(Schemas.vscodeRemote, remoteAuthority) : undefined; @@ -111,11 +112,11 @@ class RemoteExtensionManagementCLI extends ExtensionManagementCLI { return this._location; } - protected override validateExtensionKind(manifest: IExtensionManifest, output: CLIOutput): boolean { + protected override validateExtensionKind(manifest: IExtensionManifest): boolean { if (!this._extensionManifestPropertiesService.canExecuteOnWorkspace(manifest) // Web extensions installed on remote can be run in web worker extension host && !(isWeb && this._extensionManifestPropertiesService.canExecuteOnWeb(manifest))) { - output.log(localize('cannot be installed', "Cannot install the '{0}' extension because it is declared to not run in this setup.", getExtensionId(manifest.publisher, manifest.name))); + this.logger.info(localize('cannot be installed', "Cannot install the '{0}' extension because it is declared to not run in this setup.", getExtensionId(manifest.publisher, manifest.name))); return false; } return true; diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index 33045c3133b..119b587ecd5 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -7,7 +7,7 @@ import { mark } from 'vs/base/common/performance'; import { domContentLoaded, detectFullscreen, getCookieValue } from 'vs/base/browser/dom'; import { assertIsDefined } from 'vs/base/common/types'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { ILogService, ConsoleLogger, getLogLevel, ILoggerService } from 'vs/platform/log/common/log'; +import { ILogService, ConsoleLogger, getLogLevel, ILoggerService, ILogger } from 'vs/platform/log/common/log'; import { ConsoleLogInAutomationLogger } from 'vs/platform/log/browser/log'; import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { BrowserWorkbenchEnvironmentService, IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; @@ -244,7 +244,7 @@ export class BrowserMain extends Disposable { // Log const logLevel = getLogLevel(environmentService); const bufferLogger = new BufferLogger(logLevel); - const otherLoggers = [new ConsoleLogger(logLevel)]; + const otherLoggers: ILogger[] = [new ConsoleLogger(logLevel)]; if (environmentService.isExtensionDevelopment && !!environmentService.extensionTestsLocationURI) { otherLoggers.push(new ConsoleLogInAutomationLogger(logLevel)); }