aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/alexflint/go-arg/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/alexflint/go-arg/README.md')
-rw-r--r--vendor/github.com/alexflint/go-arg/README.md552
1 files changed, 552 insertions, 0 deletions
diff --git a/vendor/github.com/alexflint/go-arg/README.md b/vendor/github.com/alexflint/go-arg/README.md
new file mode 100644
index 0000000..dab2996
--- /dev/null
+++ b/vendor/github.com/alexflint/go-arg/README.md
@@ -0,0 +1,552 @@
1<h1 align="center">
2 <img src="./.github/banner.jpg" alt="go-arg" height="250px">
3 <br>
4 go-arg
5 </br>
6</h1>
7<h4 align="center">Struct-based argument parsing for Go</h4>
8<p align="center">
9 <a href="https://sourcegraph.com/github.com/alexflint/go-arg?badge"><img src="https://sourcegraph.com/github.com/alexflint/go-arg/-/badge.svg" alt="Sourcegraph"></a>
10 <a href="https://pkg.go.dev/github.com/alexflint/go-arg"><img src="https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square" alt="Documentation"></a>
11 <a href="https://github.com/alexflint/go-arg/actions"><img src="https://github.com/alexflint/go-arg/workflows/Go/badge.svg" alt="Build Status"></a>
12 <a href="https://codecov.io/gh/alexflint/go-arg"><img src="https://codecov.io/gh/alexflint/go-arg/branch/master/graph/badge.svg" alt="Coverage Status"></a>
13 <a href="https://goreportcard.com/report/github.com/alexflint/go-arg"><img src="https://goreportcard.com/badge/github.com/alexflint/go-arg" alt="Go Report Card"></a>
14</p>
15<br>
16
17Declare command line arguments for your program by defining a struct.
18
19```go
20var args struct {
21 Foo string
22 Bar bool
23}
24arg.MustParse(&args)
25fmt.Println(args.Foo, args.Bar)
26```
27
28```shell
29$ ./example --foo=hello --bar
30hello true
31```
32
33### Installation
34
35```shell
36go get github.com/alexflint/go-arg
37```
38
39### Required arguments
40
41```go
42var args struct {
43 ID int `arg:"required"`
44 Timeout time.Duration
45}
46arg.MustParse(&args)
47```
48
49```shell
50$ ./example
51Usage: example --id ID [--timeout TIMEOUT]
52error: --id is required
53```
54
55### Positional arguments
56
57```go
58var args struct {
59 Input string `arg:"positional"`
60 Output []string `arg:"positional"`
61}
62arg.MustParse(&args)
63fmt.Println("Input:", args.Input)
64fmt.Println("Output:", args.Output)
65```
66
67```
68$ ./example src.txt x.out y.out z.out
69Input: src.txt
70Output: [x.out y.out z.out]
71```
72
73### Environment variables
74
75```go
76var args struct {
77 Workers int `arg:"env"`
78}
79arg.MustParse(&args)
80fmt.Println("Workers:", args.Workers)
81```
82
83```
84$ WORKERS=4 ./example
85Workers: 4
86```
87
88```
89$ WORKERS=4 ./example --workers=6
90Workers: 6
91```
92
93You can also override the name of the environment variable:
94
95```go
96var args struct {
97 Workers int `arg:"env:NUM_WORKERS"`
98}
99arg.MustParse(&args)
100fmt.Println("Workers:", args.Workers)
101```
102
103```
104$ NUM_WORKERS=4 ./example
105Workers: 4
106```
107
108You can provide multiple values using the CSV (RFC 4180) format:
109
110```go
111var args struct {
112 Workers []int `arg:"env"`
113}
114arg.MustParse(&args)
115fmt.Println("Workers:", args.Workers)
116```
117
118```
119$ WORKERS='1,99' ./example
120Workers: [1 99]
121```
122
123### Usage strings
124```go
125var args struct {
126 Input string `arg:"positional"`
127 Output []string `arg:"positional"`
128 Verbose bool `arg:"-v,--verbose" help:"verbosity level"`
129 Dataset string `help:"dataset to use"`
130 Optimize int `arg:"-O" help:"optimization level"`
131}
132arg.MustParse(&args)
133```
134
135```shell
136$ ./example -h
137Usage: [--verbose] [--dataset DATASET] [--optimize OPTIMIZE] [--help] INPUT [OUTPUT [OUTPUT ...]]
138
139Positional arguments:
140 INPUT
141 OUTPUT
142
143Options:
144 --verbose, -v verbosity level
145 --dataset DATASET dataset to use
146 --optimize OPTIMIZE, -O OPTIMIZE
147 optimization level
148 --help, -h print this help message
149```
150
151### Default values
152
153```go
154var args struct {
155 Foo string `default:"abc"`
156 Bar bool
157}
158arg.MustParse(&args)
159```
160
161### Default values (before v1.2)
162
163```go
164var args struct {
165 Foo string
166 Bar bool
167}
168arg.Foo = "abc"
169arg.MustParse(&args)
170```
171
172### Combining command line options, environment variables, and default values
173
174You can combine command line arguments, environment variables, and default values. Command line arguments take precedence over environment variables, which take precedence over default values. This means that we check whether a certain option was provided on the command line, then if not, we check for an environment variable (only if an `env` tag was provided), then if none is found, we check for a `default` tag containing a default value.
175
176```go
177var args struct {
178 Test string `arg:"-t,env:TEST" default:"something"`
179}
180arg.MustParse(&args)
181```
182
183### Arguments with multiple values
184```go
185var args struct {
186 Database string
187 IDs []int64
188}
189arg.MustParse(&args)
190fmt.Printf("Fetching the following IDs from %s: %q", args.Database, args.IDs)
191```
192
193```shell
194./example -database foo -ids 1 2 3
195Fetching the following IDs from foo: [1 2 3]
196```
197
198### Arguments that can be specified multiple times, mixed with positionals
199```go
200var args struct {
201 Commands []string `arg:"-c,separate"`
202 Files []string `arg:"-f,separate"`
203 Databases []string `arg:"positional"`
204}
205arg.MustParse(&args)
206```
207
208```shell
209./example -c cmd1 db1 -f file1 db2 -c cmd2 -f file2 -f file3 db3 -c cmd3
210Commands: [cmd1 cmd2 cmd3]
211Files [file1 file2 file3]
212Databases [db1 db2 db3]
213```
214
215### Arguments with keys and values
216```go
217var args struct {
218 UserIDs map[string]int
219}
220arg.MustParse(&args)
221fmt.Println(args.UserIDs)
222```
223
224```shell
225./example --userids john=123 mary=456
226map[john:123 mary:456]
227```
228
229### Custom validation
230```go
231var args struct {
232 Foo string
233 Bar string
234}
235p := arg.MustParse(&args)
236if args.Foo == "" && args.Bar == "" {
237 p.Fail("you must provide either --foo or --bar")
238}
239```
240
241```shell
242./example
243Usage: samples [--foo FOO] [--bar BAR]
244error: you must provide either --foo or --bar
245```
246
247### Version strings
248
249```go
250type args struct {
251 ...
252}
253
254func (args) Version() string {
255 return "someprogram 4.3.0"
256}
257
258func main() {
259 var args args
260 arg.MustParse(&args)
261}
262```
263
264```shell
265$ ./example --version
266someprogram 4.3.0
267```
268
269### Overriding option names
270
271```go
272var args struct {
273 Short string `arg:"-s"`
274 Long string `arg:"--custom-long-option"`
275 ShortAndLong string `arg:"-x,--my-option"`
276 OnlyShort string `arg:"-o,--"`
277}
278arg.MustParse(&args)
279```
280
281```shell
282$ ./example --help
283Usage: example [-o ONLYSHORT] [--short SHORT] [--custom-long-option CUSTOM-LONG-OPTION] [--my-option MY-OPTION]
284
285Options:
286 --short SHORT, -s SHORT
287 --custom-long-option CUSTOM-LONG-OPTION
288 --my-option MY-OPTION, -x MY-OPTION
289 -o ONLYSHORT
290 --help, -h display this help and exit
291```
292
293
294### Embedded structs
295
296The fields of embedded structs are treated just like regular fields:
297
298```go
299
300type DatabaseOptions struct {
301 Host string
302 Username string
303 Password string
304}
305
306type LogOptions struct {
307 LogFile string
308 Verbose bool
309}
310
311func main() {
312 var args struct {
313 DatabaseOptions
314 LogOptions
315 }
316 arg.MustParse(&args)
317}
318```
319
320As usual, any field tagged with `arg:"-"` is ignored.
321
322### Supported types
323
324The following types may be used as arguments:
325- built-in integer types: `int, int8, int16, int32, int64, byte, rune`
326- built-in floating point types: `float32, float64`
327- strings
328- booleans
329- URLs represented as `url.URL`
330- time durations represented as `time.Duration`
331- email addresses represented as `mail.Address`
332- MAC addresses represented as `net.HardwareAddr`
333- pointers to any of the above
334- slices of any of the above
335- maps using any of the above as keys and values
336- any type that implements `encoding.TextUnmarshaler`
337
338### Custom parsing
339
340Implement `encoding.TextUnmarshaler` to define your own parsing logic.
341
342```go
343// Accepts command line arguments of the form "head.tail"
344type NameDotName struct {
345 Head, Tail string
346}
347
348func (n *NameDotName) UnmarshalText(b []byte) error {
349 s := string(b)
350 pos := strings.Index(s, ".")
351 if pos == -1 {
352 return fmt.Errorf("missing period in %s", s)
353 }
354 n.Head = s[:pos]
355 n.Tail = s[pos+1:]
356 return nil
357}
358
359func main() {
360 var args struct {
361 Name NameDotName
362 }
363 arg.MustParse(&args)
364 fmt.Printf("%#v\n", args.Name)
365}
366```
367```shell
368$ ./example --name=foo.bar
369main.NameDotName{Head:"foo", Tail:"bar"}
370
371$ ./example --name=oops
372Usage: example [--name NAME]
373error: error processing --name: missing period in "oops"
374```
375
376### Custom parsing with default values
377
378Implement `encoding.TextMarshaler` to define your own default value strings:
379
380```go
381// Accepts command line arguments of the form "head.tail"
382type NameDotName struct {
383 Head, Tail string
384}
385
386func (n *NameDotName) UnmarshalText(b []byte) error {
387 // same as previous example
388}
389
390// this is only needed if you want to display a default value in the usage string
391func (n *NameDotName) MarshalText() ([]byte, error) {
392 return []byte(fmt.Sprintf("%s.%s", n.Head, n.Tail)), nil
393}
394
395func main() {
396 var args struct {
397 Name NameDotName `default:"file.txt"`
398 }
399 arg.MustParse(&args)
400 fmt.Printf("%#v\n", args.Name)
401}
402```
403```shell
404$ ./example --help
405Usage: test [--name NAME]
406
407Options:
408 --name NAME [default: file.txt]
409 --help, -h display this help and exit
410
411$ ./example
412main.NameDotName{Head:"file", Tail:"txt"}
413```
414
415### Custom placeholders
416
417*Introduced in version 1.3.0*
418
419Use the `placeholder` tag to control which placeholder text is used in the usage text.
420
421```go
422var args struct {
423 Input string `arg:"positional" placeholder:"SRC"`
424 Output []string `arg:"positional" placeholder:"DST"`
425 Optimize int `arg:"-O" help:"optimization level" placeholder:"LEVEL"`
426 MaxJobs int `arg:"-j" help:"maximum number of simultaneous jobs" placeholder:"N"`
427}
428arg.MustParse(&args)
429```
430```shell
431$ ./example -h
432Usage: example [--optimize LEVEL] [--maxjobs N] SRC [DST [DST ...]]
433
434Positional arguments:
435 SRC
436 DST
437
438Options:
439 --optimize LEVEL, -O LEVEL
440 optimization level
441 --maxjobs N, -j N maximum number of simultaneous jobs
442 --help, -h display this help and exit
443```
444
445### Description strings
446
447```go
448type args struct {
449 Foo string
450}
451
452func (args) Description() string {
453 return "this program does this and that"
454}
455
456func main() {
457 var args args
458 arg.MustParse(&args)
459}
460```
461
462```shell
463$ ./example -h
464this program does this and that
465Usage: example [--foo FOO]
466
467Options:
468 --foo FOO
469 --help, -h display this help and exit
470```
471
472### Subcommands
473
474*Introduced in version 1.1.0*
475
476Subcommands are commonly used in tools that wish to group multiple functions into a single program. An example is the `git` tool:
477```shell
478$ git checkout [arguments specific to checking out code]
479$ git commit [arguments specific to committing]
480$ git push [arguments specific to pushing]
481```
482
483The strings "checkout", "commit", and "push" are different from simple positional arguments because the options available to the user change depending on which subcommand they choose.
484
485This can be implemented with `go-arg` as follows:
486
487```go
488type CheckoutCmd struct {
489 Branch string `arg:"positional"`
490 Track bool `arg:"-t"`
491}
492type CommitCmd struct {
493 All bool `arg:"-a"`
494 Message string `arg:"-m"`
495}
496type PushCmd struct {
497 Remote string `arg:"positional"`
498 Branch string `arg:"positional"`
499 SetUpstream bool `arg:"-u"`
500}
501var args struct {
502 Checkout *CheckoutCmd `arg:"subcommand:checkout"`
503 Commit *CommitCmd `arg:"subcommand:commit"`
504 Push *PushCmd `arg:"subcommand:push"`
505 Quiet bool `arg:"-q"` // this flag is global to all subcommands
506}
507
508arg.MustParse(&args)
509
510switch {
511case args.Checkout != nil:
512 fmt.Printf("checkout requested for branch %s\n", args.Checkout.Branch)
513case args.Commit != nil:
514 fmt.Printf("commit requested with message \"%s\"\n", args.Commit.Message)
515case args.Push != nil:
516 fmt.Printf("push requested from %s to %s\n", args.Push.Branch, args.Push.Remote)
517}
518```
519
520Some additional rules apply when working with subcommands:
521* The `subcommand` tag can only be used with fields that are pointers to structs
522* Any struct that contains a subcommand must not contain any positionals
523
524This package allows to have a program that accepts subcommands, but also does something else
525when no subcommands are specified.
526If on the other hand you want the program to terminate when no subcommands are specified,
527the recommended way is:
528
529```go
530p := arg.MustParse(&args)
531if p.Subcommand() == nil {
532 p.Fail("missing subcommand")
533}
534```
535
536### API Documentation
537
538https://godoc.org/github.com/alexflint/go-arg
539
540### Rationale
541
542There are many command line argument parsing libraries for Go, including one in the standard library, so why build another?
543
544The `flag` library that ships in the standard library seems awkward to me. Positional arguments must preceed options, so `./prog x --foo=1` does what you expect but `./prog --foo=1 x` does not. It also does not allow arguments to have both long (`--foo`) and short (`-f`) forms.
545
546Many third-party argument parsing libraries are great for writing sophisticated command line interfaces, but feel to me like overkill for a simple script with a few flags.
547
548The idea behind `go-arg` is that Go already has an excellent way to describe data structures using structs, so there is no need to develop additional levels of abstraction. Instead of one API to specify which arguments your program accepts, and then another API to get the values of those arguments, `go-arg` replaces both with a single struct.
549
550### Backward compatibility notes
551
552Earlier versions of this library required the help text to be part of the `arg` tag. This is still supported but is now deprecated. Instead, you should use a separate `help` tag, described above, which removes most of the limits on the text you can write. In particular, you will need to use the new `help` tag if your help text includes any commas.