refactor: Break up 275-line runCook into focused helpers (bd-8zbo)
Extracted 5 helper functions from the monolithic runCook function: - parseCookFlags: Parse and validate command-line flags (~40 lines) - loadAndResolveFormula: Parse, resolve, apply transformations (~60 lines) - outputCookDryRun: Display dry-run preview (~60 lines) - outputCookEphemeral: Output resolved formula as JSON (~30 lines) - persistCookFormula: Create proto bead in database (~45 lines) Main runCook function reduced from ~275 to ~65 lines with clear flow: 1. Parse flags → 2. Validate store → 3. Load formula 4. Extract metadata → 5. Handle mode (dry-run/ephemeral/persist) Benefits: - Each helper is single-responsibility and testable - Added cookFlags struct for type-safe flag passing - Error handling uses proper error returns instead of os.Exit - Clear separation of concerns 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
351
cmd/bd/cook.go
351
cmd/bd/cook.go
@@ -99,7 +99,20 @@ type cookResult struct {
|
|||||||
BondPoints []string `json:"bond_points,omitempty"`
|
BondPoints []string `json:"bond_points,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCook(cmd *cobra.Command, args []string) {
|
// cookFlags holds parsed command-line flags for the cook command
|
||||||
|
type cookFlags struct {
|
||||||
|
dryRun bool
|
||||||
|
persist bool
|
||||||
|
force bool
|
||||||
|
searchPaths []string
|
||||||
|
prefix string
|
||||||
|
inputVars map[string]string
|
||||||
|
runtimeMode bool
|
||||||
|
formulaPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseCookFlags parses and validates cook command flags
|
||||||
|
func parseCookFlags(cmd *cobra.Command, args []string) (*cookFlags, error) {
|
||||||
dryRun, _ := cmd.Flags().GetBool("dry-run")
|
dryRun, _ := cmd.Flags().GetBool("dry-run")
|
||||||
persist, _ := cmd.Flags().GetBool("persist")
|
persist, _ := cmd.Flags().GetBool("persist")
|
||||||
force, _ := cmd.Flags().GetBool("force")
|
force, _ := cmd.Flags().GetBool("force")
|
||||||
@@ -113,61 +126,51 @@ func runCook(cmd *cobra.Command, args []string) {
|
|||||||
for _, v := range varFlags {
|
for _, v := range varFlags {
|
||||||
parts := strings.SplitN(v, "=", 2)
|
parts := strings.SplitN(v, "=", 2)
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
fmt.Fprintf(os.Stderr, "Error: invalid variable format '%s', expected 'key=value'\n", v)
|
return nil, fmt.Errorf("invalid variable format '%s', expected 'key=value'", v)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
inputVars[parts[0]] = parts[1]
|
inputVars[parts[0]] = parts[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine cooking mode
|
// Validate mode
|
||||||
|
if mode != "" && mode != "compile" && mode != "runtime" {
|
||||||
|
return nil, fmt.Errorf("invalid mode '%s', must be 'compile' or 'runtime'", mode)
|
||||||
|
}
|
||||||
|
|
||||||
// Runtime mode is triggered by: explicit --mode=runtime OR providing --var flags
|
// Runtime mode is triggered by: explicit --mode=runtime OR providing --var flags
|
||||||
runtimeMode := mode == "runtime" || len(inputVars) > 0
|
runtimeMode := mode == "runtime" || len(inputVars) > 0
|
||||||
if mode != "" && mode != "compile" && mode != "runtime" {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error: invalid mode '%s', must be 'compile' or 'runtime'\n", mode)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only need store access if persisting
|
return &cookFlags{
|
||||||
if persist {
|
dryRun: dryRun,
|
||||||
CheckReadonly("cook --persist")
|
persist: persist,
|
||||||
|
force: force,
|
||||||
|
searchPaths: searchPaths,
|
||||||
|
prefix: prefix,
|
||||||
|
inputVars: inputVars,
|
||||||
|
runtimeMode: runtimeMode,
|
||||||
|
formulaPath: args[0],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
if store == nil {
|
// loadAndResolveFormula parses a formula file and applies all transformations
|
||||||
if daemonClient != nil {
|
func loadAndResolveFormula(formulaPath string, searchPaths []string) (*formula.Formula, error) {
|
||||||
fmt.Fprintf(os.Stderr, "Error: cook --persist requires direct database access\n")
|
|
||||||
fmt.Fprintf(os.Stderr, "Hint: use --no-daemon flag: bd --no-daemon cook %s --persist ...\n", args[0])
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error: no database connection\n")
|
|
||||||
}
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := rootCtx
|
|
||||||
|
|
||||||
// Create parser with search paths
|
|
||||||
parser := formula.NewParser(searchPaths...)
|
parser := formula.NewParser(searchPaths...)
|
||||||
|
|
||||||
// Parse the formula file
|
// Parse the formula file
|
||||||
formulaPath := args[0]
|
|
||||||
f, err := parser.ParseFile(formulaPath)
|
f, err := parser.ParseFile(formulaPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error parsing formula: %v\n", err)
|
return nil, fmt.Errorf("parsing formula: %w", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve inheritance
|
// Resolve inheritance
|
||||||
resolved, err := parser.Resolve(f)
|
resolved, err := parser.Resolve(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error resolving formula: %v\n", err)
|
return nil, fmt.Errorf("resolving formula: %w", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply control flow operators - loops, branches, gates
|
// Apply control flow operators - loops, branches, gates
|
||||||
// This must happen before advice and expansions so they can act on expanded loop steps
|
|
||||||
controlFlowSteps, err := formula.ApplyControlFlow(resolved.Steps, resolved.Compose)
|
controlFlowSteps, err := formula.ApplyControlFlow(resolved.Steps, resolved.Compose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error applying control flow: %v\n", err)
|
return nil, fmt.Errorf("applying control flow: %w", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
resolved.Steps = controlFlowSteps
|
resolved.Steps = controlFlowSteps
|
||||||
|
|
||||||
@@ -177,11 +180,9 @@ func runCook(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply inline step expansions
|
// Apply inline step expansions
|
||||||
// This processes Step.Expand fields before compose.expand/map rules
|
|
||||||
inlineExpandedSteps, err := formula.ApplyInlineExpansions(resolved.Steps, parser)
|
inlineExpandedSteps, err := formula.ApplyInlineExpansions(resolved.Steps, parser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error applying inline expansions: %v\n", err)
|
return nil, fmt.Errorf("applying inline expansions: %w", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
resolved.Steps = inlineExpandedSteps
|
resolved.Steps = inlineExpandedSteps
|
||||||
|
|
||||||
@@ -189,8 +190,7 @@ func runCook(cmd *cobra.Command, args []string) {
|
|||||||
if resolved.Compose != nil && (len(resolved.Compose.Expand) > 0 || len(resolved.Compose.Map) > 0) {
|
if resolved.Compose != nil && (len(resolved.Compose.Expand) > 0 || len(resolved.Compose.Map) > 0) {
|
||||||
expandedSteps, err := formula.ApplyExpansions(resolved.Steps, resolved.Compose, parser)
|
expandedSteps, err := formula.ApplyExpansions(resolved.Steps, resolved.Compose, parser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error applying expansions: %v\n", err)
|
return nil, fmt.Errorf("applying expansions: %w", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
resolved.Steps = expandedSteps
|
resolved.Steps = expandedSteps
|
||||||
}
|
}
|
||||||
@@ -200,12 +200,10 @@ func runCook(cmd *cobra.Command, args []string) {
|
|||||||
for _, aspectName := range resolved.Compose.Aspects {
|
for _, aspectName := range resolved.Compose.Aspects {
|
||||||
aspectFormula, err := parser.LoadByName(aspectName)
|
aspectFormula, err := parser.LoadByName(aspectName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error loading aspect %q: %v\n", aspectName, err)
|
return nil, fmt.Errorf("loading aspect %q: %w", aspectName, err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
if aspectFormula.Type != formula.TypeAspect {
|
if aspectFormula.Type != formula.TypeAspect {
|
||||||
fmt.Fprintf(os.Stderr, "Error: %q is not an aspect formula (type=%s)\n", aspectName, aspectFormula.Type)
|
return nil, fmt.Errorf("%q is not an aspect formula (type=%s)", aspectName, aspectFormula.Type)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
if len(aspectFormula.Advice) > 0 {
|
if len(aspectFormula.Advice) > 0 {
|
||||||
resolved.Steps = formula.ApplyAdvice(resolved.Steps, aspectFormula.Advice)
|
resolved.Steps = formula.ApplyAdvice(resolved.Steps, aspectFormula.Advice)
|
||||||
@@ -213,141 +211,119 @@ func runCook(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply prefix to proto ID if specified
|
return resolved, nil
|
||||||
protoID := resolved.Formula
|
}
|
||||||
if prefix != "" {
|
|
||||||
protoID = prefix + resolved.Formula
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract variables used in the formula
|
// outputCookDryRun displays a dry-run preview of what would be cooked
|
||||||
vars := formula.ExtractVariables(resolved)
|
func outputCookDryRun(resolved *formula.Formula, protoID string, runtimeMode bool, inputVars map[string]string, vars, bondPoints []string) {
|
||||||
|
modeLabel := "compile-time"
|
||||||
// Collect bond points
|
if runtimeMode {
|
||||||
var bondPoints []string
|
modeLabel = "runtime"
|
||||||
if resolved.Compose != nil {
|
// Apply defaults for runtime mode display
|
||||||
for _, bp := range resolved.Compose.BondPoints {
|
for name, def := range resolved.Vars {
|
||||||
bondPoints = append(bondPoints, bp.ID)
|
if _, provided := inputVars[name]; !provided && def.Default != "" {
|
||||||
|
inputVars[name] = def.Default
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if dryRun {
|
fmt.Printf("\nDry run: would cook formula %s as proto %s (%s mode)\n\n", resolved.Formula, protoID, modeLabel)
|
||||||
// Determine mode label for display
|
|
||||||
modeLabel := "compile-time"
|
|
||||||
if runtimeMode {
|
|
||||||
modeLabel = "runtime"
|
|
||||||
// Apply defaults for runtime mode display
|
|
||||||
for name, def := range resolved.Vars {
|
|
||||||
if _, provided := inputVars[name]; !provided && def.Default != "" {
|
|
||||||
inputVars[name] = def.Default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("\nDry run: would cook formula %s as proto %s (%s mode)\n\n", resolved.Formula, protoID, modeLabel)
|
// In runtime mode, show substituted steps
|
||||||
|
if runtimeMode {
|
||||||
|
substituteFormulaVars(resolved, inputVars)
|
||||||
|
fmt.Printf("Steps (%d) [variables substituted]:\n", len(resolved.Steps))
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Steps (%d) [{{variables}} shown as placeholders]:\n", len(resolved.Steps))
|
||||||
|
}
|
||||||
|
printFormulaSteps(resolved.Steps, " ")
|
||||||
|
|
||||||
// In runtime mode, show substituted steps
|
if len(vars) > 0 {
|
||||||
if runtimeMode {
|
fmt.Printf("\nVariables used: %s\n", strings.Join(vars, ", "))
|
||||||
// Create a copy with substituted values for display
|
|
||||||
substituteFormulaVars(resolved, inputVars)
|
|
||||||
fmt.Printf("Steps (%d) [variables substituted]:\n", len(resolved.Steps))
|
|
||||||
} else {
|
|
||||||
fmt.Printf("Steps (%d) [{{variables}} shown as placeholders]:\n", len(resolved.Steps))
|
|
||||||
}
|
|
||||||
printFormulaSteps(resolved.Steps, " ")
|
|
||||||
|
|
||||||
if len(vars) > 0 {
|
|
||||||
fmt.Printf("\nVariables used: %s\n", strings.Join(vars, ", "))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show variable values in runtime mode
|
|
||||||
if runtimeMode && len(inputVars) > 0 {
|
|
||||||
fmt.Printf("\nVariable values:\n")
|
|
||||||
for name, value := range inputVars {
|
|
||||||
fmt.Printf(" {{%s}} = %s\n", name, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(bondPoints) > 0 {
|
|
||||||
fmt.Printf("Bond points: %s\n", strings.Join(bondPoints, ", "))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show variable definitions (more useful in compile-time mode)
|
|
||||||
if !runtimeMode && len(resolved.Vars) > 0 {
|
|
||||||
fmt.Printf("\nVariable definitions:\n")
|
|
||||||
for name, def := range resolved.Vars {
|
|
||||||
attrs := []string{}
|
|
||||||
if def.Required {
|
|
||||||
attrs = append(attrs, "required")
|
|
||||||
}
|
|
||||||
if def.Default != "" {
|
|
||||||
attrs = append(attrs, fmt.Sprintf("default=%s", def.Default))
|
|
||||||
}
|
|
||||||
if len(def.Enum) > 0 {
|
|
||||||
attrs = append(attrs, fmt.Sprintf("enum=[%s]", strings.Join(def.Enum, ",")))
|
|
||||||
}
|
|
||||||
attrStr := ""
|
|
||||||
if len(attrs) > 0 {
|
|
||||||
attrStr = fmt.Sprintf(" (%s)", strings.Join(attrs, ", "))
|
|
||||||
}
|
|
||||||
fmt.Printf(" {{%s}}: %s%s\n", name, def.Description, attrStr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ephemeral mode (default): output resolved formula as JSON to stdout
|
// Show variable values in runtime mode
|
||||||
if !persist {
|
if runtimeMode && len(inputVars) > 0 {
|
||||||
// Runtime mode: substitute variables before output
|
fmt.Printf("\nVariable values:\n")
|
||||||
if runtimeMode {
|
for name, value := range inputVars {
|
||||||
// Apply defaults from formula variable definitions
|
fmt.Printf(" {{%s}} = %s\n", name, value)
|
||||||
for name, def := range resolved.Vars {
|
|
||||||
if _, provided := inputVars[name]; !provided && def.Default != "" {
|
|
||||||
inputVars[name] = def.Default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for missing required variables
|
|
||||||
var missingVars []string
|
|
||||||
for _, v := range vars {
|
|
||||||
if _, ok := inputVars[v]; !ok {
|
|
||||||
missingVars = append(missingVars, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(missingVars) > 0 {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error: runtime mode requires all variables to have values\n")
|
|
||||||
fmt.Fprintf(os.Stderr, "Missing: %s\n", strings.Join(missingVars, ", "))
|
|
||||||
fmt.Fprintf(os.Stderr, "Provide with: --var %s=<value>\n", missingVars[0])
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Substitute variables in the formula
|
|
||||||
substituteFormulaVars(resolved, inputVars)
|
|
||||||
}
|
}
|
||||||
outputJSON(resolved)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persist mode: create proto bead in database (legacy behavior)
|
if len(bondPoints) > 0 {
|
||||||
|
fmt.Printf("Bond points: %s\n", strings.Join(bondPoints, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show variable definitions (more useful in compile-time mode)
|
||||||
|
if !runtimeMode && len(resolved.Vars) > 0 {
|
||||||
|
fmt.Printf("\nVariable definitions:\n")
|
||||||
|
for name, def := range resolved.Vars {
|
||||||
|
attrs := []string{}
|
||||||
|
if def.Required {
|
||||||
|
attrs = append(attrs, "required")
|
||||||
|
}
|
||||||
|
if def.Default != "" {
|
||||||
|
attrs = append(attrs, fmt.Sprintf("default=%s", def.Default))
|
||||||
|
}
|
||||||
|
if len(def.Enum) > 0 {
|
||||||
|
attrs = append(attrs, fmt.Sprintf("enum=[%s]", strings.Join(def.Enum, ",")))
|
||||||
|
}
|
||||||
|
attrStr := ""
|
||||||
|
if len(attrs) > 0 {
|
||||||
|
attrStr = fmt.Sprintf(" (%s)", strings.Join(attrs, ", "))
|
||||||
|
}
|
||||||
|
fmt.Printf(" {{%s}}: %s%s\n", name, def.Description, attrStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// outputCookEphemeral outputs the resolved formula as JSON (ephemeral mode)
|
||||||
|
func outputCookEphemeral(resolved *formula.Formula, runtimeMode bool, inputVars map[string]string, vars []string) error {
|
||||||
|
if runtimeMode {
|
||||||
|
// Apply defaults from formula variable definitions
|
||||||
|
for name, def := range resolved.Vars {
|
||||||
|
if _, provided := inputVars[name]; !provided && def.Default != "" {
|
||||||
|
inputVars[name] = def.Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for missing required variables
|
||||||
|
var missingVars []string
|
||||||
|
for _, v := range vars {
|
||||||
|
if _, ok := inputVars[v]; !ok {
|
||||||
|
missingVars = append(missingVars, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(missingVars) > 0 {
|
||||||
|
return fmt.Errorf("runtime mode requires all variables to have values\nMissing: %s\nProvide with: --var %s=<value>",
|
||||||
|
strings.Join(missingVars, ", "), missingVars[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Substitute variables in the formula
|
||||||
|
substituteFormulaVars(resolved, inputVars)
|
||||||
|
}
|
||||||
|
outputJSON(resolved)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// persistCookFormula creates a proto bead in the database (persist mode)
|
||||||
|
func persistCookFormula(ctx context.Context, resolved *formula.Formula, protoID string, force bool, vars, bondPoints []string) error {
|
||||||
// Check if proto already exists
|
// Check if proto already exists
|
||||||
existingProto, err := store.GetIssue(ctx, protoID)
|
existingProto, err := store.GetIssue(ctx, protoID)
|
||||||
if err == nil && existingProto != nil {
|
if err == nil && existingProto != nil {
|
||||||
if !force {
|
if !force {
|
||||||
fmt.Fprintf(os.Stderr, "Error: proto %s already exists\n", protoID)
|
return fmt.Errorf("proto %s already exists (use --force to replace)", protoID)
|
||||||
fmt.Fprintf(os.Stderr, "Hint: use --force to replace it\n")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
// Delete existing proto and its children
|
// Delete existing proto and its children
|
||||||
if err := deleteProtoSubgraph(ctx, store, protoID); err != nil {
|
if err := deleteProtoSubgraph(ctx, store, protoID); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error deleting existing proto: %v\n", err)
|
return fmt.Errorf("deleting existing proto: %w", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the proto bead from the formula
|
// Create the proto bead from the formula
|
||||||
result, err := cookFormula(ctx, store, resolved, protoID)
|
result, err := cookFormula(ctx, store, resolved, protoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error cooking formula: %v\n", err)
|
return fmt.Errorf("cooking formula: %w", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule auto-flush
|
// Schedule auto-flush
|
||||||
@@ -361,7 +337,7 @@ func runCook(cmd *cobra.Command, args []string) {
|
|||||||
Variables: vars,
|
Variables: vars,
|
||||||
BondPoints: bondPoints,
|
BondPoints: bondPoints,
|
||||||
})
|
})
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%s Cooked proto: %s\n", ui.RenderPass("✓"), result.ProtoID)
|
fmt.Printf("%s Cooked proto: %s\n", ui.RenderPass("✓"), result.ProtoID)
|
||||||
@@ -373,6 +349,73 @@ func runCook(cmd *cobra.Command, args []string) {
|
|||||||
fmt.Printf(" Bond points: %s\n", strings.Join(bondPoints, ", "))
|
fmt.Printf(" Bond points: %s\n", strings.Join(bondPoints, ", "))
|
||||||
}
|
}
|
||||||
fmt.Printf("\nTo use: bd mol pour %s --var <name>=<value>\n", result.ProtoID)
|
fmt.Printf("\nTo use: bd mol pour %s --var <name>=<value>\n", result.ProtoID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCook(cmd *cobra.Command, args []string) {
|
||||||
|
// Parse and validate flags
|
||||||
|
flags, err := parseCookFlags(cmd, args)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate store access for persist mode
|
||||||
|
if flags.persist {
|
||||||
|
CheckReadonly("cook --persist")
|
||||||
|
if store == nil {
|
||||||
|
if daemonClient != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: cook --persist requires direct database access\n")
|
||||||
|
fmt.Fprintf(os.Stderr, "Hint: use --no-daemon flag: bd --no-daemon cook %s --persist ...\n", flags.formulaPath)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: no database connection\n")
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load and resolve the formula
|
||||||
|
resolved, err := loadAndResolveFormula(flags.formulaPath, flags.searchPaths)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply prefix to proto ID if specified
|
||||||
|
protoID := resolved.Formula
|
||||||
|
if flags.prefix != "" {
|
||||||
|
protoID = flags.prefix + resolved.Formula
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract variables and bond points
|
||||||
|
vars := formula.ExtractVariables(resolved)
|
||||||
|
var bondPoints []string
|
||||||
|
if resolved.Compose != nil {
|
||||||
|
for _, bp := range resolved.Compose.BondPoints {
|
||||||
|
bondPoints = append(bondPoints, bp.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle dry-run mode
|
||||||
|
if flags.dryRun {
|
||||||
|
outputCookDryRun(resolved, protoID, flags.runtimeMode, flags.inputVars, vars, bondPoints)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle ephemeral mode (default)
|
||||||
|
if !flags.persist {
|
||||||
|
if err := outputCookEphemeral(resolved, flags.runtimeMode, flags.inputVars, vars); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle persist mode
|
||||||
|
if err := persistCookFormula(rootCtx, resolved, protoID, flags.force, vars, bondPoints); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// cookFormulaResult holds the result of cooking
|
// cookFormulaResult holds the result of cooking
|
||||||
|
|||||||
Reference in New Issue
Block a user