package cli import ( "encoding/json" "flag" "fmt" "io" configkit "gitea.maximumdirect.net/eric/ConfigKit" appconfig "gitea.maximumdirect.net/eric/scriptorium/internal/config" ) type configurationSource struct { ID string `json:"id"` Label string `json:"label"` Layer configkit.Layer `json:"layer"` Path string `json:"path,omitempty"` } func configCommand(args []string, stdout, stderr io.Writer) int { if len(args) == 0 { fmt.Fprintln(stderr, "config parse error: configuration mode is required") return ExitRuntimeError } mode := args[0] if mode != "validate" && mode != "show" && mode != "sources" && mode != "explain" { fmt.Fprintln(stderr, "config parse error: unknown configuration mode") return ExitRuntimeError } fs := flag.NewFlagSet("config "+mode, flag.ContinueOnError) fs.SetOutput(io.Discard) var path, overlay, pointer string registerConfigSelectionFlags(fs, &path, &overlay) registerConfigurationOverrides(fs) if mode == "explain" { fs.StringVar(&pointer, "path", "", "configuration path as a JSON Pointer") } if err := fs.Parse(args[1:]); err != nil { writeApplicationError(stderr, "config parse", err) return ExitRuntimeError } if fs.NArg() != 0 { fmt.Fprintln(stderr, "config parse error: positional arguments are not accepted") return ExitRuntimeError } var explanationPath configkit.Path if mode == "explain" { if !flagWasSet(fs, "path") { fmt.Fprintln(stderr, "config parse error: --path is required") return ExitRuntimeError } var err error explanationPath, err = configkit.ParsePath(pointer) if err != nil { fmt.Fprintln(stderr, "config parse error: --path must be a JSON Pointer") return ExitRuntimeError } } result, err := appconfig.Load(appconfig.LoadOptions{ Path: path, Explicit: flagWasSet(fs, "config"), Overlay: overlay, Overrides: applicationOverrides(fs), }) if err != nil { writeApplicationError(stderr, "config", err) return ExitRuntimeError } if err := writeApplicationWarnings(stderr, result.Diagnostics()); err != nil { return ExitRuntimeError } switch mode { case "validate": return ExitOK case "show": err = result.WriteEffective(stdout) case "sources": sources := make([]configurationSource, 0, len(result.Sources())) for _, source := range result.Sources() { sources = append(sources, configurationSource{ ID: source.ID, Label: source.Label, Layer: source.Layer, Path: source.Path, }) } err = json.NewEncoder(stdout).Encode(sources) case "explain": err = result.WriteExplanation(stdout, explanationPath) } if err != nil { fmt.Fprintf(stderr, "config output error: %v\n", err) return ExitRuntimeError } return ExitOK } func registerConfigurationOverrides(fs *flag.FlagSet) { fs.String("prompt-dir", "", "prompt-definition directory override") fs.String("profile-dir", "", "profile directory override") fs.String("schema-dir", "", "schema directory override") fs.String("addr", "", "HTTP listen address override") fs.String("artifact-root", "", "HTTP artifact root override") fs.Int64("max-request-bytes", 0, "HTTP request byte limit override") fs.Int64("max-artifact-bytes", 0, "HTTP artifact byte limit override") fs.Int64("max-response-bytes", 0, "HTTP response byte limit override") }