Bug rapporté : après update client vers 1.0.9, un opérateur ne voyait qu'UNE
ligne alors que le manifest en contenait deux au même numéro. Root cause :
mon refactor v1.0.8 keyait les rows par folder name résolu via
GetInstallFolderName(). Sur les manifests existants (où l'opérateur n'avait
pas encore migré vers un installFolderTemplate distinct par channel), les
deux entries résolvent au même dossier « PROSERVE v1.5.4.32 » — le dico
TryAdd droppait la seconde silencieusement (juste un log warn).
Fix : row identity passe sur l'Id de l'entrée manifest (unique par entry,
auto-généré server-side depuis longtemps via generate_entry_id()). Le folder
name reste utilisé pour le matching installed ↔ remote quand l'entryId
manque (installs d'avant v1.0.8 qui n'ont pas encore été re-installés).
Bénéfices :
• Les deux entries s'affichent MÊME si elles partagent un
installFolderTemplate. L'install guard côté client bloquera l'écrasement
au moment de l'install avec le message clair habituel.
• Migration transparente : les installs existants continuent d'être matchés
par folder name tant qu'ils n'ont pas d'EntryId dans leur meta. Au
ré-install, le meta reçoit son EntryId et le matching devient canonique.
Détails :
── Model ─────────────────────────────────────────────────────────────
• InstalledVersion : nouveau champ optionnel EntryId (default null pour la
rétro-compat des call sites existants).
── Registry ──────────────────────────────────────────────────────────
• Scan() populate EntryId via TryReadEntryId(dir). null si le fichier meta
n'existe pas ou si la clé est absente (install antérieur à v1.0.8).
── MainViewModel.RebuildList ─────────────────────────────────────────
• remoteByRowKey : keyé par Id de l'entry (fallback folder name si le
manifest est très vieux et n'a pas d'id).
• installedByRowKey : keyé par EntryId lu du meta ; fallback = folder name
; fallback ultime = héritage de l'Id d'un remote match si un install
legacy pointe vers un remote qui, lui, a un Id.
• Tri VersionOrder : lookup version + isBeta par rowKey via deux dicos
rawByRowKey/installedByRowKey (au lieu de folder name).
── VersionRowViewModel ───────────────────────────────────────────────
• RowKey : priorité (Remote.Id → Installed.EntryId → folder name → Version).
Aligné avec la logique RebuildList pour que les lookups par RowKey
trouvent la row correcte.
Bump : 1.0.9 → 1.0.10 (fix critique du refactor v1.0.8).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PS_Launcher — Installeur
Génère un setup Windows (PSLauncher-Setup-{version}.exe) qui distribue
le launcher principal + son updater dans Program Files\ASTERION VR\PSLauncher\.
Pré-requis
- .NET 8 SDK (déjà installé pour build le projet)
- Inno Setup 6.x — https://jrsoftware.org/isdl.php (gratuit, ~6 Mo)
Build en une commande
Depuis la racine du repo :
powershell -ExecutionPolicy Bypass -File installer\build-installer.ps1
Ça enchaîne :
dotnet publish src/PSLauncher.App -c Release→PSLauncher.exe(~77 Mo)dotnet publish src/PSLauncher.Updater -c Release→PSLauncher.Updater.exe(~10 Mo)ISCC PSLauncher.iss→installer/output/PSLauncher-Setup-X.Y.Z.exe
Le fichier final fait ~80 Mo (compression ultra Inno + binaires self-contained).
Distribution
Tu balances un seul .exe au client :
- Il lance, choisit français/anglais, clique Suivant×3, c'est installé.
- Raccourci bureau + menu Démarrer créés.
- Désinstallation propre via Programmes et fonctionnalités.
Le cache utilisateur (%LocalAppData%\PSLauncher\config.json, logs, downloads partiels)
n'est pas touché par l'install/désinstall — la license et les paramètres survivent.
Mise à jour du launcher
Le launcher se met à jour seul via PSLauncher.Updater.exe (cf. flow auto-update).
Le client n'a pas besoin de rejouer l'installeur sauf changement majeur (TFM, déps).
Bumper la version
Avant de rebuild un installeur :
src/PSLauncher.App/PSLauncher.App.csproj→<Version>X.Y.Z</Version>(et AssemblyVersion / FileVersion)installer/PSLauncher.iss→#define MyAppVersion "X.Y.Z"installer/build-installer.ps1
Côté serveur, mets aussi à jour manifest/versions.json section launcher avec la
nouvelle version + URL de download du nouveau PSLauncher.exe (via le backoffice
ou édition manuelle, puis php tools/sign-manifest.php).
Code-signing (optionnel)
Pour éviter le warning SmartScreen "éditeur inconnu", il faut signer
PSLauncher.exe, PSLauncher.Updater.exe et PSLauncher-Setup-X.Y.Z.exe avec
un certificat Authenticode (OV ~250 €/an, EV ~400 €/an, ou gratuit via SignPath
pour OSS). Hors-scope du script actuel.