add: Installer funktionen mit auto Update check
This commit is contained in:
1 parent
102b485794
commit
1fb6444444
8 files changed
+422
-10
No files matched your search
@@ -61,3 +61,38 @@ Excel-Datei → excel_reader → MonthlyAttendance → pdf_filler → PDF-Datei
|
||||
| Numerisch | DD.MM.YYYY | X | Wert (dt. Format) | "6" | "1" |
|
||||
| "K"/"KK"/etc| DD.MM.YYYY | Code | leer | leer | "0" |
|
||||
| Leer | (überspringen) | — | — | — | — |
|
||||
|
||||
---
|
||||
|
||||
## Windows-Installer (Inno Setup)
|
||||
|
||||
### Ziel
|
||||
Installer-EXE erstellen, die:
|
||||
- Von einem Windows SMB-Share aus gestartet werden kann (self-contained .exe)
|
||||
- Das Programm lokal unter `%ProgramFiles%\AnwesenheitPDF\` installiert
|
||||
- Einen Startmenü-Eintrag anlegt (optional: Desktop-Verknüpfung)
|
||||
- Einen Uninstaller registriert (Programme und Features)
|
||||
|
||||
### Tool: Inno Setup 6
|
||||
- Free, open-source, weit verbreitet
|
||||
- Erzeugt eine einzelne selbstextrahierende .exe (ideal für SMB-Share)
|
||||
- Unterstützt German.isl (deutschsprachiger Wizard)
|
||||
- ISCC.exe (Compiler) muss auf Build-Maschine installiert sein
|
||||
- Installation: `winget install --id JRSoftware.InnoSetup -e -s winget -i`
|
||||
|
||||
### Dateien
|
||||
- `installer\AnwesenheitPDF.iss` — Inno Setup Script
|
||||
- `build.bat` — um Installer-Schritt erweitert (ruft ISCC auf)
|
||||
- Ausgabe: `dist\AnwesenheitPDF-Setup-x.y.z.exe`
|
||||
|
||||
### Ablauf build.bat (neu: Schritt 4)
|
||||
1. pip install
|
||||
2. update_version.py (liest Version aus config.json)
|
||||
3. PyInstaller → dist\AnwesenheitPDF\
|
||||
4. Version aus config.json extrahieren → ISCC aufrufen → dist\AnwesenheitPDF-Setup-x.y.z.exe
|
||||
|
||||
### Install-Ziel
|
||||
- `{autopf}\AnwesenheitPDF\` (= Program Files, UAC-geschützt)
|
||||
- Requires admin (PrivilegesRequired=admin)
|
||||
- Startmenü: `{group}\AnwesenheitPDF`
|
||||
- Optional Desktop-Verknüpfung (Checkbox im Wizard)
|
||||
@@ -13,3 +13,4 @@ tests/fixtures/**/*.xlsx
|
||||
tests/fixtures/**/*.xlsm
|
||||
tests/fixtures/**/reference/*.pdf
|
||||
tests/fixtures/**/diff/
|
||||
*.log
|
||||
@@ -198,3 +198,48 @@ Das Programm prüft vor jeder Generierung:
|
||||
7. Headerzeile mit `Name, Vorname` gefunden
|
||||
8. Tagesspalten ab Spaltenindex 9 vorhanden
|
||||
9. PDF-Template unter `template/sab.pdf` erreichbar
|
||||
|
||||
---
|
||||
|
||||
## Windows-Installer erstellen
|
||||
|
||||
Der Build-Prozess erzeugt neben dem Programm auch einen Windows-Installer (`.exe`), der vom SMB-Netzlaufwerk gestartet werden kann.
|
||||
|
||||
### Voraussetzung: Inno Setup 6
|
||||
|
||||
Inno Setup 6 muss auf der Build-Maschine installiert sein. Installation über `winget`:
|
||||
|
||||
```bat
|
||||
winget install --id JRSoftware.InnoSetup -e -s winget -i
|
||||
```
|
||||
|
||||
Alternativ manueller Download: <https://jrsoftware.org/isinfo.php>
|
||||
|
||||
### Installer bauen
|
||||
|
||||
```bat
|
||||
build.bat
|
||||
```
|
||||
|
||||
`build.bat` führt alle vier Schritte automatisch aus:
|
||||
|
||||
1. Abhängigkeiten installieren (`pip install`)
|
||||
2. Version aktualisieren (`update_version.py`)
|
||||
3. Programm packen (`PyInstaller` → `dist\AnwesenheitPDF\`)
|
||||
4. Installer kompilieren (`ISCC.exe` → `dist\AnwesenheitPDF-Setup-x.y.z.exe`)
|
||||
|
||||
Ist Inno Setup **nicht** installiert, wird Schritt 4 mit einer Warnung übersprungen — der PyInstaller-Output in `dist\AnwesenheitPDF\` ist trotzdem nutzbar.
|
||||
|
||||
### Installer verteilen
|
||||
|
||||
Die fertige Datei `dist\AnwesenheitPDF-Setup-x.y.z.exe` auf das SMB-Netzlaufwerk kopieren. Von dort kann sie direkt gestartet werden — ohne vorherige lokale Kopie.
|
||||
|
||||
### Was der Installer macht
|
||||
|
||||
| Aktion | Details |
|
||||
|---|---|
|
||||
| Installationspfad | `%ProgramFiles%\AnwesenheitPDF\` (Admin erforderlich) |
|
||||
| Startmenü-Eintrag | `AnwesenheitPDF` |
|
||||
| Desktop-Verknüpfung | Optional (Checkbox im Wizard, Standard: deaktiviert) |
|
||||
| Uninstaller | Registriert unter *Programme und Features* |
|
||||
| Windows-Version | Windows 10 oder höher |
|
||||
@@ -1,12 +1,14 @@
|
||||
@echo off
|
||||
REM Build-Script fuer AnwesenheitPDF.exe
|
||||
REM Build-Script fuer AnwesenheitPDF.exe + Windows-Installer
|
||||
REM
|
||||
REM Ergebnis:
|
||||
REM build/ - temporaere PyInstaller-Artefakte
|
||||
REM dist/ - fertiges Programmverzeichnis (AnwesenheitPDF.exe + alle Abhaengigkeiten)
|
||||
REM + AnwesenheitPDF-Setup-x.y.z.exe (Windows-Installer)
|
||||
REM
|
||||
REM Voraussetzungen:
|
||||
REM pip install -r requirements-dev.txt
|
||||
REM Inno Setup 6 installiert (https://jrsoftware.org/isinfo.php)
|
||||
|
||||
cd /d "%~dp0"
|
||||
|
||||
@@ -14,7 +16,7 @@ echo.
|
||||
echo === AnwesenheitPDF Build ===
|
||||
echo.
|
||||
|
||||
echo [1/3] Abhaengigkeiten installieren...
|
||||
echo [1/4] Abhaengigkeiten installieren...
|
||||
pip install -r requirements.txt --quiet && pip install -r requirements-dev.txt --quiet
|
||||
if %ERRORLEVEL% neq 0 (
|
||||
echo [FEHLER] pip install fehlgeschlagen.
|
||||
@@ -22,7 +24,7 @@ if %ERRORLEVEL% neq 0 (
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [2/3] Version aktualisieren...
|
||||
echo [2/4] Version aktualisieren...
|
||||
python update_version.py
|
||||
if %ERRORLEVEL% neq 0 (
|
||||
echo [FEHLER] Version-Update fehlgeschlagen.
|
||||
@@ -30,7 +32,7 @@ if %ERRORLEVEL% neq 0 (
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [3/3] Build starten...
|
||||
echo [3/4] Build starten...
|
||||
echo.
|
||||
|
||||
python -m PyInstaller ^
|
||||
@@ -59,11 +61,104 @@ if not exist "dist\AnwesenheitPDF\template" mkdir "dist\AnwesenheitPDF\template"
|
||||
if not exist "dist\AnwesenheitPDF\output" mkdir "dist\AnwesenheitPDF\output"
|
||||
if exist "template\sab.pdf" copy /Y "template\sab.pdf" "dist\AnwesenheitPDF\template\sab.pdf" >nul
|
||||
|
||||
echo.
|
||||
echo [4/4] Windows-Installer erstellen...
|
||||
|
||||
REM Version aus config.json lesen (Format: "x.y.z+hash" -> nur "x.y.z" verwenden)
|
||||
for /f "tokens=2 delims=:," %%v in ('findstr /c:"\"version\"" config.json') do (
|
||||
set RAW_VERSION=%%v
|
||||
)
|
||||
REM Fuehrende/nachfolgende Leerzeichen und Anfuehrungszeichen entfernen, Hash abschneiden
|
||||
set RAW_VERSION=%RAW_VERSION: =%
|
||||
set RAW_VERSION=%RAW_VERSION:"=%
|
||||
for /f "tokens=1 delims=+" %%c in ("%RAW_VERSION%") do set APP_VERSION=%%c
|
||||
|
||||
echo Version: %APP_VERSION%
|
||||
|
||||
REM Inno Setup Compiler suchen (Standard-Installationspfade)
|
||||
set ISCC_PATH=
|
||||
if exist "%ProgramFiles(x86)%\Inno Setup 6\ISCC.exe" (
|
||||
set "ISCC_PATH=%ProgramFiles(x86)%\Inno Setup 6\ISCC.exe"
|
||||
) else if exist "%ProgramFiles%\Inno Setup 6\ISCC.exe" (
|
||||
set "ISCC_PATH=%ProgramFiles%\Inno Setup 6\ISCC.exe"
|
||||
) else if exist "%LOCALAPPDATA%\Programs\Inno Setup 6\ISCC.exe" (
|
||||
set "ISCC_PATH=%LOCALAPPDATA%\Programs\Inno Setup 6\ISCC.exe"
|
||||
) else (
|
||||
for /f "delims=" %%i in ('where ISCC.exe 2^>nul') do set "ISCC_PATH=%%i"
|
||||
)
|
||||
|
||||
if "%ISCC_PATH%"=="" (
|
||||
echo.
|
||||
echo [WARNUNG] Inno Setup 6 nicht gefunden. Installer wird NICHT erstellt.
|
||||
echo Download: https://jrsoftware.org/isinfo.php
|
||||
echo Nach der Installation Inno Setup 6 neu starten und build.bat erneut ausfuehren.
|
||||
echo.
|
||||
goto build_done
|
||||
)
|
||||
|
||||
"%ISCC_PATH%" /DMyAppVersion=%APP_VERSION% installer\AnwesenheitPDF.iss > build_iscc.log 2>&1
|
||||
|
||||
if %ERRORLEVEL% neq 0 (
|
||||
echo.
|
||||
echo [FEHLER] Installer-Erstellung fehlgeschlagen.
|
||||
echo.
|
||||
type build_iscc.log
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo [OK] Installer erstellt: dist\AnwesenheitPDF-Setup-%APP_VERSION%.exe
|
||||
|
||||
echo.
|
||||
echo [5/5] Installer zu update_check_path deployen...
|
||||
|
||||
REM update_check_path aus config.json auslesen
|
||||
for /f "tokens=2 delims=:," %%d in ('findstr /c:"\"update_check_path\"" config.json') do (
|
||||
set UPDATE_PATH=%%d
|
||||
)
|
||||
REM Leerzeichen und Anfuehrungszeichen entfernen
|
||||
set UPDATE_PATH=%UPDATE_PATH: =%
|
||||
set UPDATE_PATH=%UPDATE_PATH:"=%
|
||||
|
||||
if "%UPDATE_PATH%"=="" (
|
||||
echo [WARNUNG] update_check_path nicht in config.json gefunden. Deployment uebersprungen.
|
||||
goto build_done
|
||||
)
|
||||
|
||||
REM Zielverzeichnis pruefen und ggf. erstellen
|
||||
if not exist "%UPDATE_PATH%" (
|
||||
echo [INFO] Erstelle Zielverzeichnis: %UPDATE_PATH%
|
||||
mkdir "%UPDATE_PATH%"
|
||||
if %ERRORLEVEL% neq 0 (
|
||||
echo [WARNUNG] Konnte Zielverzeichnis nicht erstellen. Deployment uebersprungen.
|
||||
goto build_done
|
||||
)
|
||||
)
|
||||
|
||||
REM Neuen Installer kopieren
|
||||
echo [INFO] Kopiere Installer nach: %UPDATE_PATH%
|
||||
copy /Y "dist\AnwesenheitPDF-Setup-%APP_VERSION%.exe" "%UPDATE_PATH%\AnwesenheitPDF-Setup-%APP_VERSION%.exe" >nul
|
||||
|
||||
if %ERRORLEVEL% neq 0 (
|
||||
echo [WARNUNG] Installer-Deployment fehlgeschlagen (Schreibrechte?).
|
||||
goto build_done
|
||||
)
|
||||
|
||||
echo [OK] Installer deployed zu: %UPDATE_PATH%\AnwesenheitPDF-Setup-%APP_VERSION%.exe
|
||||
|
||||
:build_done
|
||||
echo.
|
||||
echo [OK] Build abgeschlossen.
|
||||
echo Programm: dist\AnwesenheitPDF\AnwesenheitPDF.exe
|
||||
echo Template: dist\AnwesenheitPDF\template\sab.pdf
|
||||
echo Output: dist\AnwesenheitPDF\output
|
||||
echo Programm: dist\AnwesenheitPDF\AnwesenheitPDF.exe
|
||||
echo Template: dist\AnwesenheitPDF\template\sab.pdf
|
||||
echo Output: dist\AnwesenheitPDF\output
|
||||
if not "%ISCC_PATH%"=="" (
|
||||
echo Installer: dist\AnwesenheitPDF-Setup-%APP_VERSION%.exe
|
||||
)
|
||||
if not "%UPDATE_PATH%"=="" (
|
||||
echo Deployed: %UPDATE_PATH%\AnwesenheitPDF-Setup-%APP_VERSION%.exe
|
||||
)
|
||||
echo.
|
||||
echo ... Programm wird gestartet ...
|
||||
start "" "dist\AnwesenheitPDF\AnwesenheitPDF.exe"
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.1+250a473",
|
||||
"version": "1.0.8+47220f9",
|
||||
"antragsnummer": "100740439",
|
||||
"ort": "Dresden",
|
||||
"template_pdf": "template/sab.pdf",
|
||||
@@ -42,5 +42,6 @@
|
||||
"pauschale_present_value": "1",
|
||||
"pdf_use_display_values": true,
|
||||
"pdf_need_appearances": false,
|
||||
"excel_network_source": "J:\\Fachbereiche\\BO\\Produktionsschule\\Maßnahmeunterlagen\\30_Teilnehmende\\01_Anwesenheit\\Anwesenheitsliste\\Anwesenheitsliste 2026.xlsx"
|
||||
"excel_network_source": "J:\\Fachbereiche\\BO\\Produktionsschule\\Maßnahmeunterlagen\\30_Teilnehmende\\01_Anwesenheit\\Anwesenheitsliste\\Anwesenheitsliste 2026.xlsx",
|
||||
"update_check_path": "j:\\Fachbereiche\\BO\\Produktionsschule\\Maßnahmeunterlagen\\30_Teilnehmende\\02_Abrechnung Aufwand und Fahrtgeld\\Automatisierung"
|
||||
}
|
||||
@@ -2,13 +2,15 @@
|
||||
# Ergebnis: dist/AnwesenheitPDF/AnwesenheitPDF.exe + alle Abhaengigkeiten
|
||||
# Build-Artefakte: build/ (temporaer, nicht committen)
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import threading
|
||||
from datetime import date, datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
import customtkinter as ctk
|
||||
import tkinter as tk
|
||||
@@ -99,6 +101,78 @@ def _count_output_pdfs(config: Dict[str, Any]) -> int:
|
||||
return len(list(out_dir.glob("*.pdf")))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Update-check helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_UPDATE_CHECK_FILE = _runtime_dir() / "update_check.json"
|
||||
_INSTALLER_PATTERN = re.compile(r"^AnwesenheitPDF-Setup-(\d+\.\d+\.\d+)\.exe$", re.IGNORECASE)
|
||||
|
||||
|
||||
def _parse_semver(version_str: str) -> Tuple[int, int, int]:
|
||||
"""Parse semantic version string, ignoring build metadata after '+'."""
|
||||
base = version_str.split("+")[0].strip()
|
||||
match = re.match(r"^(\d+)\.(\d+)\.(\d+)$", base)
|
||||
if not match:
|
||||
return (0, 0, 0)
|
||||
return int(match.group(1)), int(match.group(2)), int(match.group(3))
|
||||
|
||||
|
||||
def _should_check_update() -> bool:
|
||||
"""Return True if no check has been recorded for today."""
|
||||
try:
|
||||
if _UPDATE_CHECK_FILE.exists():
|
||||
with open(_UPDATE_CHECK_FILE, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
return data.get("last_check") != date.today().isoformat()
|
||||
except Exception:
|
||||
pass
|
||||
return True
|
||||
|
||||
|
||||
def _record_update_check() -> None:
|
||||
"""Persist today's date as the last check timestamp."""
|
||||
try:
|
||||
with open(_UPDATE_CHECK_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump({"last_check": date.today().isoformat()}, f)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _find_latest_installer(config: Dict[str, Any]) -> Optional[Tuple[str, Path]]:
|
||||
"""Scan the configured SMB update path for the newest installer.
|
||||
|
||||
Returns (version_str, installer_path) if a newer version exists, else None.
|
||||
"""
|
||||
update_path_str = str(config.get("update_check_path", "")).strip()
|
||||
if not update_path_str:
|
||||
return None
|
||||
|
||||
update_dir = Path(update_path_str)
|
||||
if not update_dir.exists():
|
||||
return None
|
||||
|
||||
current_ver = _parse_semver(str(config.get("version", "0.0.0")))
|
||||
best_ver = current_ver
|
||||
best_file: Optional[Path] = None
|
||||
best_ver_str: Optional[str] = None
|
||||
|
||||
for f in update_dir.glob("AnwesenheitPDF-Setup-*.exe"):
|
||||
m = _INSTALLER_PATTERN.match(f.name)
|
||||
if not m:
|
||||
continue
|
||||
ver_str = m.group(1)
|
||||
ver = _parse_semver(ver_str)
|
||||
if ver > best_ver:
|
||||
best_ver = ver
|
||||
best_file = f
|
||||
best_ver_str = ver_str
|
||||
|
||||
if best_file and best_ver_str:
|
||||
return (best_ver_str, best_file)
|
||||
return None
|
||||
|
||||
|
||||
def _build_month_keys(config: Dict[str, Any]) -> List[str]:
|
||||
"""Return deduplicated month keys from config (preserves insertion order)."""
|
||||
seen: set = set()
|
||||
@@ -178,6 +252,7 @@ class AnwesenheitApp(ctk.CTk):
|
||||
self._tooltip_label: Optional[tk.Label] = None
|
||||
|
||||
# Build UI sections
|
||||
self._build_update_banner()
|
||||
self._build_input_section()
|
||||
self._build_button_section()
|
||||
self._build_preview_section()
|
||||
@@ -185,11 +260,68 @@ class AnwesenheitApp(ctk.CTk):
|
||||
|
||||
# Auto-sync after event loop starts
|
||||
self.after(100, self._start_initial_sync)
|
||||
# Daily update check
|
||||
if _should_check_update():
|
||||
self.after(200, self._start_update_check)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# UI builders
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _build_update_banner(self) -> None:
|
||||
"""Create the update-available banner (hidden until an update is found)."""
|
||||
self._update_banner = ctk.CTkFrame(self, fg_color="#854D0E")
|
||||
# Banner is NOT packed here — only shown when an update is detected
|
||||
self._update_banner_label = ctk.CTkLabel(
|
||||
self._update_banner,
|
||||
text="",
|
||||
text_color="#FEF9C3",
|
||||
font=ctk.CTkFont(weight="bold"),
|
||||
anchor="w",
|
||||
)
|
||||
self._update_banner_label.pack(side="left", padx=12, pady=6, fill="x", expand=True)
|
||||
self._update_banner_btn = ctk.CTkButton(
|
||||
self._update_banner,
|
||||
text="Installieren",
|
||||
width=110,
|
||||
height=28,
|
||||
fg_color="#CA8A04",
|
||||
hover_color="#A16207",
|
||||
text_color="white",
|
||||
command=self._open_update_folder,
|
||||
)
|
||||
self._update_banner_btn.pack(side="right", padx=(0, 12), pady=6)
|
||||
self._update_installer_path: Optional[Path] = None
|
||||
|
||||
def _show_update_banner(self, version: str, installer: Path) -> None:
|
||||
"""Display the update banner with the new version info."""
|
||||
self._update_installer_path = installer
|
||||
current = _CONFIG.get("version", "?").split("+")[0]
|
||||
self._update_banner_label.configure(
|
||||
text=f"Update verfügbar: v{current} → v{version} "
|
||||
f"({installer.name})"
|
||||
)
|
||||
# Insert banner above everything else
|
||||
self._update_banner.pack(fill="x", padx=16, pady=(8, 0), before=self.winfo_children()[1])
|
||||
|
||||
def _open_update_folder(self) -> None:
|
||||
"""Open the installer directory in Explorer."""
|
||||
if self._update_installer_path and self._update_installer_path.parent.exists():
|
||||
os.startfile(str(self._update_installer_path.parent))
|
||||
|
||||
def _start_update_check(self) -> None:
|
||||
threading.Thread(target=self._run_update_check, daemon=True).start()
|
||||
|
||||
def _run_update_check(self) -> None:
|
||||
try:
|
||||
result = _find_latest_installer(_CONFIG)
|
||||
except Exception:
|
||||
result = None
|
||||
_record_update_check()
|
||||
if result:
|
||||
version, installer = result
|
||||
self.after(0, self._show_update_banner, version, installer)
|
||||
|
||||
def _build_input_section(self) -> None:
|
||||
frame = ctk.CTkFrame(self)
|
||||
frame.pack(fill="x", padx=16, pady=(16, 0))
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
; Inno Setup Script fuer AnwesenheitPDF
|
||||
; Compiler: Inno Setup 6.x (https://jrsoftware.org/isinfo.php)
|
||||
;
|
||||
; Aufruf durch build.bat:
|
||||
; iscc.exe /DMyAppVersion=1.0.1 installer\AnwesenheitPDF.iss
|
||||
;
|
||||
; Ausgabe: dist\AnwesenheitPDF-Setup-{version}.exe
|
||||
|
||||
#ifndef MyAppVersion
|
||||
#define MyAppVersion "0.0.0"
|
||||
#endif
|
||||
|
||||
#define MyAppName "AnwesenheitPDF"
|
||||
#define MyAppPublisher "SAB Anwesenheitslisten"
|
||||
#define MyAppExeName "AnwesenheitPDF.exe"
|
||||
#define MyAppID "{{A3F2C1D7-84BE-4E9A-B5D0-2C7F3A1E9B46}"
|
||||
|
||||
[Setup]
|
||||
; Eindeutige App-ID – niemals aendern (sonst gelten Updates als Neuinstallation)
|
||||
AppId={#MyAppID}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppVerName={#MyAppName} {#MyAppVersion}
|
||||
AppPublisher={#MyAppPublisher}
|
||||
AppComments=Anwesenheitslisten aus Excel-Daten als PDF generieren
|
||||
|
||||
; Installations-Zielverzeichnis (Programme-Ordner)
|
||||
DefaultDirName={autopf}\{#MyAppName}
|
||||
DefaultGroupName={#MyAppName}
|
||||
DisableProgramGroupPage=yes
|
||||
|
||||
; Installer-Ausgabe
|
||||
OutputDir=..\dist
|
||||
OutputBaseFilename=AnwesenheitPDF-Setup-{#MyAppVersion}
|
||||
|
||||
; Komprimierung
|
||||
Compression=lzma2/ultra64
|
||||
SolidCompression=yes
|
||||
LZMAUseSeparateProcess=yes
|
||||
|
||||
; Erscheinungsbild
|
||||
WizardStyle=modern
|
||||
SetupIconFile=..\assets\icon.ico
|
||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||
|
||||
; Berechtigungen: Admin erforderlich fuer Installation in Programme-Ordner
|
||||
PrivilegesRequired=admin
|
||||
PrivilegesRequiredOverridesAllowed=dialog
|
||||
|
||||
; Mindest-Windows-Version: Windows 10 (10.0)
|
||||
MinVersion=10.0
|
||||
|
||||
; Installer kann direkt vom Netzlaufwerk (SMB-Share) ausgefuehrt werden
|
||||
; (kein lokales Entpacken des Installers noetig)
|
||||
AllowNetworkDrive=yes
|
||||
AllowUNCPath=yes
|
||||
|
||||
; Versionsinformation fuer die EXE-Eigenschaften
|
||||
VersionInfoVersion={#MyAppVersion}
|
||||
VersionInfoCompany={#MyAppPublisher}
|
||||
VersionInfoDescription={#MyAppName} Setup
|
||||
VersionInfoProductName={#MyAppName}
|
||||
VersionInfoProductVersion={#MyAppVersion}
|
||||
|
||||
[Languages]
|
||||
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
|
||||
|
||||
[Tasks]
|
||||
Name: "startmenuicon"; \
|
||||
Description: "Startmenü-Einträge erstellen"; \
|
||||
GroupDescription: "Startmenü:"
|
||||
|
||||
[Files]
|
||||
; Gesamten PyInstaller-Output in das Installationsverzeichnis kopieren
|
||||
Source: "..\dist\AnwesenheitPDF\*"; \
|
||||
DestDir: "{app}"; \
|
||||
Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
|
||||
[Icons]
|
||||
; Startmenü-Eintrag (nur wenn Task ausgewaehlt)
|
||||
Name: "{group}\{#MyAppName}"; \
|
||||
Filename: "{app}\{#MyAppExeName}"; \
|
||||
Comment: "Anwesenheitslisten als PDF generieren"; \
|
||||
Tasks: startmenuicon
|
||||
|
||||
; Startmenü: Uninstaller (nur wenn Task ausgewaehlt)
|
||||
Name: "{group}\{#MyAppName} deinstallieren"; \
|
||||
Filename: "{uninstallexe}"; \
|
||||
Tasks: startmenuicon
|
||||
|
||||
[Run]
|
||||
; Optionaler Start nach der Installation
|
||||
Filename: "{app}\{#MyAppExeName}"; \
|
||||
Description: "{#MyAppName} jetzt starten"; \
|
||||
Flags: nowait postinstall skipifsilent
|
||||
|
||||
[UninstallDelete]
|
||||
; Beim Deinstallieren: nur generierte Dateien loeschen, keine Nutzerdaten
|
||||
Type: files; Name: "{app}\*.log"
|
||||
@@ -100,6 +100,10 @@
|
||||
"excel_network_source": {
|
||||
"type": "string",
|
||||
"description": "Optionaler SMB- oder Dateipfad zur Excel-Datei, die beim GUI-Start nach input/ kopiert und bei Bedarf aktualisiert wird"
|
||||
},
|
||||
"update_check_path": {
|
||||
"type": "string",
|
||||
"description": "SMB-Pfad zum Verzeichnis mit Installer-Dateien (AnwesenheitPDF-Setup-x.y.z.exe) fuer automatische Update-Pruefung"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user