Files

147 lines
2.7 KiB
Go

package agent
import (
"encoding/json"
"fmt"
"io"
"strings"
"aego/project"
)
type cliFlags struct {
json bool
quiet bool
strict bool
}
func Usage(w io.Writer) {
fmt.Fprintln(w, "usage: aego <group> <verb> <args> [--json] [--dry-run] [--strict] [--quiet] [--project dir]")
fmt.Fprintln(w)
for _, c := range all {
fmt.Fprintf(w, " %-58s %s\n", c.Usage(), c.Doc)
}
}
func Main(p *project.Project, args []string, stdout, stderr io.Writer, opt Options) int {
if len(args) < 2 {
Usage(stderr)
return 2
}
if args[1] == "help" {
Usage(stdout)
return 0
}
c, ok := Find(args[0] + "." + args[1])
if !ok {
fmt.Fprintf(stderr, "aego: unknown command %s %s\n", args[0], args[1])
Usage(stderr)
return 2
}
a, f, err := parseArgs(c, args[2:])
if err == nil {
err = c.Check(a)
}
if err != nil {
fmt.Fprintln(stderr, "aego:", err)
fmt.Fprintln(stderr, "usage: aego "+c.Usage())
return 2
}
s, err := Open(p, opt)
if err != nil {
return report(stdout, stderr, f, nil, err)
}
defer s.Close()
out, err := Run(s, c.Name, a)
return report(stdout, stderr, f, out, err)
}
func parseArgs(c *Command, toks []string) (Args, cliFlags, error) {
var f cliFlags
a := Args{}
byName := map[string]Arg{}
var pos []Arg
for _, x := range c.AllArgs() {
byName[x.Name] = x
if x.Pos {
pos = append(pos, x)
}
}
var free []string
for i := 0; i < len(toks); i++ {
t := toks[i]
if t == "--" {
free = append(free, toks[i+1:]...)
break
}
if !strings.HasPrefix(t, "--") {
free = append(free, t)
continue
}
name, val, has := strings.Cut(t[2:], "=")
switch name {
case "json":
f.json = true
continue
case "quiet":
f.quiet = true
continue
case "strict":
f.strict = true
continue
case "project":
if !has {
i++
}
continue
}
x, ok := byName[name]
if !ok {
return nil, f, fmt.Errorf("unknown flag --%s", name)
}
if !has {
if x.Type == "boolean" {
val = "true"
} else {
if i+1 >= len(toks) {
return nil, f, fmt.Errorf("--%s needs a value", name)
}
i++
val = toks[i]
}
}
a[name] = val
}
if len(free) > len(pos) {
return nil, f, fmt.Errorf("too many arguments")
}
for i, v := range free {
a[pos[i].Name] = v
}
return a, f, nil
}
func report(stdout, stderr io.Writer, f cliFlags, out *Output, err error) int {
switch {
case f.json:
var v any = out
if err != nil {
v = map[string]any{"ok": false, "error": err.Error()}
}
enc := json.NewEncoder(stdout)
enc.SetIndent("", " ")
enc.Encode(v)
case err != nil:
fmt.Fprintln(stderr, "aego:", err)
case !f.quiet:
out.Print(stdout)
}
switch {
case err != nil:
return 1
case out.Errors(), f.strict && len(out.Problems) > 0:
return 2
}
return 0
}