6f9cb5646f
Two follow-ups to the previous Config Checkpoints commit:
1. Bring back the post-install "Launch Webhook Server" checkbox in the
installer. The previous attempt failed because Inno Setup's
postinstall flag launches via CreateProcess after Setup exits,
bypassing the GUI's requireAdministrator manifest. Adding the
shellexec flag switches to ShellExecute, which DOES honor the
manifest and triggers a clean UAC prompt - so the post-install
GUI launch works as expected.
2. Each checkpoint now carries a description, stored in a sidecar
.meta.json file next to the snapshot. Defaults:
- Auto-on-save: "Before save"
- Midnight scheduler: "Nightly auto-checkpoint"
- Manual: opens a small dialog so the user can type a meaningful
description (defaults to "Manual checkpoint" if blank)
The dialog and pruning both clean up sidecars alongside snapshots.
The Config Checkpoints grid grows a Description column between
When and Size.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
125 lines
5.2 KiB
Plaintext
125 lines
5.2 KiB
Plaintext
; Inno Setup script for Webhook Server.
|
|
;
|
|
; Build: iscc /DAppVersion=0.1.0 webhook-server.iss
|
|
; Output: ..\dist\WebhookServer-Setup-{AppVersion}.exe
|
|
;
|
|
; The installer copies published binaries to {pf}\WebhookServer, installs the
|
|
; Windows Service via install-service.ps1 post-install, and removes the service
|
|
; via uninstall-service.ps1 pre-uninstall. Start Menu gets a single GUI shortcut.
|
|
|
|
#ifndef AppVersion
|
|
#define AppVersion "0.1.0"
|
|
#endif
|
|
|
|
#define AppName "Webhook Server"
|
|
#define AppPublisher "Justin Paul"
|
|
#define AppURL "https://jpaul.me"
|
|
#define AppExeName "WebhookServer.Gui.exe"
|
|
#define ServiceExeName "WebhookServer.Service.exe"
|
|
#define ServiceName "WebhookServer"
|
|
#define RepoRoot "..\"
|
|
|
|
[Setup]
|
|
AppId={{6E3B3C1A-9C20-4F50-B6A8-2B6D6D7E2F11}
|
|
AppName={#AppName}
|
|
AppVersion={#AppVersion}
|
|
AppPublisher={#AppPublisher}
|
|
AppPublisherURL={#AppURL}
|
|
AppSupportURL=https://github.com/recklessop/webhook-server
|
|
AppUpdatesURL=https://github.com/recklessop/webhook-server/releases
|
|
DefaultDirName={autopf}\WebhookServer
|
|
DefaultGroupName={#AppName}
|
|
DisableProgramGroupPage=yes
|
|
OutputBaseFilename=WebhookServer-Setup-{#AppVersion}
|
|
OutputDir={#RepoRoot}dist
|
|
SetupIconFile={#RepoRoot}resources\webhook-server.ico
|
|
UninstallDisplayIcon={app}\{#AppExeName}
|
|
PrivilegesRequired=admin
|
|
ArchitecturesAllowed=x64compatible
|
|
ArchitecturesInstallIn64BitMode=x64compatible
|
|
Compression=lzma2/max
|
|
SolidCompression=yes
|
|
WizardStyle=modern
|
|
VersionInfoVersion={#AppVersion}.0
|
|
VersionInfoCompany={#AppPublisher}
|
|
VersionInfoProductName={#AppName}
|
|
|
|
[Languages]
|
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
|
|
|
[Tasks]
|
|
Name: "desktopicon"; Description: "Create a &desktop shortcut"; GroupDescription: "Additional shortcuts:"; Flags: unchecked
|
|
|
|
[Files]
|
|
Source: "{#RepoRoot}publish\service\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
|
Source: "{#RepoRoot}publish\gui\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
|
Source: "{#RepoRoot}scripts\install-service.ps1"; DestDir: "{app}\scripts"; Flags: ignoreversion
|
|
Source: "{#RepoRoot}scripts\uninstall-service.ps1"; DestDir: "{app}\scripts"; Flags: ignoreversion
|
|
Source: "{#RepoRoot}scripts\examples\*"; DestDir: "{app}\scripts\examples"; Flags: ignoreversion recursesubdirs createallsubdirs
|
|
Source: "{#RepoRoot}README.md"; DestDir: "{app}"; Flags: ignoreversion
|
|
Source: "{#RepoRoot}docs\*"; DestDir: "{app}\docs"; Flags: ignoreversion recursesubdirs createallsubdirs
|
|
Source: "{#RepoRoot}resources\webhook-server.ico"; DestDir: "{app}"; Flags: ignoreversion
|
|
|
|
[Icons]
|
|
Name: "{group}\{#AppName}"; Filename: "{app}\{#AppExeName}"; IconFilename: "{app}\webhook-server.ico"
|
|
Name: "{group}\Uninstall {#AppName}"; Filename: "{uninstallexe}"
|
|
Name: "{commondesktop}\{#AppName}"; Filename: "{app}\{#AppExeName}"; IconFilename: "{app}\webhook-server.ico"; Tasks: desktopicon
|
|
|
|
[Run]
|
|
Filename: "powershell.exe"; \
|
|
Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\scripts\install-service.ps1"" -BinaryPath ""{app}\{#ServiceExeName}"""; \
|
|
StatusMsg: "Installing Windows Service..."; \
|
|
Flags: runhidden
|
|
; Post-install GUI launch. The GUI's app.manifest is requireAdministrator,
|
|
; so launching with shellexec (ShellExecute) honors the manifest and triggers
|
|
; a clean UAC prompt. Using plain CreateProcess via the default Run path
|
|
; would skip the manifest and result in an un-elevated GUI that cannot connect
|
|
; to the admin pipe.
|
|
Filename: "{app}\{#AppExeName}"; \
|
|
Description: "Launch {#AppName}"; \
|
|
Flags: postinstall nowait shellexec skipifsilent
|
|
|
|
[UninstallRun]
|
|
Filename: "powershell.exe"; \
|
|
Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\scripts\uninstall-service.ps1"""; \
|
|
Flags: runhidden; \
|
|
RunOnceId: "RemoveWebhookService"
|
|
|
|
[Code]
|
|
function ServiceExists(): Boolean;
|
|
var
|
|
ResultCode: Integer;
|
|
begin
|
|
// sc.exe query returns 0 when the service exists, 1060 when it does not.
|
|
Exec(ExpandConstant('{sys}\sc.exe'), 'query WebhookServer', '', SW_HIDE,
|
|
ewWaitUntilTerminated, ResultCode);
|
|
Result := (ResultCode = 0);
|
|
end;
|
|
|
|
function PrepareToInstall(var NeedsRestart: Boolean): String;
|
|
var
|
|
ResultCode: Integer;
|
|
begin
|
|
Result := '';
|
|
|
|
// 1. If the service exists, stop it so its binaries are unlocked before file
|
|
// copy. net stop is synchronous (blocks until the service is actually
|
|
// stopped), unlike sc stop which is fire-and-forget. Non-zero exit -
|
|
// already stopped, missing, dependency error - we ignore; the file copy
|
|
// will fail loudly if the binaries are still locked.
|
|
if ServiceExists() then
|
|
begin
|
|
WizardForm.PreparingLabel.Caption := 'Stopping the WebhookServer service...';
|
|
Exec(ExpandConstant('{sys}\net.exe'), 'stop WebhookServer', '', SW_HIDE,
|
|
ewWaitUntilTerminated, ResultCode);
|
|
end;
|
|
|
|
// 2. Kill any running GUI / tray instances so their binaries are unlocked too.
|
|
// /f forces termination, /im matches by image name, "*" wildcard would be
|
|
// risky so we name them explicitly.
|
|
Exec(ExpandConstant('{sys}\taskkill.exe'), '/f /im WebhookServer.Gui.exe',
|
|
'', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
|
Exec(ExpandConstant('{sys}\taskkill.exe'), '/f /im WebhookServer.Service.exe',
|
|
'', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
|
end;
|