Skip to content

Show installation progress in update status bar entry on Windows#292970

Merged
dmitrivMS merged 18 commits intomainfrom
dev/dmitriv/update-progress-win32
Feb 12, 2026
Merged

Show installation progress in update status bar entry on Windows#292970
dmitrivMS merged 18 commits intomainfrom
dev/dmitriv/update-progress-win32

Conversation

@dmitrivMS
Copy link
Contributor

@dmitrivMS dmitrivMS commented Feb 5, 2026

Fixes #293872

image

@dmitrivMS dmitrivMS self-assigned this Feb 5, 2026
@dmitrivMS dmitrivMS added this to the February 2026 milestone Feb 5, 2026
@dmitrivMS dmitrivMS added install-update VS Code installation and upgrade system issues windows VS Code on Windows issues labels Feb 5, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds installation progress reporting to the Windows update status bar entry. When VS Code is updating on Windows, users will now see a progress percentage in both the status bar text and tooltip, providing better visibility into the installation progress.

Changes:

  • Modified the Updating state type to include optional currentProgress and maxProgress fields for tracking installation progress
  • Updated the Windows update service to poll a progress file written by the Inno Setup installer and update the state with progress information
  • Enhanced the status bar UI to display progress percentage when available, with a visual progress bar in the tooltip
  • Modified the Inno Setup installer script to write progress information to a file during background updates

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/vs/platform/update/common/update.ts Extended the Updating state type and factory function to include optional progress tracking fields
src/vs/platform/update/electron-main/updateService.win32.ts Added polling logic to read progress from a file and update the state during installation
src/vs/workbench/contrib/update/browser/updateStatusBarEntry.ts Enhanced UI to display progress percentage in status bar text and tooltip with a visual progress bar
build/win32/code.iss Added Inno Setup callback to write installation progress to a file and cleanup logic for the progress file
Comments suppressed due to low confidence (3)

src/vs/platform/update/electron-main/updateService.win32.ts:348

  • The progress file created during installation is not cleaned up by the Node.js code when the update completes successfully via the ready mutex path or when the child process exits. While the Inno Setup installer does clean up the file in line 1642 of code.iss, if the installer crashes or is terminated abnormally, the progress file will remain in the cache directory.

Consider adding cleanup code to delete the progress file after the ready mutex is detected, or when the child process exits (in the 'exit' event handler at line 316).

		// poll for mutex-ready
		pollUntil(() => mutex.isActive(readyMutexName))
			.then(() => this.setState(State.Ready(update, explicit, this._overwrite)));
	}

src/vs/platform/update/electron-main/updateService.win32.ts:347

  • There's a potential race condition where both pollProgress and the existing pollUntil for the ready mutex could complete at similar times. When the ready mutex becomes active, the pollUntil will call setState(State.Ready(...)) at line 347, but the pollProgress loop at line 326 checks !mutex.isActive(readyMutexName) as its exit condition. If there's a timing issue, the polling loop could make one more setState call after the Ready state has been set, potentially updating the state unnecessarily or causing inconsistencies.

Consider adding a flag or ensuring the polling loop is properly cancelled when the ready state is reached.

		// Poll for progress and ready mutex
		const pollProgress = async () => {
			while (this.state.type === StateType.Updating && !mutex.isActive(readyMutexName)) {
				try {
					const progressContent = await readFile(progressFilePath, 'utf8');
					const [currentStr, maxStr] = progressContent.split(',');
					const currentProgress = parseInt(currentStr, 10);
					const maxProgress = parseInt(maxStr, 10);
					if (!isNaN(currentProgress) && !isNaN(maxProgress) && this.state.type === StateType.Updating) {
						this.setState(State.Updating(update, currentProgress, maxProgress));
					}
				} catch {
					// Progress file may not exist yet or be locked, ignore
				}
				await timeout(500);
			}
		};

		// Start polling for progress
		pollProgress();

		// poll for mutex-ready
		pollUntil(() => mutex.isActive(readyMutexName))
			.then(() => this.setState(State.Ready(update, explicit, this._overwrite)));

src/vs/workbench/contrib/update/browser/updateStatusBarEntry.ts:330

  • The percentage calculation doesn't bound the result to a maximum of 100%. If currentProgress exceeds maxProgress (which could happen due to timing issues or installer bugs), the percentage could exceed 100%, potentially causing the progress bar to overflow its container or display misleading information like "105%".

Consider capping the percentage at 100% using Math.min(Math.round((currentProgress / maxProgress) * 100), 100) to handle edge cases gracefully.

					const percentage = Math.round((currentProgress / maxProgress) * 100);

					const progressContainer = dom.append(container, dom.$('.progress-container'));
					const progressBar = dom.append(progressContainer, dom.$('.progress-bar'));
					const progressFill = dom.append(progressBar, dom.$('.progress-fill'));
					progressFill.style.width = `${percentage}%`;

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (2)

src/vs/platform/update/electron-main/updateService.win32.ts:365

  • pollProgress() is started without awaiting/handling rejection. If anything throws outside the inner try/catch (e.g. mutex access), this can become an unhandled promise rejection. Consider invoking it with void … and attaching a .catch(...) (or wrapping the loop body in a top-level try/catch) to ensure failures are contained/logged.
		// Poll for progress and ready mutex
		const pollProgress = async () => {
			while (this.state.type === StateType.Updating && !mutex.isActive(readyMutexName)) {
				try {
					const progressContent = await readFile(progressFilePath, 'utf8');
					const [currentStr, maxStr] = progressContent.split(',');
					const currentProgress = parseInt(currentStr, 10);
					const maxProgress = parseInt(maxStr, 10);
					if (!isNaN(currentProgress) && !isNaN(maxProgress) && this.state.type === StateType.Updating) {
						this.setState(State.Updating(update, currentProgress, maxProgress));
					}
				} catch {
					// Progress file may not exist yet or be locked, ignore
				}
				await timeout(500);
			}
		};

		// Start polling for progress
		pollProgress();

src/vs/platform/update/electron-main/updateService.win32.ts:359

  • The progress polling loop calls setState(State.Updating(...)) every 500ms even if the parsed values haven’t changed, which will fire onStateChange and log update#setState repeatedly. Consider comparing against the current state’s currentProgress/maxProgress and only calling setState when the values actually change.
					const progressContent = await readFile(progressFilePath, 'utf8');
					const [currentStr, maxStr] = progressContent.split(',');
					const currentProgress = parseInt(currentStr, 10);
					const maxProgress = parseInt(maxStr, 10);
					if (!isNaN(currentProgress) && !isNaN(maxProgress) && this.state.type === StateType.Updating) {
						this.setState(State.Updating(update, currentProgress, maxProgress));
					}
				} catch {
					// Progress file may not exist yet or be locked, ignore
				}
				await timeout(500);

@dmitrivMS dmitrivMS marked this pull request as ready for review February 9, 2026 13:21
@dmitrivMS dmitrivMS enabled auto-merge (squash) February 9, 2026 13:23
@dmitrivMS dmitrivMS disabled auto-merge February 10, 2026 12:48
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Copy link
Collaborator

@deepak1556 deepak1556 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with nit

@dmitrivMS dmitrivMS merged commit e44773c into main Feb 12, 2026
40 of 41 checks passed
@dmitrivMS dmitrivMS deleted the dev/dmitriv/update-progress-win32 branch February 12, 2026 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

install-update VS Code installation and upgrade system issues windows VS Code on Windows issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update status bar tooltip should show progress during Install phase

3 participants