@@ -273,7 +273,7 @@ index 2be53f61..53904dab 100644
273273+
274274 this.setState(State.Idle(UpdateType.Archive, message));
275275diff --git a/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts
276- index a7851933..dafc4447 100644
276+ index bbbc3bde..372de75a 100644
277277--- a/src/vs/platform/update/electron-main/updateService.win32.ts
278278+++ b/src/vs/platform/update/electron-main/updateService.win32.ts
279279@@ -14,3 +14,2 @@ import { CancellationToken, CancellationTokenSource } from '../../../base/common
@@ -304,29 +304,20 @@ index a7851933..dafc4447 100644
304304+ _updateType = UpdateType.Archive;
305305+ }
306306 }
307- @@ -57,2 +60,8 @@ function getUpdateType(): UpdateType {
308-
309- + async function pollUntil(fn: () => boolean, millis = 1000): Promise<void> {
310- + while (!fn()) {
311- + await timeout(millis);
312- + }
313- + }
314- +
315- export class Win32UpdateService extends AbstractUpdateService implements IRelaunchHandler {
316- @@ -144,5 +153,6 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
307+ @@ -144,5 +147,6 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
317308 try {
318309+ const updateType = getUpdateType();
319310 const updatingVersion = (await readFile(updatingVersionPath, 'utf8')).trim();
320311 this.logService.info(`update#doCheckForUpdates - application was updating to version ${updatingVersion}`);
321312- const updatePackagePath = await this.getUpdatePackagePath(updatingVersion);
322313+ const updatePackagePath = await this.getUpdatePackagePath(updatingVersion, updateType);
323314 if (await pfs.Promises.exists(updatePackagePath)) {
324- @@ -157,3 +167 ,3 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
315+ @@ -157,3 +161 ,3 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
325316 } else {
326317- const fastUpdatesEnabled = this.configurationService.getValue('update.enableWindowsBackgroundUpdates');
327318+ const fastUpdatesEnabled = getUpdateType() === UpdateType.Setup && this.configurationService.getValue('update.enableWindowsBackgroundUpdates');
328319 // GC for background updates in system setup happens via inno_setup since it requires
329- @@ -215 ,12 +225 ,22 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
320+ @@ -176 ,12 +180 ,22 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
330321
331322- protected buildUpdateFeedUrl(quality: string, commit: string, options?: IUpdateURLOptions): string | undefined {
332323- let platform = `win32-${process.arch}`;
@@ -357,14 +348,14 @@ index a7851933..dafc4447 100644
357348- return createUpdateURL(this.productService.updateUrl!, platform, quality, commit, options);
358349+ return createUpdateURL(this.productService, quality, process.platform, process.arch, target);
359350 }
360- @@ -232 ,6 +252 ,2 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
351+ @@ -193 ,6 +207 ,2 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
361352
362353- const internalOrg = this.getInternalOrg();
363354- const background = !explicit && !internalOrg;
364355- const url = this.buildUpdateFeedUrl(this.quality, pendingCommit ?? this.productService.commit!, { background, internalOrg });
365356-
366357 // Only set CheckingForUpdates if we're not already in Overwriting state
367- @@ -241 ,9 +257 ,13 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
358+ @@ -202 ,9 +212 ,13 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
368359
369360- const headers = getUpdateRequestHeaders(this.productService.version);
370361- this.requestService.request({ url, headers, callSite: 'updateService.win32.checkForUpdates' }, CancellationToken.None)
@@ -383,7 +374,7 @@ index a7851933..dafc4447 100644
383374- if (!update || !update.url || !update.version || !update.productVersion) {
384375+ if(!result) {
385376 // If we were checking for an overwrite update and found nothing newer,
386- @@ -259 ,2 +279 ,9 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
377+ @@ -220 ,2 +234 ,9 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
387378
388379+ const { lastest, update } = result;
389380+
@@ -393,17 +384,17 @@ index a7851933..dafc4447 100644
393384+ }
394385+
395386 if (updateType === UpdateType.Archive) {
396- @@ -276 ,3 +303 ,3 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
387+ @@ -237 ,3 +258 ,3 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
397388 return this.cleanup(update.version).then(() => {
398389- return this.getUpdatePackagePath(update.version).then(updatePackagePath => {
399390+ return this.getUpdatePackagePath(update.version, updateType).then(updatePackagePath => {
400391 return pfs.Promises.exists(updatePackagePath).then(exists => {
401- @@ -284 ,3 +311 ,3 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
392+ @@ -245 ,3 +266 ,3 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
402393
403394- return this.requestService.request({ url: update.url, callSite: 'updateService.win32.downloadUpdate' }, CancellationToken.None)
404395+ return this.requestService.request({ url: update.url, callSite: NO_FETCH_TELEMETRY }, CancellationToken.None)
405396 .then(context => {
406- @@ -329 ,8 +356 ,7 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
397+ @@ -290 ,8 +311 ,7 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
407398 })
408399- .then(undefined, err => {
409400- this.telemetryService.publicLog2<{ messageHash: string }, UpdateErrorClassification>('update:error', { messageHash: String(hash(String(err))) });
@@ -415,7 +406,7 @@ index a7851933..dafc4447 100644
415406- const message: string | undefined = explicit ? (err.message || err) : undefined;
416407+ const message: string | undefined = explicit ? (error.message || error) : undefined;
417408
418- @@ -354 ,5 +380 ,7 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
409+ @@ -315 ,5 +335 ,7 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
419410
420411- private async getUpdatePackagePath(version: string): Promise<string> {
421412+ private async getUpdatePackagePath(version: string, type: UpdateType): Promise<string> {
@@ -425,12 +416,12 @@ index a7851933..dafc4447 100644
425416+
426417+ return path.join(cachePath, `${this.productService.nameShort.replaceAll(/\s/g, '')}-${this.productService.quality}-${version}.${extension}`);
427418 }
428- @@ -360 ,3 +388 ,3 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
419+ @@ -321 ,3 +343 ,3 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
429420 private async cleanup(exceptVersion: string | null = null): Promise<void> {
430421- const filter = exceptVersion ? (one: string) => !(new RegExp(`${this.productService.quality}-${exceptVersion}\\.exe$`).test(one)) : () => true;
431422+ const filter = exceptVersion ? (one: string) => !(new RegExp(`${this.productService.quality}-${exceptVersion}\\.(exe|msi)$`).test(one)) : () => true;
432423
433- @@ -394,77 +422,100 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
424+ @@ -355,14 +377,10 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
434425 await pfs.Promises.writeFile(this.availableUpdate.updateFilePath, 'flag');
435426- const child = spawn(this.availableUpdate.packagePath,
436427- [
@@ -449,34 +440,15 @@ index a7851933..dafc4447 100644
449440+
450441+ const type = getUpdateType();
451442+ if (type == UpdateType.WindowsInstaller) {
443+ + this.logService.info(`update#doApplyUpdate - msiexec.exe /i ${this.availableUpdate.packagePath}`);
444+ +
452445+ child = spawn('msiexec.exe', ['/i', this.availableUpdate.packagePath], {
453446 detached: true,
454- stdio: ['ignore', 'ignore', 'ignore'],
455- - windowsVerbatimArguments: true,
456- - env: { ...process.env, __COMPAT_LAYER: 'RunAsInvoker' }
447+ @@ -371,4 +389,23 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
448+ env: { ...process.env, __COMPAT_LAYER: 'RunAsInvoker' }
457449- }
458450- );
459451+ });
460-
461- - // Track the process so we can cancel it if needed
462- - this.availableUpdate.updateProcess = child;
463- + child.once('exit', () => {
464- + this.availableUpdate = undefined;
465- + this.setState(State.Idle(getUpdateType()));
466- + });
467-
468- - child.once('exit', () => {
469- - this.availableUpdate = undefined;
470- - this.setState(State.Idle(getUpdateType()));
471- - });
472- + const readyMutexName = `${this.productService.win32MutexName}-ready`;
473- + const mutex = await import('@vscode/windows-mutex');
474-
475- - const readyMutexName = `${this.productService.win32MutexName}-ready`;
476- - const mutex = await import('@vscode/windows-mutex');
477- + // poll for mutex-ready
478- + pollUntil(() => mutex.isActive(readyMutexName))
479- + .then(() => this.setState(State.Ready(update, explicit, this._overwrite)));
480452+ } else {
481453+ child = spawn(this.availableUpdate.packagePath,
482454+ [
@@ -496,101 +468,30 @@ index a7851933..dafc4447 100644
496468+ env: { ...process.env, __COMPAT_LAYER: 'RunAsInvoker' }
497469+ }
498470+ );
499-
500- - this.updateCancellationTokenSource?.dispose(true);
501- - const cts = this.updateCancellationTokenSource = new CancellationTokenSource();
502- - const token = cts.token;
503- + // Track the process so we can cancel it if needed
504- + this.availableUpdate.updateProcess = child;
505-
506- - const poll = async () => {
507- - while (this.state.type === StateType.Updating && !token.isCancellationRequested) {
508- - if (mutex.isActive(readyMutexName)) {
509- - this.setState(State.Ready(update, explicit, this._overwrite));
510- - return;
511- - }
512- + child.once('exit', () => {
513- + this.availableUpdate = undefined;
514- + this.setState(State.Idle(getUpdateType()));
515- + });
516-
517- - try {
518- - const progressContent = await readFile(progressFilePath, 'utf8');
519- - if (!token.isCancellationRequested) {
520- - const [currentStr, maxStr] = progressContent.split(',');
521- - const currentProgress = parseInt(currentStr, 10);
522- - const maxProgress = parseInt(maxStr, 10);
523- - if (!isNaN(currentProgress) && !isNaN(maxProgress) && this.state.type === StateType.Updating) {
524- - if (this.state.currentProgress !== currentProgress || this.state.maxProgress !== maxProgress) {
525- - this.setState(State.Updating(update, explicit, currentProgress, maxProgress));
526- + const readyMutexName = `${this.productService.win32MutexName}-ready`;
527- + const mutex = await import('@vscode/windows-mutex');
528- +
529- + this.updateCancellationTokenSource?.dispose(true);
530- + const cts = this.updateCancellationTokenSource = new CancellationTokenSource();
531- + const token = cts.token;
532- +
533- + const poll = async () => {
534- + while (this.state.type === StateType.Updating && !token.isCancellationRequested) {
535- + if (mutex.isActive(readyMutexName)) {
536- + this.setState(State.Ready(update, explicit, this._overwrite));
537- + return;
538- + }
539- +
540- + try {
541- + const progressContent = await readFile(progressFilePath, 'utf8');
542- + if (!token.isCancellationRequested) {
543- + const [currentStr, maxStr] = progressContent.split(',');
544- + const currentProgress = parseInt(currentStr, 10);
545- + const maxProgress = parseInt(maxStr, 10);
546- + if (!isNaN(currentProgress) && !isNaN(maxProgress) && this.state.type === StateType.Updating) {
547- + if (this.state.currentProgress !== currentProgress || this.state.maxProgress !== maxProgress) {
548- + this.setState(State.Updating(update, explicit, currentProgress, maxProgress));
549- + }
550- }
551- }
552- + } catch {
553- + // Progress file may not exist yet or be locked, ignore
554- }
555- - } catch {
556- - // Progress file may not exist yet or be locked, ignore
557- - }
558- -
559- - await timeout(500);
560- - }
561- - };
562-
563- - const cancelTimeout = new ProcessTimeRunOnceScheduler(() => {
564- - this.logService.warn('update#doApplyUpdate: polling timed out waiting for update to be ready');
565- - this.setState(State.Idle(getUpdateType(), 'Update did not complete within expected time'));
566- - }, 60 * 60 * 1000);
567- -
568- - // Poll for progress and ready mutex for 1 hour.
569- - cancelTimeout.schedule();
570- - poll().finally(() => {
571- - cancelTimeout.dispose();
572- - if (this.updateCancellationTokenSource === cts) {
573- - this.updateCancellationTokenSource = undefined;
574- - }
575- - cts.dispose();
576- - });
577- + await timeout(500);
578- + }
579- + };
580- +
581- + const cancelTimeout = new ProcessTimeRunOnceScheduler(() => {
582- + this.logService.warn('update#doApplyUpdate: polling timed out waiting for update to be ready');
583- + this.setState(State.Idle(getUpdateType(), 'Update did not complete within expected time'));
584- + }, 60 * 60 * 1000);
585- +
586- + // Poll for progress and ready mutex for 1 hour.
587- + cancelTimeout.schedule();
588- + poll().finally(() => {
589- + cancelTimeout.dispose();
590- + if (this.updateCancellationTokenSource === cts) {
591- + this.updateCancellationTokenSource = undefined;
592- + }
593- + cts.dispose();
594- + });
595471+ }
596- }
472+
473+ @@ -490,7 +527,19 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
474+ } else {
475+ - spawn(this.availableUpdate.packagePath, ['/silent', '/log', '/mergetasks=runcode,!desktopicon,!quicklaunchicon'], {
476+ - detached: true,
477+ - stdio: ['ignore', 'ignore', 'ignore'],
478+ - env: { ...process.env, __COMPAT_LAYER: 'RunAsInvoker' }
479+ - });
480+ + const type = getUpdateType();
481+ + if (type == UpdateType.WindowsInstaller) {
482+ + this.logService.info(`update#doQuitAndInstall - msiexec.exe /i ${this.availableUpdate.packagePath}`);
483+ +
484+ + spawn('msiexec.exe', ['/i', this.availableUpdate.packagePath], {
485+ + detached: true,
486+ + stdio: ['ignore', 'ignore', 'ignore'],
487+ + env: { ...process.env, __COMPAT_LAYER: 'RunAsInvoker' }
488+ + });
489+ + }
490+ + else {
491+ + spawn(this.availableUpdate.packagePath, ['/silent', '/log', '/mergetasks=runcode,!desktopicon,!quicklaunchicon'], {
492+ + detached: true,
493+ + stdio: ['ignore', 'ignore', 'ignore'],
494+ + env: { ...process.env, __COMPAT_LAYER: 'RunAsInvoker' }
495+ + });
496+ + }
497+ }
0 commit comments