Files
rippy/deploy/worker-windows/build-exe.ps1
T
Hitonabi 65edf8369e
Ampel / ampel (push) Successful in 28s
feat(worker-windows): Installation nach "Programme", Zielordner frei waehlbar
Commander-Wunsch: nicht ins Benutzerprofil, sondern wie jedes andere Programm
nach C:\Program Files - und selbst waehlbar, mit diesem Standard.

## Was neu ist

- Feld "Installieren nach" mit Knopf "Aendern ..." (Ordner-Dialog). Standard
  ist [Environment]::GetFolderPath("ProgramFiles") + "Rippy Worker" - der
  ECHTE Pfad; deutsche Windows-Versionen zeigen im Explorer "Programme", der
  Pfad heisst trotzdem "Program Files".
- Der Ordner-Dialog liefert den ELTERN-Ordner, "Rippy Worker" haengt der
  Installer selbst an. Sonst koennte die Deinstallation einen fremden Ordner
  mitloeschen - sie macht Remove-Item -Recurse auf das Zielverzeichnis.
- install.ps1 bekommt -InstallDir mit demselben Standard.

## Drei Folgen, die mitbehandelt werden mussten

1. RECHTE. In C:\Program Files darf nur ein Administrator schreiben. Die .exe
   traegt jetzt ein requireAdministrator-Manifest (-requireAdmin in
   build-exe.ps1), fragt also beim Doppelklick EINMAL per UAC - danach stimmen
   die Rechte fuer alles Weitere. Verifiziert: "requireAdministrator" steckt im
   Manifest, "asInvoker" nicht mehr. Zusaetzlich prueft der Installer VOR dem
   Entpacken, ob er dort schreiben darf, und nennt bei Nein die zwei Wege
   (als Administrator starten ODER Ziel ins eigene Profil legen) - statt
   irgendwo tief "Zugriff verweigert" zu produzieren.

2. DAS LOG. tray.py schrieb worker.log NEBEN das Programm. Unter Program Files
   darf ein normaler Benutzer das nicht - der Worker waere beim Starten
   gescheitert, und zwar still. Das Log liegt jetzt in
   %LOCALAPPDATA%\Rippy Worker\worker.log, also da, wo veraenderliche Daten
   hingehoeren. Rueckfall auf das Programmverzeichnis bleibt fuer
   Installationen ins eigene Profil.

3. DER AUTOSTART. Bei einer Installation unter Programme ist es eine
   Installation FUER DIE MASCHINE - der Autostart geht deshalb in den
   Autostart-Ordner aller Benutzer (CommonStartup). Das loest zugleich ein
   Rechte-Problem: erhoeht man ueber ein FREMDES Administratorkonto, waere
   GetFolderPath("Startup") der Ordner dieses Admins, also der falsche. Bei
   einem Ziel im eigenen Profil bleibt es persoenlich. uninstall.ps1 raeumt
   beide Orte ab.

## Geprueft

- Leerzeichen im Pfad: die erzeugte .bat mit cd /d "%~dp0", PATH-Erweiterung
  und relativem Aufruf laeuft aus "C:\...\Rippy Test Ordner" korrekt durch.
- Alle drei .ps1 ASCII-rein und fehlerfrei geparst.
- RippyWorkerSetup.exe neu gebaut (52736 -> 57344 Bytes, Version 1.0.1.0).

UI: Der Copy-Paste-Befehl fuer den CLI-Weg sagt jetzt, dass PowerShell als
Administrator laufen muss, und nennt -InstallDir als Ausweg ohne Adminrechte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 22:20:50 +02:00

69 lines
3.7 KiB
PowerShell

# Baut rippy.ico + RippyWorkerSetup.exe aus install-gui.ps1 (ps2exe).
#
# WANN NEU BAUEN: nur wenn sich install-gui.ps1 (die Installer-Oberflaeche)
# aendert. NICHT bei MakeMKV-/HandBrake-Updates - die .exe holt HandBrake zur
# Laufzeit (GitHub latest) und den Worker-Code live von Rippy, friert also
# keine Versionen ein.
# AUSFUEHREN AUF WINDOWS (eine Windows-.exe kann nicht von Linux gebaut werden):
# powershell -ExecutionPolicy Bypass -File build-exe.ps1
# Danach RippyWorkerSetup.exe committen (die API serviert sie).
$ErrorActionPreference = "Stop"
Add-Type -AssemblyName System.Drawing
Set-Location $PSScriptRoot
$guiSrc = Join-Path $PSScriptRoot "install-gui.ps1"
# 1. Rippy-Disc-Icon 256x256 zeichnen -> PNG -> ICO-Container
$bmp = New-Object System.Drawing.Bitmap 256, 256
$g = [System.Drawing.Graphics]::FromImage($bmp)
$g.SmoothingMode = "AntiAlias"
$g.Clear([System.Drawing.Color]::Transparent)
$g.FillEllipse((New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(99, 102, 241))), 8, 8, 240, 240)
$g.FillEllipse((New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(147, 51, 234))), 40, 40, 176, 176)
$g.FillEllipse([System.Drawing.Brushes]::White, 104, 104, 48, 48)
$ms = New-Object System.IO.MemoryStream
$bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png)
$png = $ms.ToArray()
$icoStream = New-Object System.IO.MemoryStream
$bw = New-Object System.IO.BinaryWriter $icoStream
$bw.Write([UInt16]0); $bw.Write([UInt16]1); $bw.Write([UInt16]1) # ICONDIR
$bw.Write([Byte]0); $bw.Write([Byte]0); $bw.Write([Byte]0); $bw.Write([Byte]0) # 256x256, colors, res
$bw.Write([UInt16]1); $bw.Write([UInt16]32) # planes, bpp
$bw.Write([UInt32]$png.Length); $bw.Write([UInt32]22) # size, offset
$bw.Write($png); $bw.Flush()
[System.IO.File]::WriteAllBytes("$PSScriptRoot\rippy.ico", $icoStream.ToArray())
Write-Host "rippy.ico erzeugt ($($png.Length) Bytes PNG)"
# 2. ps2exe sicherstellen - TLS 1.2 ist der Fix fuer den NuGet-Bootstrap-Fehler
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor 3072
if (-not (Get-Module -ListAvailable ps2exe)) {
Write-Host "Bootstrappe NuGet + PSGallery ..."
try { Get-PackageProvider -Name NuGet -ErrorAction Stop | Out-Null }
catch { Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope CurrentUser | Out-Null }
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted -ErrorAction SilentlyContinue
Write-Host "Installiere ps2exe ..."
Install-Module ps2exe -Scope CurrentUser -Force -AllowClobber
}
Import-Module ps2exe
# 3. Kompilieren (WinForms -> noConsole + STA, Icon eingebettet)
#
# -requireAdmin (seit 25.07.2026): Der Worker wird standardmaessig nach
# "C:\Program Files\Rippy Worker" installiert, und dorthin darf nur ein
# Administrator schreiben. Mit dem Schalter tragt die .exe ein Manifest, das
# Windows beim Doppelklick EINMAL per UAC fragen laesst - danach stimmen die
# Rechte fuer alles Weitere. Ohne ihn liefe der Installer unerhoeht und
# scheiterte beim Anlegen des Ordners; wer das Ziel ins eigene Profil legt,
# braucht die Erhoehung nicht, wird aber trotzdem gefragt (normal fuer einen
# Installer und besser als ein Fehlschlag mitten im Lauf).
Invoke-ps2exe -inputFile $guiSrc -outputFile "$PSScriptRoot\RippyWorkerSetup.exe" `
-iconFile "$PSScriptRoot\rippy.ico" -noConsole -STA -requireAdmin `
-title "Rippy Worker Setup" -product "Rippy" -company "Rippy" -version "1.0.1.0"
if (Test-Path "$PSScriptRoot\RippyWorkerSetup.exe") {
Write-Host "OK: RippyWorkerSetup.exe = $((Get-Item "$PSScriptRoot\RippyWorkerSetup.exe").Length) Bytes"
} else {
Write-Host "FEHLER: keine .exe erzeugt"
}