From 67e5405745053061ce52d05ca5f89117d78ffc95 Mon Sep 17 00:00:00 2001 From: RSkeens Date: Thu, 30 Apr 2026 11:41:38 +0200 Subject: [PATCH] initial commit --- .github/workflows/tests.yml | 38 + .github/workflows/vulns.yml | 25 + LICENSE | 21 + README.md | 264 ++++++- SECURITY.md | 17 + assets/logo-dark.png | Bin 0 -> 64334 bytes assets/logo-light.png | Bin 0 -> 72501 bytes cli.go | 344 +++++++++ cli_test.go | 1028 ++++++++++++++++++++++++++ errs.go | 39 + example/cmd/hello-world/cli.go | 16 + example/cmd/hello-world/main.go | 26 + example/cmd/hello-world/main_test.go | 47 ++ example/pkg/cli/greet/cmd.go | 32 + example/pkg/cli/greet/cmd_test.go | 14 + example/pkg/cli/greet/greet.go | 25 + example/pkg/cli/greet/greet_test.go | 25 + example/pkg/cli/hello/cmd.go | 19 + example/pkg/cli/hello/cmd_test.go | 14 + example/pkg/cli/hello/hello.go | 17 + example/pkg/cli/hello/hello_test.go | 17 + example/pkg/cli/help/help.go | 19 + example_test.go | 58 ++ go.mod | 3 + help/help.go | 19 + 25 files changed, 2126 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/tests.yml create mode 100644 .github/workflows/vulns.yml create mode 100644 LICENSE create mode 100644 SECURITY.md create mode 100644 assets/logo-dark.png create mode 100644 assets/logo-light.png create mode 100644 cli.go create mode 100644 cli_test.go create mode 100644 errs.go create mode 100644 example/cmd/hello-world/cli.go create mode 100644 example/cmd/hello-world/main.go create mode 100644 example/cmd/hello-world/main_test.go create mode 100644 example/pkg/cli/greet/cmd.go create mode 100644 example/pkg/cli/greet/cmd_test.go create mode 100644 example/pkg/cli/greet/greet.go create mode 100644 example/pkg/cli/greet/greet_test.go create mode 100644 example/pkg/cli/hello/cmd.go create mode 100644 example/pkg/cli/hello/cmd_test.go create mode 100644 example/pkg/cli/hello/hello.go create mode 100644 example/pkg/cli/hello/hello_test.go create mode 100644 example/pkg/cli/help/help.go create mode 100644 example_test.go create mode 100644 go.mod create mode 100644 help/help.go diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..b178334 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,38 @@ +name: tests + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + test: + name: test (go ${{ matrix.go }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + go: ['1.21', '1.22', '1.23', '1.24', '1.25', 'stable'] + steps: + - uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go }} + check-latest: true + + - name: go vet + run: go vet ./... + + - name: staticcheck + uses: dominikh/staticcheck-action@v1 + with: + version: latest + install-go: false + + - name: go test + run: go test -race -count=1 ./... diff --git a/.github/workflows/vulns.yml b/.github/workflows/vulns.yml new file mode 100644 index 0000000..04b2947 --- /dev/null +++ b/.github/workflows/vulns.yml @@ -0,0 +1,25 @@ +name: vulns + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + govulncheck: + name: govulncheck + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 'stable' + check-latest: true + + - name: Run govulncheck + uses: golang/govulncheck-action@v1 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..47dbdf6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Roscoe Skeens + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 86b4125..4a8ba06 100644 --- a/README.md +++ b/README.md @@ -1 +1,263 @@ -# tidycli \ No newline at end of file +

+ + + + tidycli + +

+ +[![CI](https://github.com/RSkeens/tidycli/actions/workflows/tests.yml/badge.svg)](https://github.com/RSkeens/tidycli/actions/workflows/tests.yml) [![Go Reference](https://pkg.go.dev/badge/github.com/RSkeens/tidycli.svg)](https://pkg.go.dev/github.com/RSkeens/tidycli) ![GitHub License](https://img.shields.io/github/license/RSkeens/tidycli) [![Go Report Card](https://goreportcard.com/badge/github.com/RSkeens/tidycli)](https://goreportcard.com/report/github.com/RSkeens/tidycli) + +`tidycli` is a tiny and dependency free router for go clis that need subcommands +without adopting a rich framework. It provides cli handling without ceremony. + +As a positional subcommand router, there is no global state or opinionated +bootstrapping. It does all this in under 200 lines of executable code with +zero dependencies while getting out the way of stdlib `flag`. + +Prettier than stdlib, simpler than [urfave/cli](https://github.com/urfave/cli) +or [kong](https://github.com/alecthomas/kong) and less framework heavy +than [Cobra](https://github.com/spf13/cobra). `tidycli` focuses on excellent +defaults, clean help management, a tiny api surface and fast setup. + +Perfectly structured: + +- Positional subcommands. +- Stdlib `flag` compatibility. +- Zero dependencies. +- Explicit application wiring. +- Command functions that receive a context. +- Tiny API that is easy to read and vendor. + +Describe your cli as a tree of commands mapped by arg keyword. Built in per +command minimum arg enforcement and usage strings surfaced as errors. +It never dictates how your app should bootstrap, configure logging or parse +global flags. App state is supplied to commands by closing over it from +the caller package. + +## Install + +``` +go get github.com/rskeens/tidycli +``` + +## Smallest App + +The smallest useful `tidycli` app is one `Sub` map with one `Fn`: + +```go +package main + +import ( + "context" + "errors" + "flag" + "fmt" + "log" + + "github.com/rskeens/tidycli" +) + +var errHello = errors.New("usage: hello ") + +func main() { + flag.Parse() + + if err := tidycli.Run(context.Background(), tidycli.Sub{ + "hello": {Help: errHello, Min: 1, Fn: func(_ context.Context, args []string) error { + fmt.Println("hello,", args[0]) + + return nil + }}, + }); err != nil { + log.Fatal(err) + } +} +``` + +``` +$ go run . hello world +hello, world + +$ go run . hello +usage: hello +``` + +That is the entire api surface for a single level cli! A `Sub` keyed by arg, +`Help` error, `Min` count and `Fn`. Everything else in this readme is +about scaling that pattern up to nested commands and multi package layouts. + +## Comparison + +`tidycli` exists because alternatives are either too limited (stdlib `flag` +has no subcommand routing) or too opinionated (frameworks that own `main`, +the flag parser or help output). How it compares: + +| Feature | `tidycli` | stdlib `flag` | [`urfave/cli`][urfave] | [`kong`][kong] | [`cobra`][cobra] | +| --- | --- | --- | --- | --- | --- | +| Positional subcommand routing | ✅ | ❌ | ✅ | ✅ | ✅ | +| Works with stdlib `flag` | native | native | own parser | own parser | via [`pflag`][pflag] | +| Reflection / struct tags required | ❌ | ❌ | ❌ | ✅ | ❌ | +| Runtime deps | 0 | — | 0 | 0 | 4 | +| Implementation size | <200 LOC (`cli.go` + `errs.go`) | — | ~4,900 LOC across 42 files | ~5,500 LOC across 31 files | ~4,900 LOC across 19 files | +| Role | router | parser | framework | declarative parser | framework | + +Dependency counts are from current default branch `go.mod` `require` block, +excluding modules imported only from `_test.go` files. `tidycli`'s own `go.mod` +has an empty `require` block. + +Implementation size figures are measured with [`gocloc`](https://github.com/hhatto/gocloc) +over non test `.go` files (counting code lines only, excluding blanks and comments). +Intended as ballpark rather than exact totals. + +[urfave]: https://github.com/urfave/cli +[kong]: https://github.com/alecthomas/kong +[cobra]: https://github.com/spf13/cobra +[pflag]: https://github.com/spf13/pflag + +## Project Layout + +Example app at [`example/`](./example) is laid out using one package per command: + +``` +example/ +├── cmd/hello-world/ +│ ├── cli.go // cmds arg:cmd layout +│ └── main.go // entry +└── pkg/cli/ + ├── help/help.go // central usage errors + ├── hello/ + │ ├── cmd.go // hello.Cmd() returns *tidycli.Cmd + │ └── hello.go // hello.Do leaf + └── greet/ + ├── cmd.go // greet.Cmd() with Sub for hi / bye + └── greet.go // greet.Hi / greet.Bye leaves +``` + +`cmd/hello-world/cli.go` arg:command map: + +```go +// cmd/hello-world/cli.go +package main + +import ( + "github.com/rskeens/tidycli" + "github.com/rskeens/tidycli/example/pkg/cli/greet" + "github.com/rskeens/tidycli/example/pkg/cli/hello" +) + +// cmds stores arg:cmd layout. +var cmds = tidycli.Sub{ + "hello": hello.Cmd(), + "greet": greet.Cmd(), +} +``` + +`cmd/hello-world/main.go` wires `flag.Parse` to `tidycli.Run`: + +```go +// cmd/hello-world/main.go +package main + +import ( + "context" + "flag" + "log" + + "github.com/rskeens/tidycli" +) + +func main() { + flag.Parse() + + if err := tidycli.Run(context.Background(), cmds); err != nil { + log.Fatal(err) + } +} +``` + +Each command package exposes a `Cmd()` constructor which returns `*tidycli.Cmd` +alongside leaf functions: + +```go +// pkg/cli/hello/cmd.go +package hello + +import ( + "fmt" + + "github.com/rskeens/tidycli" + "github.com/rskeens/tidycli/example/pkg/cli/help" +) + +// Cmd returns the cmd. +func Cmd() *tidycli.Cmd { + return &tidycli.Cmd{ + Help: help.ErrHello, + Min: 1, + Fn: Do, + } +} + +// pkg/cli/hello/hello.go +func Do(_ context.Context, args []string) error { + fmt.Println("hello,", args[0]) + + return nil +} +``` + +Parents with subcommands keep `Sub` map inline in the same `Cmd()` constructor. + +Run: + +``` +go run ./example/cmd/hello-world hello world +go run ./example/cmd/hello-world greet hi alice +go run ./example/cmd/hello-world +``` + +## Concepts + +### Types + +| Type | Description | +|---------|-------------| +| `Cmd` | Single command node. | +| `Sub` | `map[string]*Cmd` describing one level of the command tree. | +| `Fn` | `func(ctx context.Context, args []string) error` called once routing to resolve leaf. Context passed from `Run` so commands can honour cancel and deadlines. To give a command access to app state, close over it when constructing `Fn`. | + +### `Cmd` Fields + +| Field | Description | +|---------|-------------| +| `Help` | Usage string returned as error when args are missing or command is non leaf. | +| `Min` | Minimum number of trailing args. | +| `Sub` | Command. | +| `Flags` | When non nil, `*flag.FlagSet` parsed against args once command resolves. | +| `Fn` | Invoked func. | + +### Routing and Execution + +| Call | Description | +|--------------------------|-------------| +| `Run(ctx, sub)` | Calls `sub.Route()` then `Fn` with `ctx` and trailing args. | + +### Invalid Returns + +| Result | Condition | +|-------------------|-----------| +| `ErrArgNone` | No args given. Returns without writing to stderr, caller decides how (or whether) to render usage. | +| `ErrArgInvalid` | Arg does not match (wrapped with unknown keyword). | +| Command's `Help` | Non leaf or fewer than `Min` args given. | + +`sub.Print()` writes usage to `os.Stdout`. `sub.Fprint(w)` writes to arbitrary +`io.Writer` (tests, redirection to stderr, etc). + +## Helps + +The [`help`](./help) subpackage offers small types (`Help`, `Helps`) for +apps which want to manage usage strings as a uniform collection. +Their use is optional. + +Hopefully this software can somehow bring a bit of peace to this troubled world. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..e5279f9 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,17 @@ +# Security Policy + +Security is considered of greater importance than any other aspect of my software. Any reported vulnerability, +regardless of severity is escalated to immediate priority. + +## Reporting a vulnerability + +Please send the report to `web@rskeens.com` + +We kindly request that you please **do not create a GitHub Issue** to report a security vulnerability. This policy +is out of respect for users of the affected version. + +While not required, a Proof of Concept or other instructions which detail how to reproduce would be immensely appreciated. + +You can expect a response within 24 hours. Feedback for security ideas or features is welcome. + +Full recognition will be given should the report be valid. \ No newline at end of file diff --git a/assets/logo-dark.png b/assets/logo-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..f1f3833ab5e0340baba130abba1313c9e7a9551f GIT binary patch literal 64334 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 z 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

    Z{IaxM9V51r4+2g1tB12s7SWZs1^kpGYqm5 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 literal 0 HcmV?d00001 diff --git a/cli.go b/cli.go new file mode 100644 index 0000000..11b3771 --- /dev/null +++ b/cli.go @@ -0,0 +1,344 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +// Package tidycli is a tiny and dependency free router for clis that need +// subcommands without adopting a framework. A minimal positional subcommand +// router rather than bloat. +// +// tidycli routes positional subcommands in under a couple hundred lines of +// code and stays out of the way of the standard library's [flag] package. +// +// Prettier than stdlib, simpler than urfave/cli or kong and less heavy than +// Cobra. A core focus on simplicity, excellent defaults, clean help output, +// tiny api surface and fast setup. +// +// A cmd is described as a tree of [Cmd] values keyed by arg in a [Sub]. +// Each leaf cmd is invoked through a [Fn], which receives [context.Context] +// and trailing arg slice. Every value in a [Sub] must be non nil [*Cmd]. +// +// Typical use: +// +// import ( +// "context" +// "errors" +// "flag" +// "fmt" +// "log" +// +// "github.com/rskeens/tidycli" +// ) +// +// cmds := tidycli.Sub{ +// "hello": { +// Help: errors.New("hello NAME"), +// Min: 1, +// Fn: func(ctx context.Context, args []string) error { +// fmt.Println("hello,", args[0]) +// return nil +// }, +// }, +// } +// +// flag.Parse() +// if err := tidycli.Run(context.Background(), cmds); err != nil { +// log.Fatal(err) +// } +// +// Per cmd flags are supported by attaching [flag.FlagSet] to a leaf [Cmd] +// via [Cmd.Flags]. That is parsed against trailing args before invoking +// [Cmd.Fn]. [Cmd.Flags] on non leaf commands are ignored. +// +// tidycli does not bootstrap, configure logging or parse global flags. +// Callers wire those concerns to fit their needs. +package tidycli + +import ( + "context" + "errors" + "flag" + "fmt" + "io" + "os" + "sort" +) + +// Fn is cmd func. Optional [context.Context] for cancel and deadline. +// Args follows cmd keyword per cmd flag parse. +type Fn func(ctx context.Context, args []string) error + +// Cmd represents single cmd in the cmd tree. +// +// Help is returned as err if cmd is invoked with fewer than min args or when +// cmd is non leaf (cmd with sub holds at least one entry) and descent stops +// there because no further args. Unknown subcmd at returns [ErrArgInvalid] +// instead of Help. The err is intentional, it lets callers propagate usage +// string. +// +// Sub, when non empty, makes this cmd a parent. Routing descends it when next +// arg matches key. Nil sub and non nil but empty sub are both treated as a +// leaf. Empty Sub{} on leaf cmd does not turn into parent. +// +// Fn, Min, and Flags only effect leaf cmds. If Sub is non empty then routing +// either descends into child or returns err (Help when descent stops at cmd, +// [ErrArgInvalid] when the next arg does not match child key), so parent's Fn +// is never invoked, its Min is never checked and the Flags are never parsed. +// Setting Fn, Min, or Flags alongside a non empty Sub is silently ignored, +// attach them to leaf instead. +// +// Flags, when non nil and set on leaf are parsed against trailing args when +// routing has resolved cmd. Remaining positional args are passed to Fn and +// counted against Min. Cmd vals are not mutated by routing. Flags is owned by +// the caller and may carry parsed vals after Run / Route returns. +// +// Flags must use [flag.ContinueOnError]. Routing relies on Parse returning +// errs to convert to Help. [Sub.RouteArgs] re applies [flag.ContinueOnError] +// via [flag.FlagSet.Init] before parsing, then restores prior error +// handling after Parse. FlagSet with [flag.ExitOnError] or +// [flag.PanicOnError] are downgraded for the duration of Parse rather than +// allowed to terminate proc. +// +// Fn invoked for leaf cmds after routing succeeds and arg count satisfies Min. +type Cmd struct { + Help error + Min int + Sub Sub + Flags *flag.FlagSet + Fn Fn +} + +// Sub represents arg keyword to cmd. Vals may not be nil. Routing treats nil +// [*Cmd] as [ErrCmdNil] without panic. +type Sub map[string]*Cmd + +// Run routes parsed args by stdlib [flag] package and on success invokes resolved +// cmd [Cmd.Fn] with ctx and trailing args. +// +// Thin wrapper around [RunArgs] that supplies [flag.Args], use [RunArgs] when +// integrating with alternative flag parser, embedded shell or test harness for +// custom arg slice. +// +// [Cmd] with nil [Cmd.Fn] returns [Cmd.Help] err without panic wrapped with [ErrCmdNoFn]. +func Run(ctx context.Context, sub Sub) error { + return RunArgs(ctx, sub, flag.Args()) +} + +// RunArgs is [Run] entry for given arg slice instead of [flag.Args]. +// Identical routing and [Cmd.Fn] invocation as [Run]. +func RunArgs(ctx context.Context, sub Sub, args []string) error { + cmd, rest, err := sub.RouteArgs(args) + if err != nil { + return err + } + + if cmd.Fn == nil { + return errors.Join(ErrCmdNoFn, help(cmd)) + } + + return cmd.Fn(ctx, rest) +} + +// Route resolves [flag.Args] against sub and returns leaf cmd with trailing +// positional args. Thin wrapper around [Sub.RouteArgs]. +func (sub Sub) Route() (*Cmd, []string, error) { + return sub.RouteArgs(flag.Args()) +} + +// RouteArgs resolves args against sub and returns leaf cmd with trailing +// positional arguments. Returns [Cmd.Help] err when cmd is non leaf with no further +// args to consume or when fewer than [Cmd.Min] trailing args. Returns [ErrArgNone] +// if args is empty and [ErrArgInvalid] when arg at any depth does not match +// cmd. If cmd has non nil [Cmd.Flags] then RouteArgs resets each flag to +// [flag.Flag.DefValue] and parses against trailing args. +// +// Reset relies on clean Value.Set(DefValue), which is reliable for stdlib +// [flag] scalar flag types but may not fully reset custom [flag.Value] whose +// Set accumulates state. Such flags should construct a new [flag.FlagSet] +// per invocation rather than rely on reset. Reset is skipped for any flag +// whose current [flag.Value.String] already equals [flag.Flag.DefValue], so +// custom Values that reject their own DefValue do not fail on the first +// invocation before user input is parsed. If [flag.Value.Set] returns err +// during reset then RouteArgs returns [ErrFlagReset] rather than silently +// leaking stale state. +// +// A [flag.ErrHelp] result from the user supplying -h or --help is reported +// as cmd [Cmd.Help] err. Other errs from [flag.FlagSet.Parse] are wrapped with +// [ErrFlagParse]. +// +// Before parsing, RouteArgs re applies [flag.ContinueOnError] to FlagSet via +// [flag.FlagSet.Init]: a FlagSet constructed with [flag.ExitOnError] or +// [flag.PanicOnError] would otherwise terminate the process from inside Parse +// on parse err or on -h / --help, bypassing RouteArgs's err reporting. The +// prior error handling is captured and restored after Parse so RouteArgs +// does not leave a silent side effect on the caller-owned FlagSet. +// +// RouteArgs does not mutate [Cmd] other than vals stored inside [Cmd.Flags] +// (caller owned) and does not read from global [flag.CommandLine]. Safe for +// alongside other flag parsers, embedded shells and parallel tests that don't +// share [Cmd.Flags] across goroutines. Performs no i/o of its own so callers +// are responsible for rendering errs (including [ErrArgNone]). +// +// Malformed cmd trees report as errs without panic. Nil [*Cmd] in sub or +// descendant [Sub] returns [ErrCmdNil] and routed cmd with [Cmd.Help] as nil when +// [Cmd.Help] would be returned returns [ErrCmdNoHelp]. +func (sub Sub) RouteArgs(args []string) (*Cmd, []string, error) { + if len(args) == 0 { + return nil, nil, ErrArgNone + } + + cmd, ok := sub[args[0]] + if !ok { + return nil, nil, fmt.Errorf("%w: %v", ErrArgInvalid, args[0]) + } + + if cmd == nil { + return nil, nil, fmt.Errorf("%w: %v", ErrCmdNil, args[0]) + } + + rest := args[1:] + + for len(cmd.Sub) > 0 && len(rest) > 0 { + next, ok := cmd.Sub[rest[0]] + if !ok { + // Distinguish typo from -h or empty descent. + return nil, nil, fmt.Errorf("%w: %v", ErrArgInvalid, rest[0]) + } + + if next == nil { + return nil, nil, fmt.Errorf("%w: %v", ErrCmdNil, rest[0]) + } + + cmd = next + rest = rest[1:] + } + + if len(cmd.Sub) > 0 { + return nil, nil, help(cmd) + } + + if cmd.Flags != nil { + // Reset each registered flag to default. Flag set on prev invocation + // does not silently leak into next one if reused. Round trip through + // Value.Set is expected to succeed for scalar flag types provided by + // stdlib. Custom flag.Value with Set rejects DefValue or accumulates + // state can still fail as [ErrFlagReset]. + // + // Skip flags if current Value already equals DefValue. On first + // invocation no prior parse has dirty state so reset is noop for well + // behaved Values, and custom flag.Value whose Set rejects its DefValue + // would fail before user input parse. + var ( + errReset error + resetName string + ) + + cmd.Flags.VisitAll(func(f *flag.Flag) { + if errReset != nil { + return + } + + if f.Value.String() == f.DefValue { + return + } + + if err := f.Value.Set(f.DefValue); err != nil { + errReset = err + resetName = f.Name + } + }) + + if errReset != nil { + return nil, nil, fmt.Errorf("%w: %s: %w", ErrFlagReset, resetName, errReset) + } + + // flag.FlagSet.Parse writes to fs.Output() (stderr by default) on parse + // err and -h / --help, emitting "Usage of :" plus flag defaults. + // RouteArgs has no own i/o. Err rendering to callers so silence FlagSet + // for Parse then restore writer. + // + // Restore is deferred for panic from custom flag.Value.Set. + prevOut := cmd.Flags.Output() + cmd.Flags.SetOutput(io.Discard) + defer cmd.Flags.SetOutput(prevOut) + + // Also capture prior error handling and restore it. + prevErrHandling := cmd.Flags.ErrorHandling() + cmd.Flags.Init(cmd.Flags.Name(), flag.ContinueOnError) + defer cmd.Flags.Init(cmd.Flags.Name(), prevErrHandling) + + if err := cmd.Flags.Parse(rest); err != nil { + // usage request, not a parse failure. Return cmd [Cmd.Help]. + if errors.Is(err, flag.ErrHelp) { + return nil, nil, help(cmd) + } + + return nil, nil, fmt.Errorf("%w: %w", ErrFlagParse, err) + } + + rest = cmd.Flags.Args() + } + + if len(rest) < cmd.Min { + return nil, nil, help(cmd) + } + + return cmd, rest, nil +} + +// help returns cmd.Help. Falls back to [ErrCmdNoHelp] if no [Cmd.Help]. Used wherever +// routing would return nil err in place of usage string. +func help(cmd *Cmd) error { + if cmd.Help == nil { + return ErrCmdNoHelp + } + + return cmd.Help +} + +// Print writes cmd keywords and Helps to stdout alphabetically. Thin +// wrapper around [Sub.Fprint] targets [os.Stdout]. Redirect of usage view +// should call [Sub.Fprint]. Any logo or trailing footer should print around it. +func (sub Sub) Print() error { + return sub.Fprint(os.Stdout) +} + +// Fprint writes cmd keywords and Helps to wr alphabetically. Each entry +// renders keyword on one line followed by Help on the next then separated +// from following entry by blank line. +// +// Nil [*Cmd] sub returns [ErrCmdNil] without panic. [Cmd] with nil [Cmd.Help] is +// rendered with placeholder line so keyword appears in usage view. +func (sub Sub) Fprint(wr io.Writer) error { + args := make([]string, 0, len(sub)) + + for arg := range sub { + args = append(args, arg) + } + + sort.Strings(args) + + for idx, arg := range args { + var ( + cmd = sub[arg] + sep = "" + ) + + if cmd == nil { + return fmt.Errorf("%w: %v", ErrCmdNil, arg) + } + + if idx > 0 { + sep = "\n" + } + + desc := any(cmd.Help) + if cmd.Help == nil { + desc = "(no help)" + } + + if _, err := fmt.Fprintf(wr, "%s%s\n%v\n", sep, arg, desc); err != nil { + return err + } + } + + return nil +} diff --git a/cli_test.go b/cli_test.go new file mode 100644 index 0000000..9183022 --- /dev/null +++ b/cli_test.go @@ -0,0 +1,1028 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +package tidycli + +import ( + "bytes" + "context" + "errors" + "flag" + "fmt" + "os" + "reflect" + "strings" + "testing" +) + +// input represents inputs. +type input struct { + err error + fn Fn +} + +// want represents wants. +type want struct { + err error + fn Fn + help error +} + +// errWriter represents [io.Writer] that always fails. Used for +// err return of [Sub.Fprint]. +type errWriter struct{} + +// resetRejVal represents [flag.Value] that accepts non-empty Set +// values and stores them, but returns err on Set with empty string +// (the DefValue for fs.Var registered with this type). Used to drive +// reset err path in [Sub.RouteArgs] after a prior parse has moved +// the flag value away from its default. +type resetRejVal struct { + err error + val string +} + +// panicVal represents [flag.Value] to panic. Used for deferred +// [flag.FlagSet.SetOutput] restore in [Sub.RouteArgs]. +type panicVal struct{} + +var mock = input{ + err: fmt.Errorf("mock"), + fn: Fn(nil), +} + +func (rej *resetRejVal) String() string { + if rej == nil { + return "" + } + + return rej.val +} + +func (rej *resetRejVal) Set(val string) error { + if val == "" { + return rej.err + } + + rej.val = val + + return nil +} + +func (panicVal) String() string { + return "" +} + +func (panicVal) Set(string) error { + panic("panic") +} + +// Write is the [errWriter] writer. +func (errWriter) Write([]byte) (int, error) { + return 0, mock.err +} + +// resetFlags replaces global [flag.CommandLine] and [os.Args] for +// tests without leaking state to other tests. Restores prev vals. +func resetFlags(t *testing.T, args []string) { + t.Helper() + + var ( + prevArgs = os.Args + prevFlag = flag.CommandLine + ) + + os.Args = append([]string{t.Name()}, args...) + + flag.CommandLine = flag.NewFlagSet(t.Name(), flag.ContinueOnError) + + t.Cleanup(func() { + os.Args = prevArgs + flag.CommandLine = prevFlag + }) + + flag.Parse() +} + +// newCmd is constructor for route table tests. +func newCmd(min int, sub Sub) *Cmd { + return &Cmd{ + Help: mock.err, + Min: min, + Sub: sub, + Fn: mock.fn, + } +} + +func TestRouteArgs(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + args []string + sub Sub + want *want + }{ + "none": { + args: nil, + + sub: Sub{}, + + want: &want{ + err: ErrArgNone, + }, + }, + + "single": { + args: []string{"mock"}, + + sub: Sub{ + "mock": { + Help: mock.err, + Fn: mock.fn, + }, + }, + + want: &want{ + err: nil, + fn: mock.fn, + help: mock.err, + }, + }, + + "single-under": { + args: []string{"mock"}, + + sub: Sub{ + "mock": newCmd( + 1, + + Sub{}, + ), + }, + + want: &want{ + err: mock.err, + fn: mock.fn, + help: mock.err, + }, + }, + + "nested": { + args: []string{"mock-a", "mock-b"}, + + sub: Sub{ + "mock-a": newCmd( + 1, + + Sub{ + "mock-b": { + Help: mock.err, + Min: 0, + Fn: mock.fn, + }, + }, + ), + }, + + want: &want{ + err: nil, + fn: mock.fn, + help: mock.err, + }, + }, + + "nested-under": { + args: []string{"mock-a", "mock-b"}, + + sub: Sub{ + "mock-a": newCmd( + 1, + + Sub{ + "mock-b": { + Help: mock.err, + Min: 1, + Fn: mock.fn, + }, + }, + ), + }, + + want: &want{ + err: mock.err, + fn: mock.fn, + help: mock.err, + }, + }, + } + + for name, test := range tests { + name, test := name, test + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got, _, err := test.sub.RouteArgs(test.args) + if !errors.Is(err, test.want.err) { + t.Errorf("unexpected route error %v, want %v", err, test.want.err) + } + + if got == nil { + return + } + + if fmt.Sprintf("%v", got.Fn) != fmt.Sprintf("%v", test.want.fn) { + t.Errorf("unexpected route fn %v, want %v", got.Fn, test.want.fn) + } + + if !errors.Is(got.Help, test.want.help) { + t.Errorf("unexpected route help %v, want %v", got.Help, test.want.help) + } + }) + } +} + +func TestRouteArgsErrInvalid(t *testing.T) { + t.Parallel() + + input := Sub{ + "actions": newCmd( + 1, + + Sub{ + "get": { + Help: mock.err, + Min: 1, + Fn: mock.fn, + }, + }, + ), + } + + if _, _, got := input.RouteArgs([]string{t.Name()}); !errors.Is(got, ErrArgInvalid) { + t.Errorf("unexpected route error %v, want %v", got, ErrArgInvalid) + } +} + +func TestRunArgs(t *testing.T) { + t.Parallel() + + var ( + called bool + + input = Sub{ + "install": { + Help: mock.err, + + Fn: func(context.Context, []string) error { + called = true + return nil + }, + }, + } + + got = RunArgs(context.Background(), input, []string{"install"}) + ) + + if got != nil { + t.Errorf("run error %v", got) + } + + if !called { + t.Errorf("expected fn invoke") + } +} + +func TestRunArgsRouteErr(t *testing.T) { + t.Parallel() + + if got := RunArgs(context.Background(), Sub{}, nil); !errors.Is(got, ErrArgNone) { + t.Errorf("unexpected run error %v, want %v", got, ErrArgNone) + } +} + +func TestPrint(t *testing.T) { + input := Sub{ + "1": { + Help: errors.New("desc-1"), + }, + + "2": { + Help: errors.New("desc-2"), + }, + } + + if err := input.Print(); err != nil { + t.Errorf("print error %v", err) + } +} + +func TestFprint(t *testing.T) { + t.Parallel() + + var ( + input = Sub{ + "2": { + Help: errors.New("desc-2"), + }, + + "1": { + Help: errors.New("desc-1"), + }, + } + + buf bytes.Buffer + + want = "1\ndesc-1\n\n2\ndesc-2\n" + ) + + if err := input.Fprint(&buf); err != nil { + t.Fatalf("fprint error %v", err) + } + + if got := buf.String(); got != want { + t.Errorf("unexpected fprint output\ngot: %q\nwant: %q", got, want) + } +} + +// TestRouteArgsEmptySubLeaf asserts non nil empty Sub does not turn +// leaf cmd into non leaf. Fn must be reachable and Min checked with +// trailing args. +func TestRouteArgsEmptySubLeaf(t *testing.T) { + t.Parallel() + + var ( + called bool + + input = Sub{ + "mock": { + Help: mock.err, + Sub: Sub{}, + Fn: func(context.Context, []string) error { + called = true + return nil + }, + }, + } + ) + + if err := RunArgs(context.Background(), input, []string{"mock"}); err != nil { + t.Fatalf("unexpected run error %v", err) + } + + if !called { + t.Errorf("expected fn invoke") + } +} + +// TestRouteArgsEmptyArgs asserts empty arg return [ErrArgNone] without i/o. +func TestRouteArgsEmptyArgs(t *testing.T) { + t.Parallel() + + input := Sub{ + "mock": {Help: mock.err}, + } + + if _, _, err := input.RouteArgs(nil); !errors.Is(err, ErrArgNone) { + t.Errorf("unexpected route error %v, want %v", err, ErrArgNone) + } +} + +// TestRunArgsNilFn asserts Run does not panic on bad leaf with nil +// Fn and instead return [ErrCmdNoFn]. +func TestRunArgsNilFn(t *testing.T) { + t.Parallel() + + var ( + input = Sub{ + "broken": { + Help: mock.err, + Fn: nil, + }, + } + + got = RunArgs(context.Background(), input, []string{"broken"}) + ) + + if !errors.Is(got, ErrCmdNoFn) { + t.Errorf("unexpected run error %v, want %v", got, ErrCmdNoFn) + } +} + +// TestRouteArgsFlags asserts per cmd flags are parsed and removed +// from trailing args before returned to caller. +func TestRouteArgsFlags(t *testing.T) { + t.Parallel() + + var ( + flags = flag.NewFlagSet(t.Name(), flag.ContinueOnError) + verbose = flags.Bool("v", false, "verbose") + + input = Sub{ + t.Name(): { + Help: mock.err, + Flags: flags, + Fn: mock.fn, + }, + } + ) + + got, args, err := input.RouteArgs([]string{t.Name(), "-v", "a"}) + if err != nil { + t.Fatalf("route error %v", err) + } + + if got == nil { + t.Fatal("expected cmd, got nil") + } + + if !*verbose { + t.Errorf("expected -v to be parsed, verbose=%v", *verbose) + } + + if len(args) != 1 || args[0] != "a" { + t.Errorf("unexpected trailing args %v, want [a]", args) + } +} + +// TestRouteArgsNoMutation asserts that routing does not mutate cmd +// vals across successive RouteArgs calls. +func TestRouteArgsNoMutation(t *testing.T) { + t.Parallel() + + var ( + leaf = &Cmd{ + Help: mock.err, + Min: 1, + Sub: Sub{}, + Fn: mock.fn, + } + + sub = Sub{ + "leaf": leaf, + } + + snap = *leaf + ) + + if _, _, err := sub.RouteArgs([]string{"leaf", "a"}); err != nil { + t.Fatalf("unexpected route error %v", err) + } + + if leaf.Min != snap.Min || + !errors.Is(leaf.Help, snap.Help) { + t.Errorf("cmd changed: got %+v, want %+v", *leaf, snap) + } + + if reflect.ValueOf(leaf.Sub).Pointer() != reflect.ValueOf(snap.Sub).Pointer() { + t.Errorf("sub changed: got %v, want %v", leaf.Sub, snap.Sub) + } +} + +// TestRouteArgsSubMiss asserts that descent stops when next arg is +// unknown. Token return wrapped [ErrArgInvalid] so callers can +// distinguish typo from usage req. +func TestRouteArgsSubMiss(t *testing.T) { + t.Parallel() + + input := Sub{ + "mock-a": newCmd( + 0, + + Sub{ + "mock-b": { + Help: mock.err, + Fn: mock.fn, + }, + }, + ), + } + + _, _, err := input.RouteArgs([]string{"mock-a", "mock-c"}) + + if !errors.Is(err, ErrArgInvalid) { + t.Errorf("unexpected route error %v, want %v", err, ErrArgInvalid) + } + + if err == nil || !strings.Contains(err.Error(), "mock-c") { + t.Errorf("expected error to mention offending token %q, got %v", "mock-c", err) + } +} + +// TestRouteArgsFlagsErr asserts err from [flag.FlagSet.Parse] is +// wrapped with [ErrFlagParse]. +func TestRouteArgsFlagsErr(t *testing.T) { + t.Parallel() + + flags := flag.NewFlagSet(t.Name(), flag.ContinueOnError) + flags.SetOutput(&bytes.Buffer{}) + flags.Bool("v", false, "verbose") + + input := Sub{ + t.Name(): { + Help: mock.err, + Flags: flags, + Fn: mock.fn, + }, + } + + _, _, got := input.RouteArgs([]string{t.Name(), "-no"}) + + if got == nil { + t.Fatalf("unexpected flag parse success") + } + + if !errors.Is(got, ErrFlagParse) { + t.Errorf("unexpected route error %v, want %v", got, ErrFlagParse) + } +} + +// TestRouteArgsFlagsResetErr asserts err returned by custom [flag.Value] +// Set pre parse reset returns [ErrFlagReset] wrapped with flag name and +// underlying Set err. +func TestRouteArgsFlagsResetErr(t *testing.T) { + t.Parallel() + + var ( + flags = flag.NewFlagSet(t.Name(), flag.ContinueOnError) + rej = &resetRejVal{err: mock.err} + ) + + flags.SetOutput(&bytes.Buffer{}) + flags.Var(rej, "tag", "tag") + flags.String("zone", "", "zone") + + input := Sub{ + t.Name(): { + Help: mock.err, + Flags: flags, + Fn: mock.fn, + }, + } + + // Dirty flag successful first parse so subsequent route attempts + // to reset back to DefValue. + if _, _, err := input.RouteArgs([]string{t.Name(), "-tag=x"}); err != nil { + t.Fatalf("unexpected first route error: %v", err) + } + + _, _, got := input.RouteArgs([]string{t.Name(), "a"}) + if got == nil { + t.Fatalf("unexpected flag reset success") + } + + if !errors.Is(got, ErrFlagReset) { + t.Errorf("unexpected route error %v, want %v", got, ErrFlagReset) + } + + if !errors.Is(got, mock.err) { + t.Errorf("expected underlying Set error to be wrapped, got %v", got) + } + + if !strings.Contains(got.Error(), "tag") { + t.Errorf("expected error to mention flag name %q, got %v", "tag", got) + } +} + +// TestRouteArgsFlagsReset asserts flag vals left over from prev +// RouteArgs are reset to defaults before next Parse. +func TestRouteArgsFlagsReset(t *testing.T) { + t.Parallel() + + var ( + flags = flag.NewFlagSet(t.Name(), flag.ContinueOnError) + verbose = flags.Bool("v", false, "verbose") + name = flags.String("name", "default", "name") + + input = Sub{ + t.Name(): { + Help: mock.err, + Flags: flags, + Fn: mock.fn, + }, + } + ) + + if _, _, got := input.RouteArgs([]string{t.Name(), "-v", "-name=alt", "a"}); got != nil { + t.Fatalf("unexpected route error %v", got) + } + + if !*verbose || *name != "alt" { + t.Fatalf("expected set flags, got verbose=%v name=%q", *verbose, *name) + } + + if _, _, got := input.RouteArgs([]string{t.Name(), "a"}); got != nil { + t.Fatalf("unexpected route error %v", got) + } + + if *verbose { + t.Errorf("expected -v to reset to false, got true") + } + + if *name != "default" { + t.Errorf("expected -name to reset to %q, got %q", "default", *name) + } +} + +// TestRouteArgsFlagsHelp asserts -h / --help on per cmd +// FlagSet returns cmd Help err instead of [flag.ErrHelp]. +func TestRouteArgsFlagsHelp(t *testing.T) { + t.Parallel() + + flags := flag.NewFlagSet(t.Name(), flag.ContinueOnError) + flags.SetOutput(&bytes.Buffer{}) + flags.Bool("v", false, "verbose") + + input := Sub{ + t.Name(): { + Help: mock.err, + Flags: flags, + Fn: mock.fn, + }, + } + + _, _, got := input.RouteArgs([]string{t.Name(), "-h"}) + + if !errors.Is(got, mock.err) { + t.Errorf("unexpected route error %v, want %v", got, mock.err) + } + + if errors.Is(got, ErrFlagParse) { + t.Errorf("flag.ErrHelp should not be wrapped with ErrFlagParse, got %v", got) + } +} + +// TestRouteArgsFlagsHelpNoHelp asserts -h on cmd with nil Help +// returns [ErrCmdNoHelp] instead of [flag.ErrHelp]. +func TestRouteArgsFlagsHelpNoHelp(t *testing.T) { + t.Parallel() + + flags := flag.NewFlagSet(t.Name(), flag.ContinueOnError) + flags.SetOutput(&bytes.Buffer{}) + flags.Bool("v", false, "verbose") + + input := Sub{ + t.Name(): { + Flags: flags, + Fn: mock.fn, + }, + } + + if _, _, got := input.RouteArgs([]string{t.Name(), "-h"}); !errors.Is(got, ErrCmdNoHelp) { + t.Errorf("unexpected route error %v, want %v", got, ErrCmdNoHelp) + } +} + +// TestRouteArgsFlagsSilent asserts RouteArgs performs no i/o when +// [flag.FlagSet.Parse] would otherwise emit usage to fs.Output(). +func TestRouteArgsFlagsSilent(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + args []string + }{ + { + "parse error", []string{t.Name(), "-err"}, + }, + + { + "help flag", []string{t.Name(), "-h"}, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + var ( + flags = flag.NewFlagSet(t.Name(), flag.ContinueOnError) + out = &bytes.Buffer{} + ) + + flags.SetOutput(out) + flags.Bool("v", false, "verbose") + + input := Sub{ + t.Name(): { + Help: mock.err, + Flags: flags, + Fn: mock.fn, + }, + } + + if _, _, err := input.RouteArgs(test.args); err == nil { + t.Fatalf("unexpected route success") + } + + if out.Len() != 0 { + t.Errorf("wrote %q output", out.String()) + } + + if flags.Output() != out { + t.Errorf("left flagset output as %v, want caller's writer restored", flags.Output()) + } + }) + } +} + +// TestRouteArgsFlagsExitOnErrorDowngrade asserts FlagSet with +// [flag.ExitOnError] is downgraded to [flag.ContinueOnError] before +// Parse, so parse err or -h / --help returns routing err instead of +// terminate proc, and the prior error handling is restored after +// Parse so the caller-owned FlagSet is not silently mutated. +func TestRouteArgsFlagsExitOnErrorDowngrade(t *testing.T) { + t.Parallel() + + flags := flag.NewFlagSet(t.Name(), flag.ExitOnError) + flags.SetOutput(&bytes.Buffer{}) + flags.Bool("v", false, "verbose") + + input := Sub{ + t.Name(): { + Help: mock.err, + Flags: flags, + Fn: mock.fn, + }, + } + + if _, _, got := input.RouteArgs([]string{t.Name(), "-nope"}); !errors.Is(got, ErrFlagParse) { + t.Errorf("unexpected route error %v, want %v", got, ErrFlagParse) + } + + if eh := flags.ErrorHandling(); eh != flag.ExitOnError { + t.Errorf("flagset ErrorHandling = %v, want %v restored after parse err", eh, flag.ExitOnError) + } + + if _, _, got := input.RouteArgs([]string{t.Name(), "-h"}); !errors.Is(got, mock.err) { + t.Errorf("unexpected route error %v, want %v", got, mock.err) + } + + if eh := flags.ErrorHandling(); eh != flag.ExitOnError { + t.Errorf("flagset ErrorHandling = %v, want %v restored after help", eh, flag.ExitOnError) + } +} + +// TestRouteArgsFlagsResetSkipDefault asserts that the pre parse reset +// is skipped for any flag whose Value already equals DefValue, so a +// custom flag.Value whose Set rejects its own DefValue does not fail +// on the first invocation before user input is parsed. +func TestRouteArgsFlagsResetSkipDefault(t *testing.T) { + t.Parallel() + + var ( + flags = flag.NewFlagSet(t.Name(), flag.ContinueOnError) + rej = &resetRejVal{err: mock.err} + ) + + flags.SetOutput(&bytes.Buffer{}) + flags.Var(rej, "tag", "tag") + + input := Sub{ + t.Name(): { + Help: mock.err, + Flags: flags, + Fn: mock.fn, + }, + } + + if _, _, err := input.RouteArgs([]string{t.Name(), "-tag=x"}); err != nil { + t.Fatalf("unexpected first route error: %v", err) + } +} + +// TestRouteArgsFlagsRestoreOnPanic asserts that caller FlagSet +// output writer is restored even if Parse panics, so to not +// silently pin FlagSet output to [io.Discard]. +func TestRouteArgsFlagsRestoreOnPanic(t *testing.T) { + t.Parallel() + + var ( + out = &bytes.Buffer{} + flags = flag.NewFlagSet(t.Name(), flag.ContinueOnError) + ) + + flags.SetOutput(out) + flags.Var(panicVal{}, "panic", "panics on Set") + + input := Sub{ + t.Name(): { + Help: mock.err, + Flags: flags, + Fn: mock.fn, + }, + } + + defer func() { + if ok := recover(); ok == nil { + t.Fatalf("expected panic") + } + + if flags.Output() != out { + t.Errorf("router left flagset output %v after panic, want writer restored", flags.Output()) + } + }() + + _, _, _ = input.RouteArgs([]string{t.Name(), "-panic=x"}) +} + +// TestFprintErr asserts write err propagates to caller. +func TestFprintErr(t *testing.T) { + t.Parallel() + + input := Sub{ + t.Name(): { + Help: mock.err, + }, + } + + if got := input.Fprint(errWriter{}); !errors.Is(got, mock.err) { + t.Errorf("unexpected fprint error %v, want %v", got, mock.err) + } +} + +// TestRouteArgsNilCmd asserts nil [*Cmd] in sub return [ErrCmdNil] +// instead of panic. +func TestRouteArgsNilCmd(t *testing.T) { + t.Parallel() + + input := Sub{t.Name(): nil} + + if _, _, got := input.RouteArgs([]string{t.Name()}); !errors.Is(got, ErrCmdNil) { + t.Errorf("unexpected route error %v, want %v", got, ErrCmdNil) + } +} + +// TestRouteArgsNilSubCmd asserts nil [*Cmd] during descent into +// parent Sub return [ErrCmdNil] instead of panic. +func TestRouteArgsNilSubCmd(t *testing.T) { + t.Parallel() + + input := Sub{ + "parent": newCmd( + 0, + + Sub{ + "child": nil, + }, + ), + } + + if _, _, got := input.RouteArgs([]string{"parent", "child"}); !errors.Is(got, ErrCmdNil) { + t.Errorf("unexpected route error %v, want %v", got, ErrCmdNil) + } +} + +// TestRouteArgsNilHelpNonLeaf asserts non leaf with nil Help +// returns [ErrCmdNoHelp] instead of nil. +func TestRouteArgsNilHelpNonLeaf(t *testing.T) { + t.Parallel() + + input := Sub{ + "parent": { + Sub: Sub{ + "child": { + Help: mock.err, + Fn: mock.fn, + }, + }, + }, + } + + if _, _, got := input.RouteArgs([]string{"parent"}); !errors.Is(got, ErrCmdNoHelp) { + t.Errorf("unexpected route error %v, want %v", got, ErrCmdNoHelp) + } +} + +// TestRouteArgsNilHelpUnderMin asserts leaf with nil Help with +// too few args return [ErrCmdNoHelp] instead of nil. +func TestRouteArgsNilHelpUnderMin(t *testing.T) { + t.Parallel() + + input := Sub{ + t.Name(): { + Min: 1, + Fn: mock.fn, + }, + } + + if _, _, got := input.RouteArgs([]string{t.Name()}); !errors.Is(got, ErrCmdNoHelp) { + t.Errorf("unexpected route error %v, want %v", got, ErrCmdNoHelp) + } +} + +// TestRunArgsNilFnNilHelp asserts leaf with both Fn and Help +// nil return [ErrCmdNoFn] joined with [ErrCmdNoHelp] instead of panic. +func TestRunArgsNilFnNilHelp(t *testing.T) { + t.Parallel() + + var ( + input = Sub{t.Name(): {}} + + got = RunArgs( + context.Background(), + input, + []string{t.Name()}, + ) + ) + + if !errors.Is(got, ErrCmdNoFn) { + t.Errorf("unexpected run error %v, want %v", got, ErrCmdNoFn) + } + + if !errors.Is(got, ErrCmdNoHelp) { + t.Errorf("unexpected run error %v, want %v", got, ErrCmdNoHelp) + } +} + +// TestFprintNilCmd asserts nil [*Cmd] in sub causes Fprint to +// return [ErrCmdNil] instead of panic. +func TestFprintNilCmd(t *testing.T) { + t.Parallel() + + input := Sub{t.Name(): nil} + + if err := input.Fprint(&bytes.Buffer{}); !errors.Is(err, ErrCmdNil) { + t.Errorf("unexpected fprint error %v, want %v", err, ErrCmdNil) + } +} + +// TestFprintNilHelp asserts cmd with nil Help shows placeholder +// instead of "". +func TestFprintNilHelp(t *testing.T) { + t.Parallel() + + var ( + input = Sub{ + "mock": {}, + } + + buf bytes.Buffer + want = "mock\n(no help)\n" + ) + + if err := input.Fprint(&buf); err != nil { + t.Fatalf("fprint error %v", err) + } + + if got := buf.String(); got != want { + t.Errorf("unexpected fprint output\ngot: %q\nwant: %q", got, want) + } +} + +// TestRun asserts [Run] dispatches to [RunArgs] using left over +// [flag.Parse] args. +func TestRun(t *testing.T) { + resetFlags(t, []string{"install"}) + + var ( + called bool + + input = Sub{ + "install": { + Help: mock.err, + + Fn: func(context.Context, []string) error { + called = true + return nil + }, + }, + } + ) + + if err := Run(context.Background(), input); err != nil { + t.Errorf("run error %v", err) + } + + if !called { + t.Errorf("expected fn invoke") + } +} + +// TestRoute asserts [Sub.Route] resolves [flag.Args] to matched +// leaf cmd. +func TestRoute(t *testing.T) { + resetFlags(t, []string{t.Name()}) + + input := Sub{ + t.Name(): { + Help: mock.err, + Fn: mock.fn, + }, + } + + got, _, err := input.Route() + if err != nil { + t.Fatalf("route error %v", err) + } + + if got == nil { + t.Fatal("expected resolved cmd, got nil") + } + + if !errors.Is(got.Help, mock.err) { + t.Errorf("unexpected route help %v, want %v", got.Help, mock.err) + } +} diff --git a/errs.go b/errs.go new file mode 100644 index 0000000..cd7be8a --- /dev/null +++ b/errs.go @@ -0,0 +1,39 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +package tidycli + +import "errors" + +var ( + // ErrArgNone means no specified args. + ErrArgNone = errors.New("tidycli: no args specified") + + // ErrArgInvalid means arg did not match command. Returned for + // unknown top level arg and any unknown token while descending + // sub command [Sub]. Wraps with offending token. + ErrArgInvalid = errors.New("tidycli: invalid arg specified") + + // ErrFlagParse means [flag.FlagSet.Parse] returned err while + // parsing [Cmd.Flags] against trailing args. Err from flag pkg is + // wrapped to distinguish parse failure from routing failure or [Fn] + // failure with [errors.Is]. + ErrFlagParse = errors.New("tidycli: flag parse failed") + + // ErrFlagReset means [flag.Value] returned err from [flag.Value.Set] when + // [Sub.RouteArgs] tried to restore it to default before parsing. + // Wrapped with offending flag name and the underlying [flag.Value.Set] error + // to distinguish reset failure from parse failure with [errors.Is]. + ErrFlagReset = errors.New("tidycli: flag reset failed") + + // ErrCmdNoFn means resolved leaf command [Cmd.Fn] is nil. + // Wraps with [Cmd.Help] to surface usage. + ErrCmdNoFn = errors.New("tidycli: command has no func") + + // ErrCmdNoHelp means routing wanted to return [Cmd.Help] but [Cmd.Help] was nil. + ErrCmdNoHelp = errors.New("tidycli: command has no help") + + // ErrCmdNil means [Sub] held nil [*Cmd] for key routing / rendering. + // [Sub] vals must not be nil. + ErrCmdNil = errors.New("tidycli: nil command") +) diff --git a/example/cmd/hello-world/cli.go b/example/cmd/hello-world/cli.go new file mode 100644 index 0000000..1206822 --- /dev/null +++ b/example/cmd/hello-world/cli.go @@ -0,0 +1,16 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +package main + +import ( + "github.com/rskeens/tidycli" + "github.com/rskeens/tidycli/example/pkg/cli/greet" + "github.com/rskeens/tidycli/example/pkg/cli/hello" +) + +// cmds stores arg:cmd layout. +var cmds = tidycli.Sub{ + "hello": hello.Cmd(), + "greet": greet.Cmd(), +} diff --git a/example/cmd/hello-world/main.go b/example/cmd/hello-world/main.go new file mode 100644 index 0000000..e7c3fb4 --- /dev/null +++ b/example/cmd/hello-world/main.go @@ -0,0 +1,26 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +// Command hello-world demonstrates a minimal tidycli app. +// One package per command. +// +// go run ./example/cmd/hello-world hello world +// go run ./example/cmd/hello-world greet hi alice +// go run ./example/cmd/hello-world # prints usage +package main + +import ( + "context" + "flag" + "log" + + "github.com/rskeens/tidycli" +) + +func main() { + flag.Parse() + + if err := tidycli.Run(context.Background(), cmds); err != nil { + log.Fatal(err) + } +} diff --git a/example/cmd/hello-world/main_test.go b/example/cmd/hello-world/main_test.go new file mode 100644 index 0000000..6dbaf1f --- /dev/null +++ b/example/cmd/hello-world/main_test.go @@ -0,0 +1,47 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +package main + +import ( + "flag" + "os" + "os/exec" + "testing" +) + +// TestMainHello drives main() with a valid command to assert that +// argument parsing and dispatch wire up correctly. +func TestMainHello(t *testing.T) { + prevArgs := os.Args + prevFlag := flag.CommandLine + + os.Args = []string{"hello-world", "hello", "world"} + flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError) + + t.Cleanup(func() { + os.Args = prevArgs + flag.CommandLine = prevFlag + }) + + main() +} + +// TestMainErr re-invokes the test binary as a subprocess so the +// log.Fatal branch in main() can be exercised without terminating the +// test runner itself. +func TestMainErr(t *testing.T) { + if os.Getenv("TIDYCLI_TEST_MAIN_ERR") == "1" { + os.Args = []string{"hello-world"} + flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError) + main() + return + } + + cmd := exec.Command(os.Args[0], "-test.run=TestMainErr") + cmd.Env = append(os.Environ(), "TIDYCLI_TEST_MAIN_ERR=1") + + if err := cmd.Run(); err == nil { + t.Errorf("expected subprocess to exit non-zero, got nil") + } +} diff --git a/example/pkg/cli/greet/cmd.go b/example/pkg/cli/greet/cmd.go new file mode 100644 index 0000000..56358b1 --- /dev/null +++ b/example/pkg/cli/greet/cmd.go @@ -0,0 +1,32 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +// Package greet implements "greet" parent command and "hi" / "bye" leaves. +package greet + +import ( + "github.com/rskeens/tidycli" + "github.com/rskeens/tidycli/example/pkg/cli/help" +) + +// Cmd returns cmd. +func Cmd() *tidycli.Cmd { + return &tidycli.Cmd{ + Help: help.ErrGreet, + Min: 1, + + Sub: tidycli.Sub{ + "hi": { + Help: help.ErrGreet, + Min: 1, + Fn: Hi, + }, + + "bye": { + Help: help.ErrGreet, + Min: 1, + Fn: Bye, + }, + }, + } +} diff --git a/example/pkg/cli/greet/cmd_test.go b/example/pkg/cli/greet/cmd_test.go new file mode 100644 index 0000000..2d71b71 --- /dev/null +++ b/example/pkg/cli/greet/cmd_test.go @@ -0,0 +1,14 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +package greet + +import "testing" + +func TestCmd(t *testing.T) { + t.Parallel() + + if Cmd() == nil { + t.Error("expected non nil cmd") + } +} diff --git a/example/pkg/cli/greet/greet.go b/example/pkg/cli/greet/greet.go new file mode 100644 index 0000000..4ed5b92 --- /dev/null +++ b/example/pkg/cli/greet/greet.go @@ -0,0 +1,25 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +package greet + +import ( + "context" + "fmt" +) + +// Hi prints "hi" greeting for given name. +// hello-world greet hi NAME +func Hi(_ context.Context, args []string) error { + _, err := fmt.Println("hi,", args[0]) + + return err +} + +// Bye prints "bye" farewell for given name. +// hello-world greet bye NAME +func Bye(_ context.Context, args []string) error { + _, err := fmt.Println("bye,", args[0]) + + return err +} diff --git a/example/pkg/cli/greet/greet_test.go b/example/pkg/cli/greet/greet_test.go new file mode 100644 index 0000000..0c03c51 --- /dev/null +++ b/example/pkg/cli/greet/greet_test.go @@ -0,0 +1,25 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +package greet + +import ( + "context" + "testing" +) + +func TestHi(t *testing.T) { + t.Parallel() + + if err := Hi(context.Background(), []string{"alice"}); err != nil { + t.Errorf("hi error %v", err) + } +} + +func TestBye(t *testing.T) { + t.Parallel() + + if err := Bye(context.Background(), []string{"alice"}); err != nil { + t.Errorf("bye error %v", err) + } +} diff --git a/example/pkg/cli/hello/cmd.go b/example/pkg/cli/hello/cmd.go new file mode 100644 index 0000000..785a03e --- /dev/null +++ b/example/pkg/cli/hello/cmd.go @@ -0,0 +1,19 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +// Package hello implements "hello" leaf command. +package hello + +import ( + "github.com/rskeens/tidycli" + "github.com/rskeens/tidycli/example/pkg/cli/help" +) + +// Cmd returns cmd. +func Cmd() *tidycli.Cmd { + return &tidycli.Cmd{ + Help: help.ErrHello, + Min: 1, + Fn: Do, + } +} diff --git a/example/pkg/cli/hello/cmd_test.go b/example/pkg/cli/hello/cmd_test.go new file mode 100644 index 0000000..f375d2f --- /dev/null +++ b/example/pkg/cli/hello/cmd_test.go @@ -0,0 +1,14 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +package hello + +import "testing" + +func TestCmd(t *testing.T) { + t.Parallel() + + if Cmd() == nil { + t.Error("expected non nil cmd") + } +} diff --git a/example/pkg/cli/hello/hello.go b/example/pkg/cli/hello/hello.go new file mode 100644 index 0000000..c1aeb70 --- /dev/null +++ b/example/pkg/cli/hello/hello.go @@ -0,0 +1,17 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +package hello + +import ( + "context" + "fmt" +) + +// Do prints greeting for given name. +// hello-world hello NAME +func Do(_ context.Context, args []string) error { + _, err := fmt.Println("hello,", args[0]) + + return err +} diff --git a/example/pkg/cli/hello/hello_test.go b/example/pkg/cli/hello/hello_test.go new file mode 100644 index 0000000..5c5bd45 --- /dev/null +++ b/example/pkg/cli/hello/hello_test.go @@ -0,0 +1,17 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +package hello + +import ( + "context" + "testing" +) + +func TestDo(t *testing.T) { + t.Parallel() + + if err := Do(context.Background(), []string{"world"}); err != nil { + t.Errorf("do error %v", err) + } +} diff --git a/example/pkg/cli/help/help.go b/example/pkg/cli/help/help.go new file mode 100644 index 0000000..af96c84 --- /dev/null +++ b/example/pkg/cli/help/help.go @@ -0,0 +1,19 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +// Package help centralises example apps's per command usage messages. +// +// Stored as exported errs lets each command package import only what it needs. +// Handed to [tidycli.Cmd.Help] without restating usage string at call site. +package help + +import "errors" + +// https://developers.google.com/style/code-syntax +var ( + // ErrHello means hello help. + ErrHello = errors.New("hello-world hello NAME") + + // ErrGreet means greet help. + ErrGreet = errors.New("hello-world greet { hi | bye } NAME") +) diff --git a/example_test.go b/example_test.go new file mode 100644 index 0000000..8efa90f --- /dev/null +++ b/example_test.go @@ -0,0 +1,58 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +package tidycli_test + +import ( + "context" + "errors" + "fmt" + + "github.com/rskeens/tidycli" +) + +// Example demonstrates min cmd tree routed through [tidycli.RunArgs]. +// "hello" cmd requires one positional arg and prints greeting. +func Example() { + cmds := tidycli.Sub{ + "hello": { + Help: errors.New("hello NAME"), + Min: 1, + + Fn: func(_ context.Context, args []string) error { + fmt.Println("hello,", args[0]) + + return nil + }, + }, + } + + if err := tidycli.RunArgs(context.Background(), cmds, []string{"hello", "world"}); err != nil { + fmt.Println("error:", err) + } + + // Output: hello, world +} + +// ExampleRunArgs demonstrates [tidycli.RunArgs]. Returns [tidycli.ErrArgInvalid] +// for unknown cmd keyword without proc exit. +func ExampleRunArgs() { + cmds := tidycli.Sub{ + "echo": { + Help: errors.New("echo TEXT"), + Min: 1, + + Fn: func(_ context.Context, args []string) error { + fmt.Println(args[0]) + + return nil + }, + }, + } + + err := tidycli.RunArgs(context.Background(), cmds, []string{"no"}) + + fmt.Println(errors.Is(err, tidycli.ErrArgInvalid)) + + // Output: true +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..995828c --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/rskeens/tidycli + +go 1.21 diff --git a/help/help.go b/help/help.go new file mode 100644 index 0000000..7e33cf4 --- /dev/null +++ b/help/help.go @@ -0,0 +1,19 @@ +// © Roscoe Skeens +// SPDX-License-Identifier: MIT + +// Package help provides helper types for usage messages. +// +// Convenience for apps needing uniform usage strings. +package help + +// Help describes a command's arg and usage. +// +// Desc is stored as err returned from [tidycli.Cmd.Help]. +// Propagates through normal err paths. +type Help struct { + Arg string + Desc error +} + +// Helps is collection of [Help] entries. +type Helps []Help