mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-22 14:38:12 +02:00
Renommage AJEAN (2/3) : services, binaire et releases
Suite du renommage. Principe directeur : le code s'adapte a ce qui est DEJA installe sur la machine, plutot que d'exiger une migration privilegiee qui pourrait echouer et laisser un serveur sans service. Services (sys_unitname.go). Une mise a jour remplace le binaire, pas les unites systemd : un serveur deja installe tourne encore sous jean.service et jean-link.service. serviceName() et linkServiceName() resolvent donc le nom a l'usage — l'unite qui existe reellement — au lieu de supposer "ajean*". Sans ca, le premier systemctl restart apres MAJ echouerait, et sur un serveur distant ca veut dire l'acces coupe sans terminal pour reparer. Meme logique pour le label launchd, ou le prefixe com.jean. est conserve tant que c'est lui qui est charge. Le fichier PID du worker de lien est repris au passage (jean-link.pid -> ajean-link.pid) : c'est lui qui dit si un worker tourne, et sans reprise la premiere version renommee en aurait demarre un second, donnant deux tunnels concurrents vers le relais. Binaire. installedExePath vise desormais ajean(.exe), et l'installation pose un alias "jean" a cote — lien symbolique sous Unix, copie sous Windows ou les liens demandent des droits qu'on n'a pas toujours. La commande d'hier reste tapable : on ne controle ni les alias shell, ni les cron, ni les scripts de deploiement, ni les tutos deja ecrits. /etc/default/ajean est ecrit avec AJEAN_HOME ET JEAN_HOME, et l'ancien /etc/default/jean est laisse en place plutot que supprime : des scripts d'utilisateurs le sourcent. Releases. Les workflows produisent ajean-<os>-<arch> puis en copient un jeu jean-<os>-<arch> identique, une fois les binaires macOS recuperes. Les deux jeux sont dans SHA256SUMS. Ces copies sont indispensables : le parc installe ne sait chercher que jean-*, il ne pourrait donc meme pas atteindre la version qui apprend a lire ajean-*. A retirer quand le parc aura bascule. Le bundle devient AJEAN.app, avec le zip publie sous les deux noms pour ne pas casser les liens de telechargement deja diffuses. La detection du mode application se basant sur /Contents/MacOS et non sur le nom du bundle, elle n'est pas affectee.
This commit is contained in:
1 parent
110458c133
commit
3720b90173
11 files changed
+275
-99
No files matched your search
@@ -76,25 +76,25 @@ func cmdInstall(args []string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("utilisateur '%s' introuvable: %w", targetUser, err)
|
||||
}
|
||||
jeanHome := defaultJeanHome()
|
||||
ajeanHome := defaultAjeanHome()
|
||||
if v := os.Getenv("JEAN_HOME"); v != "" {
|
||||
jeanHome = v
|
||||
ajeanHome = v
|
||||
}
|
||||
svc := serviceName()
|
||||
|
||||
fmt.Printf("Installation pour utilisateur %s\n", cyan(targetUser))
|
||||
fmt.Printf(" JEAN_HOME = %s\n", jeanHome)
|
||||
fmt.Printf(" JEAN_HOME = %s\n", ajeanHome)
|
||||
fmt.Printf(" service = %s\n", svc)
|
||||
|
||||
// 1. Create directories
|
||||
for _, d := range []string{jeanHome, filepath.Join(jeanHome, "configs"), filepath.Join(jeanHome, "SKILLS")} {
|
||||
for _, d := range []string{ajeanHome, filepath.Join(ajeanHome, "configs"), filepath.Join(ajeanHome, "SKILLS")} {
|
||||
if err := os.MkdirAll(d, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Drop a config.env if none exists
|
||||
conf := filepath.Join(jeanHome, "config.env")
|
||||
conf := filepath.Join(ajeanHome, "config.env")
|
||||
if _, err := os.Stat(conf); os.IsNotExist(err) {
|
||||
body := strings.ReplaceAll(configTemplate, "USER", targetUser)
|
||||
if err := os.WriteFile(conf, []byte(body), 0o644); err != nil {
|
||||
@@ -111,7 +111,7 @@ func cmdInstall(args []string) error {
|
||||
if rp, e := filepath.EvalSymlinks(self); e == nil {
|
||||
self = rp
|
||||
}
|
||||
target := "/usr/local/bin/jean"
|
||||
target := installedExePath()
|
||||
// Garde-fou (issue #5) : si on tourne DÉJÀ depuis la cible (l'utilisateur a
|
||||
// posé le binaire dans /usr/local/bin/jean puis lancé `sudo jean install`),
|
||||
// ne surtout pas Remove+Symlink sur soi-même — ça effacerait le vrai binaire
|
||||
@@ -134,15 +134,34 @@ func cmdInstall(args []string) error {
|
||||
fmt.Printf(" %s %s -> %s\n", green("✓"), target, self)
|
||||
}
|
||||
|
||||
// 4. Drop /etc/default/jean so root invocations resolve JEAN_HOME correctly.
|
||||
defaults := fmt.Sprintf("# Generated by jean install — racine des configs/skills/SKILLS\nJEAN_HOME=%s\n", jeanHome)
|
||||
if err := os.WriteFile("/etc/default/jean", []byte(defaults), 0o644); err != nil {
|
||||
// 3 bis. Alias hérité : `jean` doit rester tapable. Des utilisateurs ont des
|
||||
// alias shell, des cron, des scripts de déploiement et des tutos qui appellent
|
||||
// « jean » — on ne contrôle rien de tout ça, et un binaire renommé qui casse
|
||||
// la commande d'hier est une régression pour eux. Le lien pointe sur le
|
||||
// nouveau nom, donc il suit les mises à jour sans entretien.
|
||||
if alias := legacyExePath(); alias != target {
|
||||
if rp, e := filepath.EvalSymlinks(alias); e != nil || rp != self {
|
||||
_ = os.Remove(alias)
|
||||
if err := os.Symlink(target, alias); err != nil {
|
||||
fmt.Printf(" %s alias %s non créé (%v) — « ajean » reste disponible\n", yellow("[info]"), alias, err)
|
||||
} else {
|
||||
fmt.Printf(" %s %s -> %s (alias hérité)\n", green("✓"), alias, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Drop /etc/default/ajean so root invocations resolve AJEAN_HOME correctly.
|
||||
// On écrit les DEUX clés : des scripts d'utilisateurs sourcent ce fichier et
|
||||
// lisent $JEAN_HOME. L'ancien /etc/default/jean est laissé en place — le
|
||||
// supprimer casserait ces mêmes scripts, et AjeanHome() sait déjà le lire.
|
||||
defaults := fmt.Sprintf("# Generated by ajean install — racine des configs/memoire/presets\nAJEAN_HOME=%s\nJEAN_HOME=%s\n", ajeanHome, ajeanHome)
|
||||
if err := os.WriteFile("/etc/default/ajean", []byte(defaults), 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf(" %s /etc/default/jean\n", green("✓"))
|
||||
fmt.Printf(" %s /etc/default/ajean\n", green("✓"))
|
||||
|
||||
// 5. Write the systemd unit (ExecStart = `jean serve`, no start.sh needed)
|
||||
unit := fmt.Sprintf(serviceUnitTemplate, targetUser, jeanHome, "/usr/local/bin/jean serve")
|
||||
// 5. Write the systemd unit (ExecStart = `ajean serve`, no start.sh needed)
|
||||
unit := fmt.Sprintf(serviceUnitTemplate, targetUser, ajeanHome, installedExePath()+" serve")
|
||||
unitPath := "/etc/systemd/system/" + svc + ".service"
|
||||
if err := os.WriteFile(unitPath, []byte(unit), 0o644); err != nil {
|
||||
return err
|
||||
@@ -151,14 +170,14 @@ func cmdInstall(args []string) error {
|
||||
|
||||
// 5. Sudoers drop-in
|
||||
sudoers := fmt.Sprintf(sudoersTemplate, targetUser, svc, targetUser, svc, svc, svc, svc, svc)
|
||||
sudoersPath := "/etc/sudoers.d/jean-" + svc
|
||||
sudoersPath := "/etc/sudoers.d/ajean-" + svc
|
||||
if err := os.WriteFile(sudoersPath, []byte(sudoers), 0o440); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf(" %s %s\n", green("✓"), sudoersPath)
|
||||
|
||||
// 6. chown JEAN_HOME contents to target user
|
||||
chown(jeanHome, u)
|
||||
chown(ajeanHome, u)
|
||||
|
||||
// 7. systemd reload
|
||||
_ = exec.Command("systemctl", "daemon-reload").Run()
|
||||
@@ -191,9 +210,9 @@ func cmdUninstall(args []string) error {
|
||||
_ = exec.Command("systemctl", "disable", svc).Run()
|
||||
for _, p := range []string{
|
||||
"/etc/systemd/system/" + svc + ".service",
|
||||
"/etc/sudoers.d/jean-" + svc,
|
||||
"/etc/sudoers.d/ajean-" + svc,
|
||||
"/etc/default/jean",
|
||||
"/usr/local/bin/jean",
|
||||
installedExePath(),
|
||||
} {
|
||||
if err := os.Remove(p); err == nil {
|
||||
fmt.Printf(" %s %s\n", green("✓"), p)
|
||||
|
||||
Reference in new issue
Block a user