33[ ![ GoDoc] ( https://godoc.org/github.com/mfridman/cli?status.svg )] ( https://pkg.go.dev/github.com/mfridman/cli#section-documentation )
44[ ![ CI] ( https://github.com/mfridman/cli/actions/workflows/ci.yaml/badge.svg )] ( https://github.com/mfridman/cli/actions/workflows/ci.yaml )
55
6- A Go framework for building CLI applications with flexible flag placement . Extends the standard
7- library's ` flag ` package to support [ flags
8- anywhere ] ( https://mfridman.com/blog/2024/allowing-flags-anywhere-on-the-cli/ ) in command arguments.
6+ A Go framework for building CLI applications. Extends the standard library's ` flag ` package to
7+ support [ flags anywhere ] ( https://mfridman.com/blog/2024/allowing-flags-anywhere-on-the-cli/ ) in
8+ command arguments.
99
1010## Features
1111
12+ The ** bare minimum** to build a CLI application while leveraging the standard library's ` flag `
13+ package.
14+
1215- Nested subcommands for organizing complex CLIs
1316- Flexible flag parsing, allowing flags anywhere
1417- Subcommands inherit flags from parent commands
1518- Type-safe flag access
1619- Automatic generation of help text and usage information
1720- Suggestions for misspelled or incomplete commands
1821
19- And that's it! It's the ** bare minimum to build a CLI application** while leveraging the standard
20- library's ` flag ` package.
21-
2222### But why?
2323
24- This framework embraces minimalism while maintaining functionality. It provides essential building
25- blocks for CLI applications without the bloat, allowing you to:
24+ This framework is intentionally minimal. It aims to be a building block for CLI applications that
25+ want to leverage the standard library's ` flag ` package while providing a bit more structure and
26+ flexibility.
2627
2728- Build maintainable command-line tools quickly
2829- Focus on application logic rather than framework complexity
@@ -46,7 +47,7 @@ Here's a simple example of a CLI application that echoes back the input:
4647``` go
4748root := &cli.Command {
4849 Name : " echo" ,
49- Usage : " echo <text...> [flags] " ,
50+ Usage : " echo [flags] <text> ..." ,
5051 ShortHelp : " echo is a simple command that prints the provided text" ,
5152 Flags : cli.FlagsFunc (func (f *flag.FlagSet ) {
5253 // Add a flag to capitalize the input
@@ -57,8 +58,7 @@ root := &cli.Command{
5758 },
5859 Exec : func (ctx context.Context , s *cli.State ) error {
5960 if len (s.Args ) == 0 {
60- // Return a new error with the error code ErrShowHelp
61- return fmt.Errorf (" no text provided" )
61+ return errors.New (" must provide text to echo, see --help" )
6262 }
6363 output := strings.Join (s.Args , " " )
6464 // If -c flag is set, capitalize the output
@@ -69,8 +69,7 @@ root := &cli.Command{
6969 return nil
7070 },
7171}
72- err := cli.ParseAndRun (context.Background (), root, os.Args [1 :], nil )
73- if err != nil {
72+ if err := cli.ParseAndRun (context.Background (), root, os.Args [1 :], nil ); err != nil {
7473 if errors.Is (err, flag.ErrHelp ) {
7574 return
7675 }
@@ -88,7 +87,7 @@ Each command in your CLI application is represented by a `Command` struct:
8887
8988``` go
9089type Command struct {
91- Name string
90+ Name string // Required
9291 Usage string
9392 ShortHelp string
9493 UsageFunc func (*Command) string
@@ -103,8 +102,7 @@ The `Name` field is the command's name and is **required**.
103102
104103The ` Usage ` and ` ShortHelp ` fields are used to generate help text. Nice-to-have but not required.
105104
106- The ` Flags ` field is a ` *flag.FlagSet ` that defines the command's flags. The ` SubCommands ` field is
107- a slice of child commands.
105+ The ` Flags ` field is a ` *flag.FlagSet ` that defines the command's flags.
108106
109107> [ !TIP]
110108>
@@ -124,8 +122,12 @@ root := &cli.Command{
124122```
125123
126124The ` FlagsMetadata ` field is a slice of ` FlagMetadata ` structs that define metadata for each flag.
127- Unfortunatly, the ` flag.FlagSet ` package alone is a bit limiting, so this package adds a layer on
128- top to provide the most common features.
125+ Unfortunatly, the ` flag ` package alone is a bit limiting, so this package adds a layer on top to
126+ provide the most common features, such as automatic handling of required flags.
127+
128+ The ` SubCommands ` field is a slice of ` *Command ` structs that represent subcommands. This allows you
129+ to organize your CLI application into a hierarchy of commands. Each subcommand can have its own
130+ flags and business logic.
129131
130132The ` Exec ` field is a function that is called when the command is executed. This is where you put
131133your business logic.
@@ -137,10 +139,8 @@ Flags can be accessed using the type-safe `GetFlag` function, called inside your
137139``` go
138140// Access boolean flag
139141verbose := cli.GetFlag [bool ](state, " verbose" )
140-
141142// Access string flag
142143output := cli.GetFlag [string ](state, " output" )
143-
144144// Access integer flag
145145count := cli.GetFlag [int ](state, " count" )
146146```
@@ -183,36 +183,45 @@ When reading command usage strings, the following syntax is used:
183183| ------------- | -------------------------- |
184184| ` <required> ` | Required argument |
185185| ` [optional] ` | Optional argument |
186- | ` <arg...> ` | One or more arguments |
187- | ` [arg...] ` | Zero or more arguments |
186+ | ` <arg> ... ` | One or more arguments |
187+ | ` [arg] ... ` | Zero or more arguments |
188188| ` (a\|b) ` | Must choose one of a or b |
189189| ` [-f <file>] ` | Flag with value (optional) |
190190| ` -f <file> ` | Flag with value (required) |
191191
192192Examples:
193193
194194``` bash
195- # Two required arguments
196- copy < source> < dest>
197- # Zero or more paths
198- ls [path...]
199- # Optional flag with value, required host
200- ssh [-p < port> ] < user@host>
201- # Required subcommand, optional remote
202- git (pull| push) [remote]
195+ # Multiple source files, one destination
196+ mv < source> ... < dest>
197+
198+ # Required flag with value, optional config
199+ build -t < tag> [config]...
200+
201+ # Subcommands with own flags
202+ docker (run| build) [--file < dockerfile> ] < image>
203+
204+ # Multiple flag values
205+ find [--exclude < pattern> ]... < path>
206+
207+ # Choice between options, required path
208+ chmod (u+x| a+r) < file> ...
209+
210+ # Flag groups with value
211+ kubectl [-n < namespace> ] (get| delete) (pod| service) < name>
203212```
204213
205214## Status
206215
207- This project is in active development and undergoing changes as the API is refined. Please open an
216+ This project is in active development and undergoing changes as the API gets refined. Please open an
208217issue if you encounter any problems or have suggestions for improvement.
209218
210219- [x] Nail down required flags implementation
211- - [ ] Add tests for typos and command suggestions, crude levenstein distance for now
212- - [ ] Internal implementation (not user-facing), track selected ` *Command ` in ` *State ` and remove
220+ - [x ] Add tests for typos and command suggestions, crude levenstein distance for now
221+ - [x ] Internal implementation (not user-facing), track selected ` *Command ` in ` *State ` and remove
213222 ` flags *flag.FlagSet ` from ` *State `
214- - [ ] Figure out whether to keep ` *Error ` and whether to catch ` ErrShowHelp ` in ` ParseAndRun `
215- - [ ] Should ` Parse ` , ` Run ` and ` ParseAndRun ` be methods on ` *Command ` ?
223+ - [x ] Figure out whether to keep ` *Error ` and whether to catch ` ErrShowHelp ` in ` ParseAndRun `
224+ - [x ] Should ` Parse ` , ` Run ` and ` ParseAndRun ` be methods on ` *Command ` ? No.
216225- [ ] What to do with ` showHelp() ` , should it be a standalone function or an exported method on
217226 ` *Command ` ?
218227- [ ] Is there room for ` clihelp ` package for standalone use?
@@ -224,7 +233,7 @@ needs](https://mfridman.com/blog/2021/a-simpler-building-block-for-go-clis/).
224233
225234I was inspired by Peter Bourgon's [ ff] ( https://github.com/peterbourgon/ff ) library, specifically the
226235` v3 ` branch, which was soooo close to what I wanted. But the ` v4 ` branch took a different direction
227- and I wanted to keep the simplicity of the ` v3 ` branch. This library aims to pick up where ` ff/ v3`
236+ and I wanted to keep the simplicity of the ` v3 ` branch. This library aims to pick up where the ` v3 `
228237left off.
229238
230239## License
0 commit comments