// Package hook runs post-sync hook scripts. package hook import ( "context" "fmt" "os" "os/exec" "strconv" "s3watch/internal/syncer" ) // Runner executes a configured hook script after changes. type Runner struct { path string dir string } // NewRunner creates a hook runner for an executable script path. func NewRunner(path string, dir string) Runner { return Runner{path: path, dir: dir} } // Run executes the hook and passes change counts through environment variables. func (r Runner) Run(ctx context.Context, result syncer.Result) error { if r.path == "" { return nil } cmd := exec.CommandContext(ctx, r.path) cmd.Dir = r.dir cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Env = append(os.Environ(), "S3WATCH_CHANGED="+strconv.FormatBool(result.Changed()), "S3WATCH_DOWNLOADED="+strconv.Itoa(result.Downloaded), "S3WATCH_UPLOADED="+strconv.Itoa(result.Uploaded), "S3WATCH_UPDATED="+strconv.Itoa(result.Updated), "S3WATCH_DELETED="+strconv.Itoa(result.Deleted), "S3WATCH_UNCHANGED="+strconv.Itoa(result.Unchanged), ) if err := cmd.Run(); err != nil { return fmt.Errorf("executing %q: %w", r.path, err) } return nil }