From 42fcfb8bfc975a450fcc7f32ce11ad0c4171a9b8 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 19 May 2023 11:07:43 +0200 Subject: [PATCH] innosetup to start/stop tunnel service (#180527) * innosetup to start/stop tunnel service * better messages for tunnel still running * fix error * more logs * add '/log' * update * fix * update * add kill & timeout wait * stop service in PrepareToInstall * non-background: check for tunnel mutex when wizard starts * polish tunnel mutex names, prompt if tunnel is still running --- build/gulpfile.vscode.win32.js | 3 + build/win32/code.iss | 100 ++++++++++++++---- product.json | 4 +- .../electron-main/updateService.win32.ts | 4 +- 4 files changed, 88 insertions(+), 23 deletions(-) diff --git a/build/gulpfile.vscode.win32.js b/build/gulpfile.vscode.win32.js index 0d3abdae01b..6e9a6f331ba 100644 --- a/build/gulpfile.vscode.win32.js +++ b/build/gulpfile.vscode.win32.js @@ -99,6 +99,9 @@ function buildWin32Setup(arch, target) { RegValueName: product.win32RegValueName, ShellNameShort: product.win32ShellNameShort, AppMutex: product.win32MutexName, + TunnelMutex: product.win32TunnelMutex, + TunnelServiceMutex: product.win32TunnelServiceMutex, + ApplicationName: product.applicationName, Arch: arch, AppId: { 'ia32': ia32AppId, 'x64': x64AppId, 'arm64': arm64AppId }[arch], IncompatibleTargetAppId: { 'ia32': product.win32AppId, 'x64': product.win32x64AppId, 'arm64': product.win32arm64AppId }[arch], diff --git a/build/win32/code.iss b/build/win32/code.iss index d365ab1cbda..7754562225b 100644 --- a/build/win32/code.iss +++ b/build/win32/code.iss @@ -62,13 +62,13 @@ Name: "hungarian"; MessagesFile: "{#RepoDir}\build\win32\i18n\Default.hu.isl,{#R Name: "turkish"; MessagesFile: "compiler:Languages\Turkish.isl,{#RepoDir}\build\win32\i18n\messages.tr.isl" {#LocalizedLanguageFile("trk")} [InstallDelete] -Type: filesandordirs; Name: "{app}\resources\app\out"; Check: IsNotUpdate -Type: filesandordirs; Name: "{app}\resources\app\plugins"; Check: IsNotUpdate -Type: filesandordirs; Name: "{app}\resources\app\extensions"; Check: IsNotUpdate -Type: filesandordirs; Name: "{app}\resources\app\node_modules"; Check: IsNotUpdate -Type: filesandordirs; Name: "{app}\resources\app\node_modules.asar.unpacked"; Check: IsNotUpdate -Type: files; Name: "{app}\resources\app\node_modules.asar"; Check: IsNotUpdate -Type: files; Name: "{app}\resources\app\Credits_45.0.2454.85.html"; Check: IsNotUpdate +Type: filesandordirs; Name: "{app}\resources\app\out"; Check: IsNotBackgroundUpdate +Type: filesandordirs; Name: "{app}\resources\app\plugins"; Check: IsNotBackgroundUpdate +Type: filesandordirs; Name: "{app}\resources\app\extensions"; Check: IsNotBackgroundUpdate +Type: filesandordirs; Name: "{app}\resources\app\node_modules"; Check: IsNotBackgroundUpdate +Type: filesandordirs; Name: "{app}\resources\app\node_modules.asar.unpacked"; Check: IsNotBackgroundUpdate +Type: files; Name: "{app}\resources\app\node_modules.asar"; Check: IsNotBackgroundUpdate +Type: files; Name: "{app}\resources\app\Credits_45.0.2454.85.html"; Check: IsNotBackgroundUpdate [UninstallDelete] Type: filesandordirs; Name: "{app}\_" @@ -1299,6 +1299,16 @@ Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Drive\shell\{#RegValu Root: {#EnvironmentRootKey}; Subkey: "{#EnvironmentKey}"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}\bin"; Tasks: addtopath; Check: NeedsAddPath(ExpandConstant('{app}\bin')) [Code] +function IsBackgroundUpdate(): Boolean; +begin + Result := ExpandConstant('{param:update|false}') <> 'false'; +end; + +function IsNotBackgroundUpdate(): Boolean; +begin + Result := not IsBackgroundUpdate(); +end; + // Don't allow installing conflicting architectures function InitializeSetup(): Boolean; var @@ -1351,6 +1361,13 @@ begin MsgBox('Please uninstall the ' + AltArch + '-bit version of {#NameShort} before installing this ' + ThisArch + '-bit version.', mbInformation, MB_OK); end; end; + + if IsNotBackgroundUpdate() and CheckForMutexes('{#TunnelMutex}') then + begin + MsgBox('{#NameShort} is still running a tunnel. Please stop the tunnel before installing.', mbInformation, MB_OK); + Result := false + end; + end; function WizardNotSilent(): Boolean; @@ -1359,14 +1376,44 @@ begin end; // Updates -function IsBackgroundUpdate(): Boolean; + +var + ShouldRestartTunnelService: Boolean; + +procedure StopTunnelServiceIfNeeded(); +var + StopServiceResultCode: Integer; + WaitCounter: Integer; begin - Result := ExpandConstant('{param:update|false}') <> 'false'; + ShouldRestartTunnelService := False; + if CheckForMutexes('{#TunnelServiceMutex}') then begin + // stop the tunnel service + Log('Stopping the tunnel service using ' + ExpandConstant('"{app}\bin\{#ApplicationName}.cmd"')); + ShellExec('', ExpandConstant('"{app}\bin\{#ApplicationName}.cmd"'), 'tunnel service uninstall', '', SW_HIDE, ewWaitUntilTerminated, StopServiceResultCode); + + Log('Stopping the tunnel service completed with result code ' + IntToStr(StopServiceResultCode)); + + WaitCounter := 10; + while (WaitCounter > 0) and CheckForMutexes('{#TunnelServiceMutex}') do + begin + Log('Tunnel service is still running, waiting'); + Sleep(500); + WaitCounter := WaitCounter - 1 + end; + if CheckForMutexes('{#TunnelServiceMutex}') then + Log('Unable to stop tunnel service') + else + ShouldRestartTunnelService := True; + end end; -function IsNotUpdate(): Boolean; + +// called before the wizard checks for running application +function PrepareToInstall(var NeedsRestart: Boolean): String; begin - Result := not IsBackgroundUpdate(); + if IsNotBackgroundUpdate() then + StopTunnelServiceIfNeeded(); + Result := '' end; // VS Code will create a flag file before the update starts (/update=C:\foo\bar) @@ -1450,18 +1497,33 @@ end; procedure CurStepChanged(CurStep: TSetupStep); var UpdateResultCode: Integer; + StartServiceResultCode: Integer; begin - if IsBackgroundUpdate() and (CurStep = ssPostInstall) then + if CurStep = ssPostInstall then begin - CreateMutex('{#AppMutex}-ready'); - - while (CheckForMutexes('{#AppMutex}')) do + if IsBackgroundUpdate() then begin - Log('Application is still running, waiting'); - Sleep(1000); + CreateMutex('{#AppMutex}-ready'); + + while (CheckForMutexes('{#AppMutex}')) do + begin + Log('Application is still running, waiting'); + Sleep(1000) + end; + + StopTunnelServiceIfNeeded(); + + Exec(ExpandConstant('{app}\tools\inno_updater.exe'), ExpandConstant('"{app}\{#ExeBasename}.exe" ' + BoolToStr(LockFileExists())), '', SW_SHOW, ewWaitUntilTerminated, UpdateResultCode); end; - Exec(ExpandConstant('{app}\tools\inno_updater.exe'), ExpandConstant('"{app}\{#ExeBasename}.exe" ' + BoolToStr(LockFileExists())), '', SW_SHOW, ewWaitUntilTerminated, UpdateResultCode); + if ShouldRestartTunnelService then + begin + // start the tunnel service + Log('Restarting the tunnel service...'); + ShellExec('', ExpandConstant('"{app}\bin\{#ApplicationName}.cmd"'), 'tunnel service install', '', SW_HIDE, ewWaitUntilTerminated, StartServiceResultCode); + Log('Starting the tunnel service completed with result code ' + IntToStr(StartServiceResultCode)); + ShouldRestartTunnelService := False + end; end; end; @@ -1545,4 +1607,4 @@ begin #endif Exec(ExpandConstant('{sys}\icacls.exe'), ExpandConstant('"{app}" /inheritancelevel:r ') + Permissions, '', SW_HIDE, ewWaitUntilTerminated, ResultCode); -end; +end; \ No newline at end of file diff --git a/product.json b/product.json index 56048315511..f801597290e 100644 --- a/product.json +++ b/product.json @@ -24,8 +24,8 @@ "win32arm64UserAppId": "{{3AEBF0C8-F733-4AD4-BADE-FDB816D53D7B}", "win32AppUserModelId": "Microsoft.CodeOSS", "win32ShellNameShort": "C&ode - OSS", - "win32TunnelServiceMutex": "vscodetunnelserviceoss", - "win32TunnelMutex": "vscodetunneloss", + "win32TunnelServiceMutex": "vscodeoss-tunnelservice", + "win32TunnelMutex": "vscodeoss-tunnel", "darwinBundleIdentifier": "com.visualstudio.code.oss", "linuxIconName": "code-oss", "licenseFileName": "LICENSE.txt", diff --git a/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts index f4c506f55d1..d45291e67e6 100644 --- a/src/vs/platform/update/electron-main/updateService.win32.ts +++ b/src/vs/platform/update/electron-main/updateService.win32.ts @@ -212,7 +212,7 @@ export class Win32UpdateService extends AbstractUpdateService { this.availableUpdate.updateFilePath = path.join(cachePath, `CodeSetup-${this.productService.quality}-${update.version}.flag`); await pfs.Promises.writeFile(this.availableUpdate.updateFilePath, 'flag'); - const child = spawn(this.availableUpdate.packagePath, ['/verysilent', `/update="${this.availableUpdate.updateFilePath}"`, '/nocloseapplications', '/mergetasks=runcode,!desktopicon,!quicklaunchicon'], { + const child = spawn(this.availableUpdate.packagePath, ['/verysilent', '/log', `/update="${this.availableUpdate.updateFilePath}"`, '/nocloseapplications', '/mergetasks=runcode,!desktopicon,!quicklaunchicon'], { detached: true, stdio: ['ignore', 'ignore', 'ignore'], windowsVerbatimArguments: true @@ -241,7 +241,7 @@ export class Win32UpdateService extends AbstractUpdateService { if (this.state.update.supportsFastUpdate && this.availableUpdate.updateFilePath) { fs.unlinkSync(this.availableUpdate.updateFilePath); } else { - spawn(this.availableUpdate.packagePath, ['/silent', '/mergetasks=runcode,!desktopicon,!quicklaunchicon'], { + spawn(this.availableUpdate.packagePath, ['/silent', '/log', '/mergetasks=runcode,!desktopicon,!quicklaunchicon'], { detached: true, stdio: ['ignore', 'ignore', 'ignore'] });