diff --git a/AGENTS.md b/AGENTS.md index 497ebd1..ed865fc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -54,6 +54,7 @@ RESTIC_PASSWORD=example-local-password RESTIC_PASSWORD2=example-b2-password B2_APPLICATION_ID=xxxx B2_APPLICATION_KEY=yyyy +B2_EXECUTABLE_PATH=/opt/homebrew/bin/b2 SATORU_RESTIC_B2_REPOSITORY=b2:bucket-name:repo-prefix ``` diff --git a/cmd/satoru/config.go b/cmd/satoru/config.go index af78cae..b794c99 100644 --- a/cmd/satoru/config.go +++ b/cmd/satoru/config.go @@ -30,6 +30,7 @@ const defaultConfigBody = `# Satoru configuration file # Backblaze B2 credentials (application key format): # B2_APPLICATION_ID=your-application-key-id # B2_APPLICATION_KEY=your-application-key +# B2_EXECUTABLE_PATH=/opt/homebrew/bin/b2 # # B2 restic repository target: # SATORU_RESTIC_B2_REPOSITORY=b2:your-bucket:satoru-repo diff --git a/cmd/satoru/scanner.go b/cmd/satoru/scanner.go index 457399d..4e77cc4 100644 --- a/cmd/satoru/scanner.go +++ b/cmd/satoru/scanner.go @@ -17,25 +17,33 @@ import ( ) func (a *app) runtimeChecks() []webui.RuntimeCheck { - tools := []string{"restic", "rsync", "ssh", "b2"} + tools := []struct { + Name string + ExecPath string + }{ + {Name: "restic", ExecPath: "restic"}, + {Name: "rsync", ExecPath: "rsync"}, + {Name: "ssh", ExecPath: "ssh"}, + {Name: "b2", ExecPath: b2ExecutablePath()}, + } out := make([]webui.RuntimeCheck, 0, len(tools)) for _, name := range tools { - path, err := exec.LookPath(name) + path, err := exec.LookPath(name.ExecPath) if err != nil { - out = append(out, webui.RuntimeCheck{Name: name, Installed: false, Details: "not found in PATH"}) + out = append(out, webui.RuntimeCheck{Name: name.Name, Installed: false, Details: "not found: " + name.ExecPath}) continue } details := path - if name == "b2" && a.b2ProbeNote != "" { + if name.Name == "b2" && a.b2ProbeNote != "" { details = details + " | " + a.b2ProbeNote } - out = append(out, webui.RuntimeCheck{Name: name, Installed: true, Details: details}) + out = append(out, webui.RuntimeCheck{Name: name.Name, Installed: true, Details: details}) } return out } func (a *app) runStartupB2Probe(ctx context.Context) { - if _, err := exec.LookPath("b2"); err != nil { + if _, err := exec.LookPath(b2ExecutablePath()); err != nil { a.b2ProbeNote = "startup probe skipped: b2 cli not installed" a.b2InitReady = false a.b2InitRepo = "" @@ -105,6 +113,10 @@ func clipDetail(v string, max int) string { return v[:max-3] + "..." } +func b2ExecutablePath() string { + return getenvDefault("B2_EXECUTABLE_PATH", "b2") +} + func runSSHHello(ctx context.Context, site store.Site) (string, string) { target := fmt.Sprintf("%s@%s", site.SSHUser, site.Host) cmdCtx, cancel := context.WithTimeout(ctx, 10*time.Second)