Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

restart extension host for updating extensions instead of reload #206997

Merged
merged 4 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ import {
InstallDropdownAction, InstallingLabelAction,
LocalInstallAction,
MigrateDeprecatedExtensionAction,
ReloadAction,
ExtensionRuntimeStateAction,
RemoteInstallAction,
SetColorThemeAction,
SetFileIconThemeAction,
Expand Down Expand Up @@ -315,7 +315,7 @@ export class ExtensionEditor extends EditorPane {

const installAction = this.instantiationService.createInstance(InstallDropdownAction);
const actions = [
this.instantiationService.createInstance(ReloadAction),
this.instantiationService.createInstance(ExtensionRuntimeStateAction),
this.instantiationService.createInstance(ExtensionStatusLabelAction),
this.instantiationService.createInstance(ActionWithDropDownAction, 'extensions.updateActions', '',
[[this.instantiationService.createInstance(UpdateAction, true)], [this.instantiationService.createInstance(ToggleAutoUpdateForExtensionAction, true, [true, 'onlyEnabledExtensions'])]]),
Expand Down
20 changes: 10 additions & 10 deletions src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1554,28 +1554,28 @@ export class DisableDropDownAction extends ActionWithDropDownAction {

}

export class ReloadAction extends ExtensionAction {
export class ExtensionRuntimeStateAction extends ExtensionAction {

private static readonly EnabledClass = `${ExtensionAction.LABEL_ACTION_CLASS} reload`;
private static readonly DisabledClass = `${ReloadAction.EnabledClass} disabled`;
private static readonly DisabledClass = `${ExtensionRuntimeStateAction.EnabledClass} disabled`;

updateWhenCounterExtensionChanges: boolean = true;

constructor(
@IHostService private readonly hostService: IHostService,
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
@IUpdateService private readonly updateService: IUpdateService,
@IExtensionService private readonly extensionService: IExtensionService,
@IProductService private readonly productService: IProductService,
) {
super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false);
super('extensions.runtimeState', '', ExtensionRuntimeStateAction.DisabledClass, false);
this._register(this.extensionService.onDidChangeExtensions(() => this.update()));
this.update();
}

update(): void {
this.enabled = false;
this.tooltip = '';
this.class = ReloadAction.DisabledClass;
this.class = ExtensionRuntimeStateAction.DisabledClass;

if (!this.extension) {
return;
Expand All @@ -1596,18 +1596,18 @@ export class ReloadAction extends ExtensionAction {
}

this.enabled = true;
this.class = ReloadAction.EnabledClass;
this.class = ExtensionRuntimeStateAction.EnabledClass;
this.tooltip = runtimeState.reason;
this.label = runtimeState.action === ExtensionRuntimeActionType.Reload ? localize('reload window', 'Reload Window')
: runtimeState.action === ExtensionRuntimeActionType.QuitAndInstall ? localize('restart product', 'Restart {0}', this.productService.nameShort)
this.label = runtimeState.action === ExtensionRuntimeActionType.RestartExtensions ? localize('restart extensions', 'Restart Extensions')
: runtimeState.action === ExtensionRuntimeActionType.QuitAndInstall ? localize('restart product', 'Restart to Update')
: runtimeState.action === ExtensionRuntimeActionType.ApplyUpdate || runtimeState.action === ExtensionRuntimeActionType.DownloadUpdate ? localize('update product', 'Update {0}', this.productService.nameShort) : '';
}

override async run(): Promise<any> {
const runtimeState = this.extension?.runtimeState;

if (runtimeState?.action === ExtensionRuntimeActionType.Reload) {
return this.hostService.reload();
if (runtimeState?.action === ExtensionRuntimeActionType.RestartExtensions) {
return this.extensionsWorkbenchService.updateRunningExtensions();
}

else if (runtimeState?.action === ExtensionRuntimeActionType.DownloadUpdate) {
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/contrib/extensions/browser/extensionsList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
import { Event } from 'vs/base/common/event';
import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
import { ManageExtensionAction, ReloadAction, ExtensionStatusLabelAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, WebInstallAction, MigrateDeprecatedExtensionAction, SetLanguageAction, ClearLanguageAction, UpdateAction, ToggleAutoUpdateForExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { ManageExtensionAction, ExtensionRuntimeStateAction, ExtensionStatusLabelAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, WebInstallAction, MigrateDeprecatedExtensionAction, SetLanguageAction, ClearLanguageAction, UpdateAction, ToggleAutoUpdateForExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, ExtensionPackCountWidget as ExtensionPackBadgeWidget, SyncIgnoredWidget, ExtensionHoverWidget, ExtensionActivationStatusWidget, PreReleaseBookmarkWidget, extensionVerifiedPublisherIconColor, VerifiedPublisherWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
import { IExtensionService, toExtension } from 'vs/workbench/services/extensions/common/extensions';
Expand Down Expand Up @@ -117,7 +117,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
const actions = [
this.instantiationService.createInstance(ExtensionStatusLabelAction),
this.instantiationService.createInstance(MigrateDeprecatedExtensionAction, true),
this.instantiationService.createInstance(ReloadAction),
this.instantiationService.createInstance(ExtensionRuntimeStateAction),
this.instantiationService.createInstance(ActionWithDropDownAction, 'extensions.updateActions', '',
[[this.instantiationService.createInstance(UpdateAction, false)], [this.instantiationService.createInstance(ToggleAutoUpdateForExtensionAction, true, [true, 'onlyEnabledExtensions'])]]),
this.instantiationService.createInstance(InstallDropdownAction),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,39 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
return undefined;
}

async updateRunningExtensions(): Promise<void> {
const toAdd: ILocalExtension[] = [];
const toRemove: string[] = [];
for (const extension of this.local) {
const runtimeState = extension.runtimeState;
if (!runtimeState || runtimeState.action !== ExtensionRuntimeActionType.RestartExtensions) {
continue;
}
if (extension.state === ExtensionState.Uninstalled) {
toRemove.push(extension.identifier.id);
continue;
}
if (!extension.local) {
continue;
}
const isEnabled = this.extensionEnablementService.isEnabled(extension.local);
if (isEnabled) {
const runningExtension = this.extensionService.extensions.find(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, extension.identifier));
if (runningExtension) {
toRemove.push(runningExtension.identifier.value);
}
toAdd.push(extension.local);
} else {
toRemove.push(extension.identifier.id);
}
}
if (toAdd.length || toRemove.length) {
if (await this.extensionService.stopExtensionHosts(nls.localize('restart', "Enable or Disable extensions"))) {
await this.extensionService.startExtensionHosts({ toAdd, toRemove });
}
}
}

private getRuntimeState(extension: IExtension): ExtensionRuntimeState | undefined {
const isUninstalled = extension.state === ExtensionState.Uninstalled;
const runningExtension = this.extensionService.extensions.find(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, extension.identifier));
Expand All @@ -1119,7 +1152,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
const canRemoveRunningExtension = runningExtension && this.extensionService.canRemoveExtension(runningExtension);
const isSameExtensionRunning = runningExtension && (!extension.server || extension.server === this.extensionManagementServerService.getExtensionManagementServer(toExtension(runningExtension)));
if (!canRemoveRunningExtension && isSameExtensionRunning && !runningExtension.isUnderDevelopment) {
return { action: ExtensionRuntimeActionType.Reload, reason: nls.localize('postUninstallTooltip', "Please reload {0} to complete the uninstallation of this extension.", this.productService.nameLong) };
return { action: ExtensionRuntimeActionType.RestartExtensions, reason: nls.localize('postUninstallTooltip', "Please restart extensions to complete the uninstallation of this extension.") };
}
return undefined;
}
Expand Down Expand Up @@ -1157,20 +1190,20 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
}
return undefined;
}
return { action: ExtensionRuntimeActionType.Reload, reason: nls.localize('postUpdateTooltip', "Please reload {0} to enable the updated extension.", this.productService.nameLong) };
return { action: ExtensionRuntimeActionType.RestartExtensions, reason: nls.localize('postUpdateTooltip', "Please restart extensions to enable the updated extension.") };
}

if (this.extensionsServers.length > 1) {
const extensionInOtherServer = this.installed.filter(e => areSameExtensions(e.identifier, extension.identifier) && e.server !== extension.server)[0];
if (extensionInOtherServer) {
// This extension prefers to run on UI/Local side but is running in remote
if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnUI(extension.local.manifest) && extensionInOtherServer.server === this.extensionManagementServerService.localExtensionManagementServer) {
return { action: ExtensionRuntimeActionType.Reload, reason: nls.localize('enable locally', "Please reload {0} to enable this extension locally.", this.productService.nameLong) };
return { action: ExtensionRuntimeActionType.RestartExtensions, reason: nls.localize('enable locally', "Please restart extensions to enable this extension locally.") };
}

// This extension prefers to run on Workspace/Remote side but is running in local
if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnWorkspace(extension.local.manifest) && extensionInOtherServer.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
return { action: ExtensionRuntimeActionType.Reload, reason: nls.localize('enable remote', "Please reload {0} to enable this extension in {1}.", this.productService.nameLong, this.extensionManagementServerService.remoteExtensionManagementServer?.label) };
return { action: ExtensionRuntimeActionType.RestartExtensions, reason: nls.localize('enable remote', "Please restart extensions to enable this extension in {1}.", this.extensionManagementServerService.remoteExtensionManagementServer?.label) };
}
}
}
Expand All @@ -1180,20 +1213,20 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
if (extension.server === this.extensionManagementServerService.localExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) {
// This extension prefers to run on UI/Local side but is running in remote
if (this.extensionManifestPropertiesService.prefersExecuteOnUI(extension.local.manifest)) {
return { action: ExtensionRuntimeActionType.Reload, reason: nls.localize('postEnableTooltip', "Please reload {0} to enable this extension.", this.productService.nameLong) };
return { action: ExtensionRuntimeActionType.RestartExtensions, reason: nls.localize('postEnableTooltip', "Please restart extensions to enable this extension.") };
}
}
if (extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) {
// This extension prefers to run on Workspace/Remote side but is running in local
if (this.extensionManifestPropertiesService.prefersExecuteOnWorkspace(extension.local.manifest)) {
return { action: ExtensionRuntimeActionType.Reload, reason: nls.localize('postEnableTooltip', "Please reload {0} to enable this extension.", this.productService.nameLong) };
return { action: ExtensionRuntimeActionType.RestartExtensions, reason: nls.localize('postEnableTooltip', "Please restart extensions to enable this extension.") };
}
}
}
return undefined;
} else {
if (isSameExtensionRunning) {
return { action: ExtensionRuntimeActionType.Reload, reason: nls.localize('postDisableTooltip', "Please reload {0} to disable this extension.", this.productService.nameLong) };
return { action: ExtensionRuntimeActionType.RestartExtensions, reason: nls.localize('postDisableTooltip', "Please restart extensions to disable this extension.") };
}
}
return undefined;
Expand All @@ -1202,15 +1235,15 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
// Extension is not running
else {
if (isEnabled && !this.extensionService.canAddExtension(toExtensionDescription(extension.local))) {
return { action: ExtensionRuntimeActionType.Reload, reason: nls.localize('postEnableTooltip', "Please reload {0} to enable this extension.", this.productService.nameLong) };
return { action: ExtensionRuntimeActionType.RestartExtensions, reason: nls.localize('postEnableTooltip', "Please restart extensions to enable this extension.") };
}

const otherServer = extension.server ? extension.server === this.extensionManagementServerService.localExtensionManagementServer ? this.extensionManagementServerService.remoteExtensionManagementServer : this.extensionManagementServerService.localExtensionManagementServer : null;
if (otherServer && extension.enablementState === EnablementState.DisabledByExtensionKind) {
const extensionInOtherServer = this.local.filter(e => areSameExtensions(e.identifier, extension.identifier) && e.server === otherServer)[0];
// Same extension in other server exists and
if (extensionInOtherServer && extensionInOtherServer.local && this.extensionEnablementService.isEnabled(extensionInOtherServer.local)) {
return { action: ExtensionRuntimeActionType.Reload, reason: nls.localize('postEnableTooltip', "Please reload {0} to enable this extension.", this.productService.nameLong) };
return { action: ExtensionRuntimeActionType.RestartExtensions, reason: nls.localize('postEnableTooltip', "Please restart extensions to enable this extension.") };
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/contrib/extensions/common/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const enum ExtensionState {
}

export const enum ExtensionRuntimeActionType {
Reload = 'reload',
RestartExtensions = 'restartExtensions',
DownloadUpdate = 'downloadUpdate',
ApplyUpdate = 'applyUpdate',
QuitAndInstall = 'quitAndInstall',
Expand Down Expand Up @@ -139,6 +139,7 @@ export interface IExtensionsWorkbenchService {
checkForUpdates(): Promise<void>;
getExtensionStatus(extension: IExtension): IExtensionsStatus | undefined;
updateAll(): Promise<InstallExtensionResult[]>;
updateRunningExtensions(): Promise<void>;

// Sync APIs
isExtensionIgnoredToSync(extension: IExtension): boolean;
Expand Down