Go 95 lines
package workflow
import (
"fmt"
"os"
"path/filepath"
"github.com/ajhahnde/eeco/internal/config"
)
// DisabledMarker is the sentinel file name that marks a user-scaffolded
// workflow as disabled. Its presence inside the workflow's directory
// makes ScriptRun report the workflow as blocked rather than execute
// it. The marker is empty; its existence is the entire signal. Stored
// in-tree with the workflow it gates, so removing the workflow removes
// the marker, and no separate ledger file enters the frozen surface.
const DisabledMarker = "disabled"
// workflowDir returns the absolute path of a user-scaffolded workflow's
// directory inside the workspace.
func workflowDir(cfg *config.Config, name string) string {
return filepath.Join(cfg.Workspace, "workflows", name)
}
// WorkflowExists reports whether a user-scaffolded workflow directory
// exists for name. Used by the CLI surface to refuse a toggle that
// names a workflow eeco does not know about.
func WorkflowExists(cfg *config.Config, name string) bool {
if cfg == nil {
return false
}
info, err := os.Stat(workflowDir(cfg, name))
return err == nil && info.IsDir()
}
// IsDisabled reports whether a user-scaffolded workflow is currently
// disabled. A missing workflow is not "disabled" — it is absent; callers
// that need to distinguish use WorkflowExists first.
func IsDisabled(cfg *config.Config, name string) bool {
if cfg == nil {
return false
}
_, err := os.Stat(filepath.Join(workflowDir(cfg, name), DisabledMarker))
return err == nil
}
// Disable marks a user-scaffolded workflow as disabled by creating an
// empty sentinel marker file inside its directory. The workflow stays
// on disk; ScriptRun reports it as blocked until Enable removes the
// marker. A workflow already disabled is a clean no-op.
func Disable(cfg *config.Config, name string) error {
dir, err := toggleDir(cfg, name)
if err != nil {
return err
}
marker := filepath.Join(dir, DisabledMarker)
if _, err := os.Stat(marker); err == nil {
return nil
}
return os.WriteFile(marker, nil, 0o644)
}
// Enable removes the disabled marker from a user-scaffolded workflow's
// directory. The workflow becomes runnable again. A workflow that is
// not disabled is a clean no-op.
func Enable(cfg *config.Config, name string) error {
dir, err := toggleDir(cfg, name)
if err != nil {
return err
}
marker := filepath.Join(dir, DisabledMarker)
if err := os.Remove(marker); err != nil && !os.IsNotExist(err) {
return err
}
return nil
}
// toggleDir validates inputs shared by Enable / Disable and returns the
// workflow's on-disk directory. Refuses nil config, a bad workflow
// name, and a workflow whose directory does not exist.
func toggleDir(cfg *config.Config, name string) (string, error) {
if cfg == nil {
return "", fmt.Errorf("nil config")
}
if !workflowNameRE.MatchString(name) {
return "", fmt.Errorf("workflow name %q: must be lower-kebab-case (a-z, 0-9, '-')", name)
}
dir := workflowDir(cfg, name)
info, err := os.Stat(dir)
if err != nil || !info.IsDir() {
return "", fmt.Errorf("workflow %q not found at %s", name, dir)
}
return dir, nil
}