ananke/internal/execx/runner.go

59 lines
1.6 KiB
Go

package execx
import (
"context"
"fmt"
"log"
"os"
"os/exec"
"strings"
)
type Runner struct {
DryRun bool
Kubeconfig string
Logger *log.Logger
}
// Run runs one orchestration or CLI step.
// Signature: (r *Runner) Run(ctx context.Context, name string, args ...string) (string, error).
// Why: keeps behavior explicit so startup/shutdown workflows remain maintainable as services evolve.
func (r *Runner) Run(ctx context.Context, name string, args ...string) (string, error) {
if r.DryRun {
r.logf("DRY-RUN: %s %s", name, strings.Join(args, " "))
return "", nil
}
cmd := exec.CommandContext(ctx, name, args...)
cmd.Env = os.Environ()
if r.Kubeconfig != "" {
cmd.Env = append(cmd.Env, "KUBECONFIG="+r.Kubeconfig)
}
out, err := cmd.CombinedOutput()
trimmed := strings.TrimSpace(string(out))
if err != nil {
if trimmed == "" {
return "", fmt.Errorf("%s %s: %w", name, strings.Join(args, " "), err)
}
return trimmed, fmt.Errorf("%s %s: %w", name, strings.Join(args, " "), err)
}
return trimmed, nil
}
// CommandExists runs one orchestration or CLI step.
// Signature: (r *Runner) CommandExists(name string) bool.
// Why: keeps behavior explicit so startup/shutdown workflows remain maintainable as services evolve.
func (r *Runner) CommandExists(name string) bool {
_, err := exec.LookPath(name)
return err == nil
}
// logf runs one orchestration or CLI step.
// Signature: (r *Runner) logf(format string, args ...any).
// Why: keeps behavior explicit so startup/shutdown workflows remain maintainable as services evolve.
func (r *Runner) logf(format string, args ...any) {
if r.Logger != nil {
r.Logger.Printf(format, args...)
}
}