install: éviter le symlink circulaire si le binaire tourne déjà depuis /usr/local/bin/jean (fix #5)

This commit is contained in:
nathaninline committed 2026-07-07 13:23:21 +02:00
1 parent 5931bd72a6
commit 357b814745
1 file changed
+22 -6
+22 -6
View File
@@ -108,15 +108,31 @@ func cmdInstall(args []string) error {
if err != nil {
return err
}
if rp, e := filepath.EvalSymlinks(self); e == nil {
self = rp
}
target := "/usr/local/bin/jean"
_ = os.Remove(target)
if err := os.Symlink(self, target); err != nil {
// fall back to copy if symlink fails (e.g. cross-fs)
if data, err := os.ReadFile(self); err == nil {
_ = os.WriteFile(target, data, 0o755)
// 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
// et créerait /usr/local/bin/jean -> /usr/local/bin/jean (« Too many levels
// of symbolic links »). On compare les chemins réels (résolus).
alreadyInPlace := false
if tp, e := filepath.EvalSymlinks(target); e == nil && tp == self {
alreadyInPlace = true
}
if alreadyInPlace {
fmt.Printf(" %s %s est déjà le binaire installé (aucun lien à créer)\n", green("✓"), target)
} else {
_ = os.Remove(target)
if err := os.Symlink(self, target); err != nil {
// fall back to copy if symlink fails (e.g. cross-fs)
if data, err := os.ReadFile(self); err == nil {
_ = os.WriteFile(target, data, 0o755)
}
}
fmt.Printf(" %s %s -> %s\n", green("✓"), target, self)
}
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)