mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
Le refus d'un chargement résident trop gros pour la RAM faisait sortir « loki serve » en erreur (code 1) ; l'unité loki-engine (Restart=on-failure, RestartSec=3) le relançait toutes les trois secondes, sans fin, pour un échec qui ne dépend que du preset et de la machine. - Le refus sort avec un code dédié, 78 (EX_CONFIG) ; mustExit respecte le code porté par l'erreur, toutes les autres gardent 1. - L'unité écrite par « loki install » porte RestartPreventExitStatus=78 ; les autres échecs restent relancés. - Unité d'une version précédente (« loki update » ne réécrit pas les unités, il tourne sans droits root) : reconnue à coup sûr (parent systemd, INVOCATION_ID, unité et compléments lus sans la directive), le refus y sort sans erreur pour ne pas boucler, avec la marche à suivre au journal. Même chose sous launchd, qui relance toute sortie non nulle. - Le moteur d'essai de l'optimiseur garde toujours le vrai code. Le conteneur ne relance jamais le moteur de lui-même : rien à y changer, la raison reste au journal et l'interface la montre (modelLoadError). - Tests : directive reconnue (et seulement elle), code de sortie du refus, enveloppé ou non, unité générée (Linux). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
86 lines
3.1 KiB
Go
86 lines
3.1 KiB
Go
//go:build darwin
|
|
|
|
package loki
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
)
|
|
|
|
// sys_install_darwin.go — la part launchd de l'installation. Le parcours commun
|
|
// (dossiers, lien du binaire, /etc/default, chown) vit dans sys_install_unix.go.
|
|
//
|
|
// ⚠️ NON TESTÉ sur un vrai Mac. Le support macOS a été ajouté parce que le code
|
|
// systemd tournait par erreur et échouait sur « systemctl: command not found ».
|
|
// Implémentation prudente, à valider sur une machine Apple.
|
|
|
|
// launchdPlistTemplate — champs : Label, binaire, argument, UserName,
|
|
// WorkingDirectory, LOKI_HOME, StandardOutPath, StandardErrorPath.
|
|
// KeepAlive/SuccessfulExit=false ≈ Restart=on-failure ; RunAtLoad relance au
|
|
// boot une fois chargé avec `-w`.
|
|
const launchdPlistTemplate = `<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>Label</key><string>%s</string>
|
|
<key>ProgramArguments</key>
|
|
<array>
|
|
<string>%s</string>
|
|
<string>%s</string>
|
|
</array>
|
|
<key>UserName</key><string>%s</string>
|
|
<key>WorkingDirectory</key><string>%s</string>
|
|
<key>EnvironmentVariables</key>
|
|
<dict><key>LOKI_HOME</key><string>%s</string></dict>
|
|
<key>RunAtLoad</key><true/>
|
|
<key>KeepAlive</key>
|
|
<dict><key>SuccessfulExit</key><false/></dict>
|
|
<key>StandardOutPath</key><string>%s</string>
|
|
<key>StandardErrorPath</key><string>%s</string>
|
|
</dict>
|
|
</plist>
|
|
`
|
|
|
|
// unitArgs associe chaque service à la sous-commande qu'il exécute.
|
|
func unitArgs() map[string]string {
|
|
return map[string]string{serviceName(): "serve", uiUnitName: "web"}
|
|
}
|
|
|
|
// supervisorRestartsRefusal : sous launchd (le LaunchDaemon du moteur, que
|
|
// launchd désigne par XPC_SERVICE_NAME), KeepAlive/SuccessfulExit=false relance
|
|
// TOUTE sortie non nulle — aucune exception par code n'existe. Un refus de
|
|
// LOAD_GUARD y sort donc sans erreur (voir loadGuardRefusal). L'app de bureau
|
|
// lance le moteur elle-même et ne le relance pas : code normal.
|
|
func supervisorRestartsRefusal() (bool, string) {
|
|
return os.Getenv("XPC_SERVICE_NAME") == "com.loki."+serviceName(), ""
|
|
}
|
|
|
|
func installServices(targetUser, lokiHome string) error {
|
|
exe := installedExePath()
|
|
for name, arg := range unitArgs() {
|
|
logPath := filepath.Join(lokiHome, name+".log")
|
|
plist := fmt.Sprintf(launchdPlistTemplate,
|
|
launchdLabel(name), exe, arg, targetUser, lokiHome, lokiHome, logPath, logPath)
|
|
path := launchdPlistPath(name)
|
|
if err := os.WriteFile(path, []byte(plist), 0o644); err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf(" %s %s\n", green("✓"), path)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// uninstallServices décharge et efface les deux daemons. L'interface passe
|
|
// AVANT le moteur : elle sait le redémarrer, l'ordre inverse pourrait le
|
|
// relancer sous nos pieds.
|
|
func uninstallServices() {
|
|
for _, name := range []string{uiUnitName, serviceName()} {
|
|
_ = exec.Command("launchctl", "unload", "-w", launchdPlistPath(name)).Run()
|
|
if err := os.Remove(launchdPlistPath(name)); err == nil {
|
|
fmt.Printf(" %s %s\n", green("✓"), launchdPlistPath(name))
|
|
}
|
|
}
|
|
}
|