119 lines
3.4 KiB
Go
119 lines
3.4 KiB
Go
package app
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"strconv"
|
|
)
|
|
|
|
type boundedRunRequest struct {
|
|
Config commonConfigFlags
|
|
Plan BoundedPlan
|
|
Force bool
|
|
SelectedArtifacts []string
|
|
}
|
|
|
|
type singletonStringFlag struct {
|
|
name string
|
|
value string
|
|
set bool
|
|
}
|
|
|
|
func (f *singletonStringFlag) String() string { return f.value }
|
|
|
|
func (f *singletonStringFlag) Set(value string) error {
|
|
if f.set {
|
|
return fmt.Errorf("--%s may be specified only once", f.name)
|
|
}
|
|
f.value = value
|
|
f.set = true
|
|
return nil
|
|
}
|
|
|
|
func (f singletonStringFlag) pointer() *string {
|
|
if !f.set {
|
|
return nil
|
|
}
|
|
value := f.value
|
|
return &value
|
|
}
|
|
|
|
type singletonBoolFlag struct {
|
|
name string
|
|
value bool
|
|
set bool
|
|
}
|
|
|
|
func (f *singletonBoolFlag) String() string { return strconv.FormatBool(f.value) }
|
|
func (f *singletonBoolFlag) IsBoolFlag() bool { return true }
|
|
|
|
func (f *singletonBoolFlag) Set(raw string) error {
|
|
if f.set {
|
|
return fmt.Errorf("--%s may be specified only once", f.name)
|
|
}
|
|
value, err := strconv.ParseBool(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("--%s requires a boolean value: %w", f.name, err)
|
|
}
|
|
f.value = value
|
|
f.set = true
|
|
return nil
|
|
}
|
|
|
|
func parseBoundedRunRequest(command string, args []string, help io.Writer) (boundedRunRequest, error) {
|
|
fs := flag.NewFlagSet(command, flag.ContinueOnError)
|
|
fs.SetOutput(help)
|
|
|
|
var configFlags commonConfigFlags
|
|
var from singletonStringFlag
|
|
var through singletonStringFlag
|
|
var force singletonBoolFlag
|
|
var selectedArtifacts artifactSelectionFlag
|
|
from.name = "from"
|
|
through.name = "through"
|
|
force.name = "force"
|
|
|
|
addCommonConfigFlags(fs, &configFlags)
|
|
fs.Var(&from, "from", "first canonical stage to select (inclusive)")
|
|
fs.Var(&through, "through", "last canonical stage to select (inclusive)")
|
|
fs.Var(&force, "force", "rerun selected stages even when already succeeded")
|
|
fs.Var(&selectedArtifacts, "artifacts", "configured artifact names to execute and publish (comma-separated or repeatable)")
|
|
fs.Usage = func() {
|
|
invocation := "narratio run"
|
|
if command == "plan" {
|
|
invocation = "narratio session plan"
|
|
}
|
|
_, _ = fmt.Fprintf(help, "Usage: %s <session_id> [--from <stage>] [--through <stage>] [--force] [--artifacts <name[,name...]>] [common config flags]\n\n", invocation)
|
|
_, _ = fmt.Fprintln(help, "Bounds are inclusive; omitted --from or --through selects the beginning or end of the canonical pipeline.")
|
|
_, _ = fmt.Fprintln(help)
|
|
_, _ = fmt.Fprintln(help, "Flags:")
|
|
fs.PrintDefaults()
|
|
}
|
|
|
|
if err := parseSessionAwareFlags(command, fs, args, &configFlags.sessionID); err != nil {
|
|
return boundedRunRequest{}, err
|
|
}
|
|
if configFlags.sessionID == "" {
|
|
return boundedRunRequest{}, fmt.Errorf("%s: session_id is required", command)
|
|
}
|
|
plan, err := BuildBoundedPlan(from.value, through.value)
|
|
if err != nil {
|
|
return boundedRunRequest{}, fmt.Errorf("%s: %w", command, err)
|
|
}
|
|
normalizedArtifacts, err := selectedArtifacts.Normalize()
|
|
if err != nil {
|
|
return boundedRunRequest{}, fmt.Errorf("%s: invalid --artifacts: %w", command, err)
|
|
}
|
|
if len(normalizedArtifacts) > 0 && !plan.Contains("analyze") && !plan.Contains("publish") {
|
|
return boundedRunRequest{}, fmt.Errorf("%s: --artifacts requires a selected range containing analyze or publish", command)
|
|
}
|
|
|
|
return boundedRunRequest{
|
|
Config: configFlags,
|
|
Plan: plan,
|
|
Force: force.value,
|
|
SelectedArtifacts: normalizedArtifacts,
|
|
}, nil
|
|
}
|