diff --git a/docs/windows/innosetup-rdp-package-filelist.md b/docs/windows/innosetup-rdp-package-filelist.md index f7b12b9..cc9a9e0 100644 --- a/docs/windows/innosetup-rdp-package-filelist.md +++ b/docs/windows/innosetup-rdp-package-filelist.md @@ -1 +1,7 @@ -windows/installkit/innosetup/innosetup-rdp-package-filelist.md +# Moved + +Документ перенесён в новую структуру install-kit: + +- `windows/installkit/innosetup/innosetup-rdp-package-filelist.md` + +Этот файл оставлен как совместимый указатель, чтобы не ломать существующие ссылки в документации/автоматизации. diff --git a/windows/installkit/innosetup/.gitignore b/windows/installkit/innosetup/.gitignore new file mode 100644 index 0000000..3383cd1 --- /dev/null +++ b/windows/installkit/innosetup/.gitignore @@ -0,0 +1,6 @@ +# Build outputs +/*.exe + +# Offline payload ZIPs should not be committed +/*.zip +/payload/*.zip diff --git a/windows/installkit/innosetup/AWatch-rus-InnoSetup.iss b/windows/installkit/innosetup/AWatch-rus-InnoSetup.iss index b843b56..aaabb72 100644 --- a/windows/installkit/innosetup/AWatch-rus-InnoSetup.iss +++ b/windows/installkit/innosetup/AWatch-rus-InnoSetup.iss @@ -1,7 +1,13 @@ #define MyAppName "AWatch-rus InstallKit" #define MyAppVersion "1.0.0" #define MyAppPublisher "AWatch-rus" -#define MyAppExeName "powershell.exe" + +#define AwDefaultServerHost "10.10.10.13" +#define AwDefaultServerPort "5600" +#define AwDefaultUsers "user1,user2,user3,user4,user5" +#define AwDefaultInstallRoot "C:\\Program Files\\ActivityWatch-Phase2" +#define AwDefaultStateRoot "C:\\ProgramData\\ActivityWatch-Phase2" +#define AwDefaultZipName "activitywatch-v0.13.2-windows-x86_64.zip" [Setup] AppId={{6D6A1F74-0F4F-4A57-B5E3-1C2C2F56C0E9} @@ -14,12 +20,16 @@ OutputDir=. OutputBaseFilename=AWatch-rus-InstallKit Compression=lzma SolidCompression=yes -ArchitecturesInstallIn64BitMode=x64 +ArchitecturesInstallIn64BitMode=x64compatible PrivilegesRequired=admin [Languages] Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl" +[Tasks] +Name: "deploy"; Description: "Запустить деплой после установки"; Flags: checkedonce +Name: "validate"; Description: "Запустить validate-deployment (через -ValidateAfterDeploy)"; Flags: checkedonce + [Files] Source: "..\..\ActivityWatch.Windows.Common.psd1"; DestDir: "{app}\windows"; Flags: ignoreversion Source: "..\..\ActivityWatch.Windows.Common.psm1"; DestDir: "{app}\windows"; Flags: ignoreversion @@ -33,9 +43,169 @@ Source: "..\..\browser-domains-native-collector.ps1"; DestDir: "{app}\windows"; Source: "..\..\dlp-endpoint-signals-collector.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion Source: "..\..\web-category-rules.example.json"; DestDir: "{app}\windows"; Flags: ignoreversion Source: "..\..\dlp-policy.example.json"; DestDir: "{app}\windows"; Flags: ignoreversion -Source: "payload\activitywatch-v0.13.2-windows-x86_64.zip"; DestDir: "{app}\payload"; Flags: ignoreversion skipifsourcedoesntexist +; Offline payload (optional): place ZIP into windows/installkit/innosetup/payload/ before compiling. +Source: "payload\{#AwDefaultZipName}"; DestDir: "{app}\payload"; Flags: ignoreversion skipifsourcedoesntexist Source: "innosetup-rdp-package-filelist.md"; DestDir: "{app}\windows\installkit\innosetup"; Flags: ignoreversion [Run] -Filename: "powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\windows\deploy-ensemble.ps1"""; Flags: runhidden -Filename: "powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\windows\validate-deployment.ps1"""; Flags: runhidden +Filename: "powershell.exe"; Parameters: "{code:GetDeployEnsembleParams}"; Flags: runhidden; Tasks: deploy + +[Code] +var + ServerHostPage: TInputQueryWizardPage; + UsersPage: TInputQueryWizardPage; + OptionsPage: TInputOptionWizardPage; + +function NormalizeUserCsv(const UserCsv: string): string; +var + i: Integer; + s: string; + token: string; +begin + Result := ''; + s := UserCsv; + while True do + begin + i := Pos(',', s); + if i = 0 then + begin + token := Trim(s); + s := ''; + end + else + begin + token := Trim(Copy(s, 1, i - 1)); + Delete(s, 1, i); + end; + + if token <> '' then + begin + if Result <> '' then + Result := Result + ','; + Result := Result + token; + end; + + if s = '' then + Break; + end; +end; + +function BuildUsersPowerShellArg(const UserCsv: string): string; +var + i: Integer; + s: string; + token: string; + quoted: string; +begin + Result := ''; + s := UserCsv; + while True do + begin + i := Pos(',', s); + if i = 0 then + begin + token := Trim(s); + s := ''; + end + else + begin + token := Trim(Copy(s, 1, i - 1)); + Delete(s, 1, i); + end; + + if token <> '' then + begin + quoted := '"' + token + '"'; + if Result <> '' then + Result := Result + ','; + Result := Result + quoted; + end; + + if s = '' then + Break; + end; + if Result <> '' then + Result := '-Users ' + Result; +end; + +function PayloadZipPath: string; +begin + Result := ExpandConstant('{app}\payload\{#AwDefaultZipName}'); +end; + +function HasPayloadZip: Boolean; +begin + Result := FileExists(ExpandConstant('{src}\payload\{#AwDefaultZipName}')); +end; + +procedure InitializeWizard; +begin + ServerHostPage := CreateInputQueryPage( + wpSelectDir, + 'Параметры AW сервера', + 'Укажите сервер ActivityWatch (куда агенты будут отправлять данные).', + 'Если нужно, измените host/port. По умолчанию — наша конфигурация.' + ); + ServerHostPage.Add('ServerHost', False); + ServerHostPage.Add('ServerPort', False); + ServerHostPage.Values[0] := '{#AwDefaultServerHost}'; + ServerHostPage.Values[1] := '{#AwDefaultServerPort}'; + + UsersPage := CreateInputQueryPage( + ServerHostPage.ID, + 'Пользователи (RDP)', + 'Перечень пользователей, для которых разворачиваем агенты.', + 'Введите список через запятую. Пример: user1,user2,user3' + ); + UsersPage.Add('Users (CSV)', False); + UsersPage.Values[0] := '{#AwDefaultUsers}'; + + OptionsPage := CreateInputOptionPage( + UsersPage.ID, + 'Опции деплоя', + 'Выберите опции для установки/валидации.', + '', + False, + False + ); + OptionsPage.Add('Использовать offline payload (встроенный ZIP)'); + OptionsPage.Add('Запустить validate-deployment после деплоя'); + OptionsPage.Values[0] := HasPayloadZip; + OptionsPage.Values[1] := True; +end; + +function GetDeployEnsembleParams(Param: string): string; +var + serverHost: string; + serverPort: string; + usersCsv: string; + usersArg: string; + zipArg: string; + validateArg: string; +begin + serverHost := Trim(ServerHostPage.Values[0]); + serverPort := Trim(ServerHostPage.Values[1]); + usersCsv := NormalizeUserCsv(UsersPage.Values[0]); + + usersArg := BuildUsersPowerShellArg(usersCsv); + if usersArg = '' then + RaiseException('Users list is empty.'); + + zipArg := ''; + if OptionsPage.Values[0] then + zipArg := ' -PackageZipPath "' + PayloadZipPath + '"'; + + validateArg := ''; + if OptionsPage.Values[1] and WizardIsTaskSelected('validate') then + validateArg := ' -ValidateAfterDeploy'; + + Result := + '-NoProfile -ExecutionPolicy Bypass -File "' + ExpandConstant('{app}\windows\deploy-ensemble.ps1') + '"' + + ' -ServerHost "' + serverHost + '"' + + ' -ServerPort ' + serverPort + + ' ' + usersArg + + zipArg + + ' -InstallRoot "{#AwDefaultInstallRoot}"' + + ' -StateRoot "{#AwDefaultStateRoot}"' + + validateArg; +end; diff --git a/windows/installkit/innosetup/BUILD.md b/windows/installkit/innosetup/BUILD.md new file mode 100644 index 0000000..5a96501 --- /dev/null +++ b/windows/installkit/innosetup/BUILD.md @@ -0,0 +1,35 @@ +# Build (Inno Setup) + +## Prerequisites + +- Windows machine with Inno Setup installed (`ISCC.exe` available). + +## Offline vs Online payload + +- **Offline (recommended for closed networks)**: put `activitywatch-v0.13.2-windows-x86_64.zip` into `payload\`. +- **Online**: leave `payload\` empty; the deploy script will download the ZIP from GitHub Releases. + +## Compile + +From this folder: + +```bat +iscc AWatch-rus-InnoSetup.iss +``` + +The resulting installer `AWatch-rus-InstallKit.exe` is written to the same directory (by `OutputDir=.`). + +## Compile from Linux (Wine) + +```sh +./build_with_wine.sh +``` + +## Install-time parameters + +The installer wizard asks for: + +- `ServerHost` / `ServerPort` (defaults to our AW server `10.10.10.13:5600`) +- `Users` (CSV) +- Whether to use offline payload (auto-enabled when the ZIP exists at compile time) +- Whether to validate after deploy (`-ValidateAfterDeploy`, report written to `C:\ProgramData\ActivityWatch-Phase2\ensemble-report-*.json`) diff --git a/windows/installkit/innosetup/build_with_wine.sh b/windows/installkit/innosetup/build_with_wine.sh new file mode 100644 index 0000000..af2a00f --- /dev/null +++ b/windows/installkit/innosetup/build_with_wine.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -euo pipefail + +KIT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +WINEPREFIX_DEFAULT="${HOME}/.wine-aw-inno" +WINEPREFIX="${WINEPREFIX:-$WINEPREFIX_DEFAULT}" + +IS_EXE="${IS_EXE:-/tmp/innosetup.exe}" +ISCC_WIN='C:\InnoSetup\ISCC.exe' + +cd "$KIT_DIR" + +mkdir -p payload + +ZIP_NAME="activitywatch-v0.13.2-windows-x86_64.zip" + +# If someone dropped the ZIP in the kit root, stage it into payload/. +if [[ -f "$ZIP_NAME" && ! -f "payload/$ZIP_NAME" ]]; then + cp -f "$ZIP_NAME" "payload/$ZIP_NAME" +fi + +export WINEPREFIX +export WINEDEBUG="${WINEDEBUG:--all}" + +if [[ ! -f "${WINEPREFIX}/drive_c/InnoSetup/ISCC.exe" ]]; then + mkdir -p "$WINEPREFIX" + if [[ ! -f "$IS_EXE" ]]; then + curl -fsSL -o "$IS_EXE" https://jrsoftware.org/download.php/is.exe + fi + wineboot -u + wine "$IS_EXE" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- /DIR="C:\InnoSetup" +fi + +rm -f AWatch-rus-InstallKit.exe +wine "$ISCC_WIN" "AWatch-rus-InnoSetup.iss" + +ls -la AWatch-rus-InstallKit.exe +sha256sum AWatch-rus-InstallKit.exe diff --git a/windows/installkit/innosetup/innosetup-rdp-package-filelist.md b/windows/installkit/innosetup/innosetup-rdp-package-filelist.md index 7027e49..4b36595 100644 --- a/windows/installkit/innosetup/innosetup-rdp-package-filelist.md +++ b/windows/installkit/innosetup/innosetup-rdp-package-filelist.md @@ -42,10 +42,12 @@ ## 2) Бинарный payload ActivityWatch -Нужен один из двух режимов: +Поддерживаются оба режима: -- **Online**: скрипты скачивают `activitywatch--windows-x86_64.zip` из GitHub Releases. -- **Offline**: ZIP добавляется в пакет (например `payload\activitywatch-v0.13.2-windows-x86_64.zip`) и передаётся через `-PackageZipPath`. +- **Online**: ZIP скачивается из GitHub Releases. +- **Offline**: ZIP кладётся в installer (`payload\activitywatch-v0.13.2-windows-x86_64.zip`) и передаётся в deploy через `-PackageZipPath`. + +Для нашей закрытой среды обычно используется **offline-режим**. ## 3) Что НЕ включать в installer как статические файлы @@ -83,7 +85,9 @@ ## 6) Контроль перед сборкой .iss 1. Все файлы из раздела 1 присутствуют. -2. Выбран режим payload: online или offline. -3. Для offline-режима ZIP действительно лежит в `payload\`. -4. В .iss есть запуск нужного deploy-сценария (`deploy-ensemble.ps1` или `deploy-domain-users.ps1`). -5. После установки запускается `validate-deployment.ps1` с сохранением JSON-отчёта. +2. В .iss не осталось вызова `deploy-ensemble.ps1` без параметров: нужны `-ServerHost` и `-Users`. +3. Для **Phase2** используются пути: + - `InstallRoot = C:\Program Files\ActivityWatch-Phase2` + - `StateRoot = C:\ProgramData\ActivityWatch-Phase2` +4. Для offline-режима ZIP лежит в `windows/installkit/innosetup/payload/` (имя: `activitywatch-v0.13.2-windows-x86_64.zip`). +5. Для проверки используется `-ValidateAfterDeploy` (отчёт `ensemble-report-*.json` пишется в `C:\ProgramData\ActivityWatch-Phase2\`). diff --git a/windows/installkit/innosetup/payload/README.md b/windows/installkit/innosetup/payload/README.md new file mode 100644 index 0000000..659b990 --- /dev/null +++ b/windows/installkit/innosetup/payload/README.md @@ -0,0 +1,6 @@ +Place ActivityWatch ZIP here for offline installer builds. + +Expected filename: +- `activitywatch-v0.13.2-windows-x86_64.zip` + +If the ZIP is absent, the installer can still be built (online mode), but the deploy step will download the payload from GitHub Releases.