bambuddy.iss 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. ; Bambuddy Windows Installer — Inno Setup script
  2. ;
  3. ; Builds a self-contained installer that lays down:
  4. ; - embedded Python 3.13 + pre-installed venv
  5. ; - backend source + pre-built frontend bundle
  6. ; - NSSM + ffmpeg under bin/
  7. ; - a Windows service running as LocalSystem
  8. ;
  9. ; Build prerequisites: run installers/windows/build.py first to stage
  10. ; the build/staging/ tree, then compile this file with ISCC.exe.
  11. ;
  12. ; See installers/windows/README.md for the full pipeline.
  13. #define MyAppName "Bambuddy"
  14. #define MyAppPublisher "Martin Ziegler"
  15. #define MyAppURL "https://bambuddy.cool"
  16. #define MyAppExeName "bambuddy.exe"
  17. #define ServiceName "Bambuddy"
  18. #define DefaultPort "8000"
  19. ; Version is stamped by build.py into build\staging\version.iss as a
  20. ; #define directive. Falls back to a placeholder if you ran ISCC without
  21. ; running build.py first (don't ship that build).
  22. #ifexist "build\staging\version.iss"
  23. #include "build\staging\version.iss"
  24. #else
  25. #define MyAppVersion "0.0.0+dev"
  26. #endif
  27. [Setup]
  28. AppId={{8C9C9E1A-7C5A-4F2A-9F1B-BAMBUDDY00001}}
  29. AppName={#MyAppName}
  30. AppVersion={#MyAppVersion}
  31. AppPublisher={#MyAppPublisher}
  32. AppPublisherURL={#MyAppURL}
  33. AppSupportURL={#MyAppURL}
  34. AppUpdatesURL={#MyAppURL}
  35. DefaultDirName={autopf}\Bambuddy
  36. DefaultGroupName={#MyAppName}
  37. DisableProgramGroupPage=yes
  38. LicenseFile=..\..\LICENSE
  39. OutputDir=build\output
  40. OutputBaseFilename=bambuddy-{#MyAppVersion}-windows-x64-setup
  41. Compression=lzma
  42. SolidCompression=yes
  43. WizardStyle=modern
  44. ArchitecturesAllowed=x64compatible
  45. ArchitecturesInstallIn64BitMode=x64compatible
  46. ; Admin required: we register a Windows service and write to ProgramData
  47. PrivilegesRequired=admin
  48. PrivilegesRequiredOverridesAllowed=
  49. ; Bambuddy branding — bambuddy.ico is a multi-resolution .ico (16/32/48/
  50. ; 64/128/256) generated from frontend/public/img/favicon.png; lives next
  51. ; to this .iss so the SourcePath-relative reference works during compile
  52. ; and the [Files] entry stages it into {app} for Add/Remove Programs.
  53. SetupIconFile=bambuddy.ico
  54. UninstallDisplayIcon={app}\bambuddy.ico
  55. ; Don't allow installing to a network drive — service won't start cleanly
  56. DisableDirPage=no
  57. DisableReadyPage=no
  58. ChangesEnvironment=no
  59. CloseApplications=no
  60. [Languages]
  61. Name: "english"; MessagesFile: "compiler:Default.isl"
  62. Name: "german"; MessagesFile: "compiler:Languages\German.isl"
  63. [Tasks]
  64. Name: "desktopicon"; Description: "Create a desktop shortcut"; GroupDescription: "Additional shortcuts:"; Flags: unchecked
  65. Name: "firewallrule"; Description: "Add Windows Firewall rule for Bambuddy (port {#DefaultPort})"; GroupDescription: "Network:"
  66. [Files]
  67. ; Embedded Python (entire tree)
  68. Source: "build\staging\python\*"; DestDir: "{app}\python"; Flags: recursesubdirs ignoreversion
  69. ; Backend + frontend
  70. Source: "build\staging\app\*"; DestDir: "{app}\app"; Flags: recursesubdirs ignoreversion
  71. ; NSSM, ffmpeg, ffprobe
  72. Source: "build\staging\bin\*"; DestDir: "{app}\bin"; Flags: recursesubdirs ignoreversion
  73. ; Service install/uninstall scripts
  74. Source: "build\staging\service\*"; DestDir: "{app}\service"; Flags: recursesubdirs ignoreversion
  75. ; Version stamp
  76. Source: "build\staging\VERSION"; DestDir: "{app}"; Flags: ignoreversion
  77. ; App icon — used by UninstallDisplayIcon (Add/Remove Programs) and the
  78. ; Start Menu / desktop shortcuts. Lives at the install root so the
  79. ; UninstallDisplayIcon path stays stable when the [Files] tree changes.
  80. Source: "bambuddy.ico"; DestDir: "{app}"; Flags: ignoreversion
  81. [Dirs]
  82. ; ProgramData layout — created with permissions LocalSystem can write to
  83. Name: "{commonappdata}\Bambuddy"; Permissions: users-modify
  84. Name: "{commonappdata}\Bambuddy\data"; Permissions: users-modify
  85. Name: "{commonappdata}\Bambuddy\logs"; Permissions: users-modify
  86. [Icons]
  87. Name: "{group}\Open Bambuddy Dashboard"; Filename: "http://localhost:{#DefaultPort}"; IconFilename: "{app}\bambuddy.ico"
  88. Name: "{group}\Bambuddy Logs"; Filename: "{commonappdata}\Bambuddy\logs"
  89. Name: "{group}\Uninstall Bambuddy"; Filename: "{uninstallexe}"
  90. Name: "{commondesktop}\Bambuddy"; Filename: "http://localhost:{#DefaultPort}"; IconFilename: "{app}\bambuddy.ico"; Tasks: desktopicon
  91. [Run]
  92. ; Register and start the Windows service
  93. Filename: "{app}\service\install-service.bat"; Parameters: """{app}"" ""{commonappdata}\Bambuddy"" {#DefaultPort}"; Flags: runhidden waituntilterminated; StatusMsg: "Registering Bambuddy service..."
  94. ; Open Windows Firewall on the dashboard port. We do this only if the
  95. ; user opted in via the firewallrule task — some environments manage
  96. ; firewall centrally and prefer to handle this themselves.
  97. Filename: "netsh.exe"; Parameters: "advfirewall firewall add rule name=""Bambuddy Dashboard"" dir=in action=allow protocol=TCP localport={#DefaultPort}"; Flags: runhidden waituntilterminated; Tasks: firewallrule; StatusMsg: "Adding firewall rule..."
  98. ; Open the dashboard in the user's default browser at the end of install
  99. Filename: "http://localhost:{#DefaultPort}"; Flags: shellexec postinstall nowait skipifsilent; Description: "Open Bambuddy Dashboard"
  100. [UninstallRun]
  101. ; Stop + deregister the service before file removal. RunOnceId makes the
  102. ; entry run-once per uninstall pass (Inno Setup default is to re-run on
  103. ; every pass, which can fire multiple times during upgrade flows).
  104. Filename: "{app}\service\uninstall-service.bat"; Parameters: """{app}"""; Flags: runhidden waituntilterminated; RunOnceId: "StopBambuddyService"
  105. ; Remove the firewall rule (silently — if it doesn't exist, netsh just complains)
  106. Filename: "netsh.exe"; Parameters: "advfirewall firewall delete rule name=""Bambuddy Dashboard"""; Flags: runhidden waituntilterminated; RunOnceId: "RemoveFirewallRule"
  107. [UninstallDelete]
  108. ; Remove install dir contents; leave ProgramData\Bambuddy alone so the
  109. ; user keeps their database + archives. Re-installing on top picks them
  110. ; back up automatically.
  111. Type: filesandordirs; Name: "{app}"
  112. [Code]
  113. // Stop the Bambuddy service BEFORE the [Files] section copies anything,
  114. // so file locks on python.exe / .pyd / nssm.exe release in time for the
  115. // overwrite. Without this, upgrading over a running install fails with
  116. // "permission denied" on every file the service has open.
  117. //
  118. // On a fresh install {app}\bin\nssm.exe doesn't exist yet — FileExists
  119. // guards that path so the hook is a no-op for first-time installers.
  120. // The Sleep gives Windows a beat to finalize the python.exe unload
  121. // before the [Files] step starts grabbing exclusive handles.
  122. //
  123. // The install-service.bat in [Run] does `nssm remove ... confirm` plus
  124. // a fresh `nssm install`, so even if we leave the old service entry in
  125. // place here, the post-install step re-registers it cleanly.
  126. function PrepareToInstall(var NeedsRestart: Boolean): String;
  127. var
  128. ResultCode: Integer;
  129. NssmPath: string;
  130. begin
  131. Result := '';
  132. NeedsRestart := False;
  133. NssmPath := ExpandConstant('{app}\bin\nssm.exe');
  134. if FileExists(NssmPath) then
  135. begin
  136. Log('Stopping Bambuddy service before file copy...');
  137. Exec(NssmPath, 'stop Bambuddy', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
  138. // ResultCode 0 == stopped; non-zero is fine too (already stopped /
  139. // service not registered). The lock we care about is python.exe's,
  140. // and it's released the moment the process exits.
  141. Sleep(1500);
  142. end;
  143. end;
  144. // Pre-install check: refuse to install if port 8000 is already in use by
  145. // something other than a previous Bambuddy install. This catches the
  146. // "I have something else on 8000" case early instead of after install.
  147. function InitializeSetup(): Boolean;
  148. begin
  149. Result := True;
  150. // TODO: optional port-conflict check. Inno Setup doesn't have a
  151. // native socket API; would need a tiny helper exe or a netstat parse.
  152. // Defer to v1.1 — for v1, accept that conflicts surface at first
  153. // service start and the user reads the log.
  154. end;