package main import ( "context" "errors" "fmt" "io" "os" "strconv" commandkit "gitea.maximumdirect.net/eric/CommandKit" ) type greetInput struct { Count commandkit.Supplied[int] Tags commandkit.Supplied[[]string] } type reportInput struct { Scenario string } var ( errRecoveredFixture = errors.New("a local read failed and was recovered") errWarningFixture = errors.New("a local warning has a cause") errPartialFixture = errors.New("the local report could not be completed") ) func newApp() (*commandkit.App, error) { countDefault := 1 tagDefaults := []string{"demo"} greet := commandkit.NewCommand(commandkit.CommandSpec[greetInput]{ Name: "greet", Summary: "Show presence-aware values and repeated labels.", Flags: []commandkit.Flag[greetInput]{ commandkit.ValueFlag(commandkit.FlagMeta{Name: "count", Usage: "Greeting count."}, &countDefault, strconv.Atoi, func(input *greetInput, value commandkit.Supplied[int]) { input.Count = value }), commandkit.RepeatFlag(commandkit.FlagMeta{Name: "tag", Usage: "A repeatable label."}, tagDefaults, func(value string) (string, error) { return value, nil }, func(input *greetInput, value commandkit.Supplied[[]string]) { input.Tags = value }), }, Run: func(invocation commandkit.Invocation, input greetInput) commandkit.Outcome { reporter := invocation.Reporter() count := fmt.Sprintf("default %d (not supplied)", input.Count.Value) if input.Count.Set { count = fmt.Sprintf("explicit %d", input.Count.Value) } tags := fmt.Sprintf("default %v (not supplied)", input.Tags.Value) if input.Tags.Set { tags = fmt.Sprintf("explicit %v", input.Tags.Value) } _ = reporter.RenderOutput(func(writer io.Writer) error { _, err := fmt.Fprintf(writer, "Hello; count=%s; tags=%s; entered=%q; canonical=%q\n", count, tags, invocation.EnteredPath(), invocation.CanonicalPath()) return err }) return commandkit.Success() }, }) report := commandkit.NewCommand(commandkit.CommandSpec[reportInput]{ Name: "report", Summary: "Demonstrate invocation reporting with local scenarios.", NewInput: func() reportInput { return reportInput{Scenario: "demo"} }, Arguments: []commandkit.Argument[reportInput]{ commandkit.ValueArgument(commandkit.ArgumentMeta{Name: "scenario", Usage: "demo, recover, warn, warn-error, fail, or partial."}, false, func(value string) (string, error) { return value, nil }, func(input *reportInput, value commandkit.Supplied[string]) { input.Scenario = value.Value }), }, CheckInput: func(input reportInput) error { switch input.Scenario { case "demo", "recover", "warn", "warn-error", "fail", "partial": return nil default: return fmt.Errorf("unknown reporting scenario %q", input.Scenario) } }, Run: func(invocation commandkit.Invocation, input reportInput) commandkit.Outcome { return runReportingExample(invocation, input.Scenario) }, }) workspace := commandkit.Group("workspace", "Workspace commands.", greet) declarations := []commandkit.Declaration{ workspace, report, commandkit.Alias("hello", "workspace greet"), commandkit.Alias("ws", "workspace"), commandkit.FlagAliasFor("workspace greet", "--times", "--count"), commandkit.FlagAlias("--hlep", "--help"), } return commandkit.New(commandkit.Identity{Name: "core-example", Version: "1.0"}, declarations...) } func runReportingExample(invocation commandkit.Invocation, scenario string) commandkit.Outcome { reporter := invocation.Reporter() deferred := reporter.AtEnd() switch scenario { case "demo": _ = reporter.Progress("Loaded one local fixture.") _ = deferred.Warn("Optional fixture warning", func(writer io.Writer) error { _, err := io.WriteString(writer, "The sample contains an optional note.\n") return err }) _ = deferred.Info("Using deterministic local data.") _ = deferred.Debug("Selected the built-in reporting example.") _ = deferred.Info("Summary", writeExampleSummary) _ = reporter.RenderOutput(writeExampleReport) return commandkit.Success() case "recover": return commandkit.Success().WithCause(errRecoveredFixture) case "warn": _ = deferred.Warn("The local operation completed with a warning.") return commandkit.Success() case "warn-error": _ = deferred.Warn("The local operation completed with a warning.") return commandkit.Success().WithCause(errWarningFixture) case "fail": return commandkit.Failure("The selected local operation could not be completed.") case "partial": _ = reporter.RenderOutput(writePartialExampleReport) return commandkit.Failure("The local report stopped after partial output.").WithCause(errPartialFixture) default: return commandkit.Usage(fmt.Sprintf("unknown reporting scenario %q", scenario)) } } func writeExampleReport(writer io.Writer) error { _, err := fmt.Fprintln(writer, "Prepared a local report from one fixture.") return err } func writePartialExampleReport(writer io.Writer) error { _, err := io.WriteString(writer, "Partial local report: first section complete.\n") return err } func writeExampleSummary(writer io.Writer) error { _, err := io.WriteString(writer, "Processed one local fixture.\n") return err } func main() { app, err := newApp() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } outcome := app.Execute(context.Background(), os.Args[1:], commandkit.Streams{Out: os.Stdout, Err: os.Stderr}) if outcome.Status != 0 { os.Exit(outcome.Status) } }