Codebase list golang-github-jawher-mow.cli / 7c33c23
Import upstream version 1.2.0 Kali Janitor 2 years ago
26 changed file(s) with 490 addition(s) and 179 deletion(s). Raw diff Collapse all Expand all
0 name: CI
1
2 on: push
3
4 jobs:
5 test:
6 strategy:
7 matrix:
8 go: ["1.12", "1.13", "1.14"]
9 runs-on: ubuntu-latest
10 steps:
11 - name: Set up Go ${{ matrix.go }}
12 uses: actions/setup-go@v1
13 with:
14 go-version: ${{ matrix.go }}
15 id: go
16 - name: Checkout the code
17 uses: actions/checkout@v2
18
19 - name: Test with Go ${{ matrix.go }}
20 run: go test -v -coverprofile=profile.cov ./...
21
22 - name: Send coverage with Go ${{ matrix.go }}
23 uses: shogo82148/actions-goveralls@v1
24 with:
25 path-to-profile: profile.cov
26 flag-name: Go-${{ matrix.go }}
27 parallel: true
28
29 lint:
30 runs-on: ubuntu-latest
31 steps:
32 - name: Checkout the code
33 uses: actions/checkout@v2
34
35 - name: Set up Go
36 uses: actions/setup-go@v1
37 with:
38 go-version: 1.14
39 id: go
40
41 - name: lint
42 uses: golangci/golangci-lint-action@v1
43 with:
44 version: v1.28
45
46 readme:
47 runs-on: ubuntu-latest
48 steps:
49 - name: Set up Go
50 uses: actions/setup-go@v1
51 with:
52 go-version: 1.14
53 id: go
54
55
56 - name: Checkout the code
57 uses: actions/checkout@v2
58
59 - name: Set GOPATH
60 run: echo ::set-env name=GOPATH::$GITHUB_WORKSPACE/go
61
62 - name: Readme Check
63 run: export PATH="$GOPATH/bin:$PATH"; make readmecheck.setup readmecheck
64
65 finish:
66 needs: test
67 runs-on: ubuntu-latest
68 steps:
69 - uses: shogo82148/actions-goveralls@v1
70 with:
71 parallel-finished: true
0 name: Release
1
2 # Triggered only when a tag is pushed
3 on:
4 push:
5 branches:
6 - "!*"
7 tags:
8 - "v*"
9 jobs:
10 release:
11 runs-on: ubuntu-latest
12 name: Release
13 steps:
14 - name: Check out code
15 uses: actions/checkout@v2
16 with:
17 fetch-depth: 0
18
19 - name: Release the application
20 uses: goreleaser/goreleaser-action@v2
21 with:
22 args: release --rm-dist
23 env:
24 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
0 project_name: mow.cli
1 build:
2 skip: true
3 release:
4 github:
5 prerelease: auto
6 changelog:
7 sort: asc
8 filters:
9 exclude:
10 - '^docs:'
11 - '^test:'
+0
-22
.travis.yml less more
0 language: go
1 go:
2 - "1.12"
3 - "1.11"
4
5 sudo: false
6
7 env:
8 - GO111MODULE=on
9
10 install: make setup
11
12 script: make check test-cover
13
14 deploy:
15 provider: releases
16 api_key:
17 secure: D2fwuS7n54ZkjfRmLMEAnwR2lQLa5xd+4s0l65pI6UN4ljVfQwQiFdZXaZWFr8PYSTKTm0UPj6Iqqw7VOl8I6iDzcaOqN3hoh5mDaJ7kyo7GZRPodwK9MKdOp5dPw459L2Atll8kxb4iYmfnjmcl0lDCUuWvMxXx+zgiFTB7BO0=
18 skip_cleanup: true
19 on:
20 tags: true
21 go: "1.12"
00 test:
11 go test ./...
2
3 test-cover:
4 go list -f '{{if len .TestGoFiles}}"go test -coverprofile={{.Dir}}/.coverprofile {{.ImportPath}}"{{end}}' ./... | xargs -L 1 sh -c
5 gover
6 goveralls -coverprofile=gover.coverprofile -service=travis-ci
72
83 check: readmecheck
94 bin/golangci-lint run
127 autoreadme -f
138
149 readmecheck:
15 sed '$ d' README.md > README.original.md
10 head -n -1 README.md > README.original.md
1611 autoreadme -f
17 sed '$ d' README.md > README.generated.md
12 head -n -1 README.md > README.generated.md
1813 diff README.generated.md README.original.md
1914
20 setup:
21 go get golang.org/x/tools/cmd/cover
22 go get github.com/mattn/goveralls
23 go get github.com/modocache/gover
24 go get github.com/divan/autoreadme
25 curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.16.0
15 lint.setup:
16 curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.28.0
2617
27 .PHONY: test check lint vet fmtcheck ineffassign readmecheck
18
19 readmecheck.setup:
20 go get github.com/jawher/autoreadme
21
22 .PHONY: test check doc readmecheck lint.setup readmecheck.setup
00 # mow.cli
1 [![Build Status](https://travis-ci.org/jawher/mow.cli.svg?branch=master)](https://travis-ci.org/jawher/mow.cli)
2 [![GoDoc](https://godoc.org/github.com/github.com/jawher/mow.cli?status.svg)](https://godoc.org/github.com/jawher/mow.cli)
1 ![CI](https://github.com/jawher/mow.cli/workflows/CI/badge.svg)
2 [![GoDoc](https://pkg.go.dev/badge/github.com/jawher/mow.cli)](https://pkg.go.dev/github.com/jawher/mow.cli)
33 [![Coverage Status](https://coveralls.io/repos/github/jawher/mow.cli/badge.svg?branch=master)](https://coveralls.io/github/jawher/mow.cli?branch=master)
44
55 Package cli provides a framework to build command line applications in Go with most of the burden of arguments parsing and validation placed on the framework instead of the user.
106106 familiar commands such as git and docker. We build a fictional utility called
107107 uman to manage users in a system. It provides two commands that can be invoked:
108108 list and get. The list command takes an optional flag to specify all users
109 including disabled ones. The get command requries one argument, the user ID,
109 including disabled ones. The get command requires one argument, the user ID,
110110 and takes an optional flag to specify a detailed listing.
111111
112112 ```go
154154 // Declare our second command, which is invocable with "uman get"
155155 app.Command("get", "get a user details", func(cmd *cli.Cmd) {
156156 var (
157 detailed = cmd.BoolOpt("detailed", false, "Disaply detailed info")
157 detailed = cmd.BoolOpt("detailed", false, "Display detailed info")
158158 id = cmd.StringArg("ID", "", "The user id to display")
159159 )
160160
615615 $ docker job log clear
616616 ```
617617
618 Commands can be hidden in the help messages.
619 This can prove useful to deprecate a command so that it does not appear to new users in the help, but still exists to not break existing scripts.
620 To hide a command, set the Hidden field to true:
621
622 ```
623 app.Command("login", "login to the backend (DEPRECATED: please use auth instead)", func(cmd *cli.Cmd)) {
624 cmd.Hidden = true
625 }
626 ```
627
618628 As a convenience, to assign an Action to a func with no arguments, use
619629 ActionCommand when defining the Command. For example, the following two
620630 statements are equivalent:
10611071 Please see the `LICENSE` file for details.
10621072
10631073 * * *
1064 Automatically generated by [autoreadme](https://github.com/jimmyfrasche/autoreadme) on 2019.02.24
1074 Automatically generated by [autoreadme](https://github.com/jawher/autoreadme) on 2020.08.08
00 # mow.cli
1 [![Build Status](https://travis-ci.org/{{.RepoPath}}.svg?branch=master)](https://travis-ci.org/{{.RepoPath}})
2 [![GoDoc](https://godoc.org/github.com/{{.Import}}?status.svg)](https://godoc.org/{{.Import}})
3 [![Coverage Status](https://coveralls.io/repos/github/{{.RepoPath}}/badge.svg?branch=master)](https://coveralls.io/github/{{.RepoPath}}?branch=master)
1 ![CI](https://github.com/jawher/mow.cli/workflows/CI/badge.svg)
2 [![GoDoc](https://pkg.go.dev/badge/github.com/jawher/mow.cli)](https://pkg.go.dev/github.com/jawher/mow.cli)
3 [![Coverage Status](https://coveralls.io/repos/github/jawher/mow.cli/badge.svg?branch=master)](https://coveralls.io/github/jawher/mow.cli?branch=master)
44
55 {{.Synopsis}}
66
106106 familiar commands such as git and docker. We build a fictional utility called
107107 uman to manage users in a system. It provides two commands that can be invoked:
108108 list and get. The list command takes an optional flag to specify all users
109 including disabled ones. The get command requries one argument, the user ID,
109 including disabled ones. The get command requires one argument, the user ID,
110110 and takes an optional flag to specify a detailed listing.
111111
112112 ```go
154154 // Declare our second command, which is invocable with "uman get"
155155 app.Command("get", "get a user details", func(cmd *cli.Cmd) {
156156 var (
157 detailed = cmd.BoolOpt("detailed", false, "Disaply detailed info")
157 detailed = cmd.BoolOpt("detailed", false, "Display detailed info")
158158 id = cmd.StringArg("ID", "", "The user id to display")
159159 )
160160
304304 Please see the `LICENSE` file for details.
305305
306306 * * *
307 Automatically generated by [autoreadme](https://github.com/jimmyfrasche/autoreadme) on {{.Today}}
307 Automatically generated by [autoreadme](https://github.com/jawher/autoreadme) on {{.Today}}
393393 panic(fmt.Sprintf("duplicate argument name %q", arg.Name))
394394 }
395395
396 arg.DefaultValue = values.DefaultValue(arg.Value)
397
396398 arg.ValueSetFromEnv = values.SetFromEnv(arg.Value, arg.EnvVar)
397399
398400 c.args = append(c.args, &arg)
779779
780780 func TestHelpAndVersionWithOptionsEnd(t *testing.T) {
781781 for _, flag := range []string{"-h", "--help", "-v", "--version"} {
782 testHelpAndVersionWithOptionsEnd(flag, t)
782 t.Run(flag, func(t *testing.T) {
783 testHelpAndVersionWithOptionsEnd(flag, t)
784 })
783785 }
784786 }
785787
786788 var genGolden = flag.Bool("g", false, "Generate golden file(s)")
787789
788790 func TestHelpMessage(t *testing.T) {
789 var out, err string
790 defer captureAndRestoreOutput(&out, &err)()
791
792 exitCalled := false
793 defer exitShouldBeCalledWith(t, 0, &exitCalled)()
794
795 app := App("app", "App Desc")
796 app.Spec = "[-bdsuikqs] BOOL1 [STR1] INT3..."
797
798 // Options
799 app.Bool(BoolOpt{Name: "b bool1 u uuu", Value: false, EnvVar: "BOOL1", Desc: "Bool Option 1"})
800 app.Bool(BoolOpt{Name: "bool2", Value: true, EnvVar: " ", Desc: "Bool Option 2"})
801 app.Bool(BoolOpt{Name: "d", Value: true, EnvVar: "BOOL3", Desc: "Bool Option 3", HideValue: true})
802
803 app.String(StringOpt{Name: "s str1", Value: "", EnvVar: "STR1", Desc: "String Option 1"})
804 app.String(StringOpt{Name: "str2", Value: "a value", Desc: "String Option 2"})
805 app.String(StringOpt{Name: "v", Value: "another value", EnvVar: "STR3", Desc: "String Option 3", HideValue: true})
806
807 app.Int(IntOpt{Name: "i int1", Value: 0, EnvVar: "INT1 ALIAS_INT1"})
808 app.Int(IntOpt{Name: "int2", Value: 1, EnvVar: "INT2", Desc: "Int Option 2"})
809 app.Int(IntOpt{Name: "k", Value: 1, EnvVar: "INT3", Desc: "Int Option 3", HideValue: true})
810
811 app.Strings(StringsOpt{Name: "x strs1", Value: nil, EnvVar: "STRS1", Desc: "Strings Option 1"})
812 app.Strings(StringsOpt{Name: "strs2", Value: []string{"value1", "value2"}, EnvVar: "STRS2", Desc: "Strings Option 2"})
813 app.Strings(StringsOpt{Name: "z", Value: []string{"another value"}, EnvVar: "STRS3", Desc: "Strings Option 3", HideValue: true})
814
815 app.Ints(IntsOpt{Name: "q ints1", Value: nil, EnvVar: "INTS1", Desc: "Ints Option 1"})
816 app.Ints(IntsOpt{Name: "ints2", Value: []int{1, 2, 3}, EnvVar: "INTS2", Desc: "Ints Option 2"})
817 app.Ints(IntsOpt{Name: "j", Value: []int{1}, EnvVar: "INTS3", Desc: "Ints Option 3", HideValue: true})
818
819 // Args
820 app.Bool(BoolArg{Name: "BOOL1", Value: false, EnvVar: "BOOL1", Desc: "Bool Argument 1"})
821 app.Bool(BoolArg{Name: "BOOL2", Value: true, Desc: "Bool Argument 2"})
822 app.Bool(BoolArg{Name: "BOOL3", Value: true, EnvVar: "BOOL3", Desc: "Bool Argument 3", HideValue: true})
823
824 app.String(StringArg{Name: "STR1", Value: "", EnvVar: "STR1", Desc: "String Argument 1"})
825 app.String(StringArg{Name: "STR2", Value: "a value", EnvVar: "STR2", Desc: "String Argument 2"})
826 app.String(StringArg{Name: "STR3", Value: "another value", EnvVar: "STR3", Desc: "String Argument 3", HideValue: true})
827
828 app.Int(IntArg{Name: "INT1", Value: 0, EnvVar: "INT1", Desc: "Int Argument 1"})
829 app.Int(IntArg{Name: "INT2", Value: 1, EnvVar: "INT2", Desc: "Int Argument 2"})
830 app.Int(IntArg{Name: "INT3", Value: 1, EnvVar: "INT3", Desc: "Int Argument 3", HideValue: true})
831
832 app.Strings(StringsArg{Name: "STRS1", Value: nil, EnvVar: "STRS1", Desc: "Strings Argument 1"})
833 app.Strings(StringsArg{Name: "STRS2", Value: []string{"value1", "value2"}, EnvVar: "STRS2"})
834 app.Strings(StringsArg{Name: "STRS3", Value: []string{"another value"}, EnvVar: "STRS3", Desc: "Strings Argument 3", HideValue: true})
835
836 app.Ints(IntsArg{Name: "INTS1", Value: nil, EnvVar: "INTS1", Desc: "Ints Argument 1"})
837 app.Ints(IntsArg{Name: "INTS2", Value: []int{1, 2, 3}, EnvVar: "INTS2", Desc: "Ints Argument 2"})
838 app.Ints(IntsArg{Name: "INTS3", Value: []int{1}, EnvVar: "INTS3", Desc: "Ints Argument 3", HideValue: true})
839
840 app.Action = func() {}
841
842 app.Command("command1", "command1 description", func(cmd *Cmd) {})
843 app.Command("command2", "command2 description", func(cmd *Cmd) {})
844 app.Command("command3", "command3 description", func(cmd *Cmd) {})
845
846 require.NoError(t,
847 app.Run([]string{"app", "-h"}))
848
849 if *genGolden {
850 require.NoError(t,
851 ioutil.WriteFile("testdata/help-output.txt.golden", []byte(err), 0644))
852 }
853
854 expected, e := ioutil.ReadFile("testdata/help-output.txt")
855 require.NoError(t, e, "Failed to read the expected help output from testdata/help-output.txt")
856
857 require.Equal(t, expected, []byte(err))
791 cases := []struct {
792 name string
793 params []string
794 env map[string]string
795 exitCode int
796 }{
797 {name: "top-help", params: []string{"app", "-h"}},
798 {name: "top-help-i-user", params: []string{"app", "-i=5"}, exitCode: 2},
799 {name: "top-help-i-env", params: []string{"app"}, env: map[string]string{"INT1": "25"}, exitCode: 2},
800 {name: "command1", params: []string{"app", "command1", "-h"}},
801 {name: "command2", params: []string{"app", "command2", "-h"}},
802 {name: "command3", params: []string{"app", "command3", "-h"}},
803 {name: "command3-child1", params: []string{"app", "command3", "child1", "-h"}},
804 {name: "command3-child2", params: []string{"app", "command3", "child2", "-h"}},
805 {name: "command4", params: []string{"app", "command4", "-h"}},
806 }
807 for _, cas := range cases {
808 cas := cas
809 t.Run(cas.name, func(t *testing.T) {
810 t.Logf("case: %+v", cas)
811 var out, stdErr string
812 defer captureAndRestoreOutput(&out, &stdErr)()
813 defer setAndRestoreEnv(cas.env)()
814
815 exitCalled := false
816 defer exitShouldBeCalledWith(t, cas.exitCode, &exitCalled)()
817
818 app := App("app", "App Desc")
819 app.Spec = "[-bdsuikqs] [BOOL1 STR1 INT3...]"
820
821 // Options
822 app.Bool(BoolOpt{Name: "b bool1 u uuu", Value: false, EnvVar: "BOOL1", Desc: "Bool Option 1"})
823 app.Bool(BoolOpt{Name: "bool2", Value: true, EnvVar: " ", Desc: "Bool Option 2"})
824 app.Bool(BoolOpt{Name: "d", Value: true, EnvVar: "BOOL3", Desc: "Bool Option 3", HideValue: true})
825
826 app.String(StringOpt{Name: "s str1", Value: "", EnvVar: "STR1", Desc: "String Option 1"})
827 app.String(StringOpt{Name: "str2", Value: "a value", Desc: "String Option 2"})
828 app.String(StringOpt{Name: "v", Value: "another value", EnvVar: "STR3", Desc: "String Option 3", HideValue: true})
829
830 app.Int(IntOpt{Name: "i int1", Value: 0, EnvVar: "INT1 ALIAS_INT1"})
831 app.Int(IntOpt{Name: "int2", Value: 1, EnvVar: "INT2", Desc: "Int Option 2"})
832 app.Int(IntOpt{Name: "k", Value: 1, EnvVar: "INT3", Desc: "Int Option 3", HideValue: true})
833
834 app.Strings(StringsOpt{Name: "x strs1", Value: nil, EnvVar: "STRS1", Desc: "Strings Option 1"})
835 app.Strings(StringsOpt{Name: "strs2", Value: []string{"value1", "value2"}, EnvVar: "STRS2", Desc: "Strings Option 2"})
836 app.Strings(StringsOpt{Name: "z", Value: []string{"another value"}, EnvVar: "STRS3", Desc: "Strings Option 3", HideValue: true})
837
838 app.Ints(IntsOpt{Name: "q ints1", Value: nil, EnvVar: "INTS1", Desc: "Ints Option 1"})
839 app.Ints(IntsOpt{Name: "ints2", Value: []int{1, 2, 3}, EnvVar: "INTS2", Desc: "Ints Option 2"})
840 app.Ints(IntsOpt{Name: "j", Value: []int{1}, EnvVar: "INTS3", Desc: "Ints Option 3", HideValue: true})
841
842 // Args
843 app.Bool(BoolArg{Name: "BOOL1", Value: false, EnvVar: "BOOL1", Desc: "Bool Argument 1"})
844 app.Bool(BoolArg{Name: "BOOL2", Value: true, Desc: "Bool Argument 2"})
845 app.Bool(BoolArg{Name: "BOOL3", Value: true, EnvVar: "BOOL3", Desc: "Bool Argument 3", HideValue: true})
846
847 app.String(StringArg{Name: "STR1", Value: "", EnvVar: "STR1", Desc: "String Argument 1"})
848 app.String(StringArg{Name: "STR2", Value: "a value", EnvVar: "STR2", Desc: "String Argument 2"})
849 app.String(StringArg{Name: "STR3", Value: "another value", EnvVar: "STR3", Desc: "String Argument 3", HideValue: true})
850
851 app.Int(IntArg{Name: "INT1", Value: 0, EnvVar: "INT1", Desc: "Int Argument 1"})
852 app.Int(IntArg{Name: "INT2", Value: 1, EnvVar: "INT2", Desc: "Int Argument 2"})
853 app.Int(IntArg{Name: "INT3", Value: 1, EnvVar: "INT3", Desc: "Int Argument 3", HideValue: true})
854
855 app.Strings(StringsArg{Name: "STRS1", Value: nil, EnvVar: "STRS1", Desc: "Strings Argument 1"})
856 app.Strings(StringsArg{Name: "STRS2", Value: []string{"value1", "value2"}, EnvVar: "STRS2"})
857 app.Strings(StringsArg{Name: "STRS3", Value: []string{"another value"}, EnvVar: "STRS3", Desc: "Strings Argument 3", HideValue: true})
858
859 app.Ints(IntsArg{Name: "INTS1", Value: nil, EnvVar: "INTS1", Desc: "Ints Argument 1"})
860 app.Ints(IntsArg{Name: "INTS2", Value: []int{1, 2, 3}, EnvVar: "INTS2", Desc: "Ints Argument 2"})
861 app.Ints(IntsArg{Name: "INTS3", Value: []int{1}, EnvVar: "INTS3", Desc: "Ints Argument 3", HideValue: true})
862
863 app.Command("command1", "command1 description", func(cmd *Cmd) {})
864 app.Command("command2", "command2 description", func(cmd *Cmd) {})
865 app.Command("command3", "command3 description", func(cmd *Cmd) {
866 cmd.Command("child1", "child1 description", func(cmd *Cmd) {
867 cmd.StringArg("ARG1", "", "arg1 desc")
868 })
869 cmd.Command("child2", "child2 description", func(cmd *Cmd) {
870 cmd.Hidden = true
871 cmd.StringOpt("o opt", "", "opt desc")
872 })
873 })
874 app.Command("command4", "command4 description", func(cmd *Cmd) {
875 cmd.Hidden = true
876 })
877
878 fmt.Printf("calling app with %+v\n", cas.params)
879 require.NoError(t,
880 app.Run(cas.params))
881
882 filename := fmt.Sprintf("testdata/help-output-%s.txt", cas.name)
883
884 if *genGolden {
885 require.NoError(t,
886 ioutil.WriteFile(filename, []byte(stdErr), 0644))
887 }
888
889 expected, e := ioutil.ReadFile(filename)
890 require.NoError(t, e, "Failed to read the expected help output from %s", filename)
891
892 require.Equal(t, string(expected), stdErr)
893 })
894 }
858895 }
859896
860897 func TestLongHelpMessage(t *testing.T) {
22002237 return captureAndRestoreOutput(nil, nil)
22012238 }
22022239
2240 func setAndRestoreEnv(env map[string]string) func() {
2241 backup := map[string]string{}
2242 for k, v := range env {
2243 backup[k] = os.Getenv(k)
2244 os.Setenv(k, v)
2245 }
2246
2247 return func() {
2248 for k, v := range backup {
2249 os.Setenv(k, v)
2250 }
2251 }
2252 }
2253
22032254 func captureAndRestoreOutput(out, err *string) func() {
22042255 oldStdOut := stdOut
22052256 oldStdErr := stdErr
1111 "github.com/jawher/mow.cli/internal/fsm"
1212 "github.com/jawher/mow.cli/internal/lexer"
1313 "github.com/jawher/mow.cli/internal/parser"
14 "github.com/jawher/mow.cli/internal/values"
1514 )
1615
1716 /*
3029 Spec string
3130 // The command long description to be shown when help is requested
3231 LongDesc string
32 // Hide this command in the help messages
33 Hidden bool
3334 // The command error handling strategy
3435 ErrorHandling flag.ErrorHandling
3536
543544 for _, arg := range c.args {
544545 var (
545546 env = formatEnvVarsForHelp(arg.EnvVar)
546 value = formatValueForHelp(arg.HideValue, arg.Value)
547 value = formatValueForHelp(arg.HideValue, arg.DefaultValue)
547548 )
548549 printTabbedRow(w, arg.Name, joinStrings(arg.Desc, env, value))
549550 }
556557 var (
557558 optNames = formatOptNamesForHelp(opt)
558559 env = formatEnvVarsForHelp(opt.EnvVar)
559 value = formatValueForHelp(opt.HideValue, opt.Value)
560 value = formatValueForHelp(opt.HideValue, opt.DefaultValue)
560561 )
561562 printTabbedRow(w, optNames, joinStrings(opt.Desc, env, value))
562563 }
563564 }
564565
565 if len(c.commands) > 0 {
566 commands := make([]*Cmd, 0, len(c.commands))
567 for _, c := range c.commands {
568 if err := c.doInit(); err != nil {
569 panic(err)
570 }
571
572 if c.Hidden {
573 continue
574 }
575
576 commands = append(commands, c)
577 }
578
579 if len(commands) > 0 {
566580 fmt.Fprint(w, "\t\nCommands:\t\n")
567581
568 for _, c := range c.commands {
582 for _, c := range commands {
569583 fmt.Fprintf(w, " %s\t%s\n", strings.Join(c.aliases, ", "), c.desc)
570584 }
571585 }
572586
573 if len(c.commands) > 0 {
587 if len(commands) > 0 {
574588 fmt.Fprintf(w, "\t\nRun '%s COMMAND --help' for more information on a command.\n", path)
575589 }
576590
603617 }
604618 }
605619
606 func formatValueForHelp(hide bool, v flag.Value) string {
620 func formatValueForHelp(hide bool, v string) string {
607621 if hide {
608622 return ""
609623 }
610624
611 if dv, ok := v.(values.DefaultValued); ok {
612 if dv.IsDefault() {
613 return ""
614 }
615 }
616
617 return fmt.Sprintf("(default %s)", v.String())
625 if v == "" {
626 return ""
627 }
628
629 return fmt.Sprintf("(default %s)", v)
618630 }
619631
620632 func formatEnvVarsForHelp(envVars string) string {
286286 $ docker job r # using the alias we defined
287287 $ docker job log show
288288 $ docker job log clear
289
290 Commands can be hidden in the help messages.
291 This can prove useful to deprecate a command so that it does not appear to new users in the help, but still exists to not break existing scripts.
292 To hide a command, set the Hidden field to true:
293
294 app.Command("login", "login to the backend (DEPRECATED: please use auth instead)", func(cmd *cli.Cmd)) {
295 cmd.Hidden = true
296 }
289297
290298 As a convenience, to assign an Action to a func with no arguments, use
291299 ActionCommand when defining the Command. For example, the following two
11
22 require (
33 github.com/stretchr/objx v0.2.0 // indirect
4 github.com/stretchr/testify v1.3.0
4 github.com/stretchr/testify v1.4.0
5 gopkg.in/yaml.v2 v2.2.5 // indirect
56 )
7
8 go 1.13
22 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
33 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
44 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5 github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
56 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
7 github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
68 github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
7 github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
8 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
99 github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
1010 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
11 github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
12 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
13 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
14 gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
15 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
16 gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
17 gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
1313 ValueSetFromEnv bool
1414 ValueSetByUser *bool
1515 Value flag.Value
16 DefaultValue string
1617 }
5353
5454 return nil
5555 }
56
57 func DefaultValue(v flag.Value) string {
58 if dv, ok := v.(DefaultValued); ok {
59 if dv.IsDefault() {
60 return ""
61 }
62 }
63 return v.String()
64 }
466466 }
467467
468468 func (c *Cmd) mkOpt(opt container.Container) {
469 opt.DefaultValue = values.DefaultValue(opt.Value)
469470 opt.ValueSetFromEnv = values.SetFromEnv(opt.Value, opt.EnvVar)
470471
471472 opt.Names = mkOptStrs(opt.Name)
0
1 Usage: app command1
2
3 command1 description
0
1 Usage: app command2
2
3 command2 description
0
1 Usage: app command3 child1 ARG1
2
3 child1 description
4
5 Arguments:
6 ARG1 arg1 desc
0
1 Usage: app command3 child2 [OPTIONS]
2
3 child2 description
4
5 Options:
6 -o, --opt opt desc
0
1 Usage: app command3 COMMAND [arg...]
2
3 command3 description
4
5 Commands:
6 child1 child1 description
7
8 Run 'app command3 COMMAND --help' for more information on a command.
0
1 Usage: app command4
2
3 command4 description
0
1 Usage: app [-bdsuikqs] [BOOL1 STR1 INT3...] COMMAND [arg...]
2
3 App Desc
4
5 Arguments:
6 BOOL1 Bool Argument 1 (env $BOOL1)
7 BOOL2 Bool Argument 2 (default true)
8 BOOL3 Bool Argument 3 (env $BOOL3)
9 STR1 String Argument 1 (env $STR1)
10 STR2 String Argument 2 (env $STR2) (default "a value")
11 STR3 String Argument 3 (env $STR3)
12 INT1 Int Argument 1 (env $INT1) (default 0)
13 INT2 Int Argument 2 (env $INT2) (default 1)
14 INT3 Int Argument 3 (env $INT3)
15 STRS1 Strings Argument 1 (env $STRS1)
16 STRS2 (env $STRS2) (default ["value1", "value2"])
17 STRS3 Strings Argument 3 (env $STRS3)
18 INTS1 Ints Argument 1 (env $INTS1)
19 INTS2 Ints Argument 2 (env $INTS2) (default [1, 2, 3])
20 INTS3 Ints Argument 3 (env $INTS3)
21
22 Options:
23 -b, --bool1 Bool Option 1 (env $BOOL1)
24 --bool2 Bool Option 2 (default true)
25 -d Bool Option 3 (env $BOOL3)
26 -s, --str1 String Option 1 (env $STR1)
27 --str2 String Option 2 (default "a value")
28 -v String Option 3 (env $STR3)
29 -i, --int1 (env $INT1, $ALIAS_INT1) (default 0)
30 --int2 Int Option 2 (env $INT2) (default 1)
31 -k Int Option 3 (env $INT3)
32 -x, --strs1 Strings Option 1 (env $STRS1)
33 --strs2 Strings Option 2 (env $STRS2) (default ["value1", "value2"])
34 -z Strings Option 3 (env $STRS3)
35 -q, --ints1 Ints Option 1 (env $INTS1)
36 --ints2 Ints Option 2 (env $INTS2) (default [1, 2, 3])
37 -j Ints Option 3 (env $INTS3)
38
39 Commands:
40 command1 command1 description
41 command2 command2 description
42 command3 command3 description
43
44 Run 'app COMMAND --help' for more information on a command.
0
1 Usage: app [-bdsuikqs] [BOOL1 STR1 INT3...] COMMAND [arg...]
2
3 App Desc
4
5 Arguments:
6 BOOL1 Bool Argument 1 (env $BOOL1)
7 BOOL2 Bool Argument 2 (default true)
8 BOOL3 Bool Argument 3 (env $BOOL3)
9 STR1 String Argument 1 (env $STR1)
10 STR2 String Argument 2 (env $STR2) (default "a value")
11 STR3 String Argument 3 (env $STR3)
12 INT1 Int Argument 1 (env $INT1) (default 0)
13 INT2 Int Argument 2 (env $INT2) (default 1)
14 INT3 Int Argument 3 (env $INT3)
15 STRS1 Strings Argument 1 (env $STRS1)
16 STRS2 (env $STRS2) (default ["value1", "value2"])
17 STRS3 Strings Argument 3 (env $STRS3)
18 INTS1 Ints Argument 1 (env $INTS1)
19 INTS2 Ints Argument 2 (env $INTS2) (default [1, 2, 3])
20 INTS3 Ints Argument 3 (env $INTS3)
21
22 Options:
23 -b, --bool1 Bool Option 1 (env $BOOL1)
24 --bool2 Bool Option 2 (default true)
25 -d Bool Option 3 (env $BOOL3)
26 -s, --str1 String Option 1 (env $STR1)
27 --str2 String Option 2 (default "a value")
28 -v String Option 3 (env $STR3)
29 -i, --int1 (env $INT1, $ALIAS_INT1) (default 0)
30 --int2 Int Option 2 (env $INT2) (default 1)
31 -k Int Option 3 (env $INT3)
32 -x, --strs1 Strings Option 1 (env $STRS1)
33 --strs2 Strings Option 2 (env $STRS2) (default ["value1", "value2"])
34 -z Strings Option 3 (env $STRS3)
35 -q, --ints1 Ints Option 1 (env $INTS1)
36 --ints2 Ints Option 2 (env $INTS2) (default [1, 2, 3])
37 -j Ints Option 3 (env $INTS3)
38
39 Commands:
40 command1 command1 description
41 command2 command2 description
42 command3 command3 description
43
44 Run 'app COMMAND --help' for more information on a command.
0
1 Usage: app [-bdsuikqs] [BOOL1 STR1 INT3...] COMMAND [arg...]
2
3 App Desc
4
5 Arguments:
6 BOOL1 Bool Argument 1 (env $BOOL1)
7 BOOL2 Bool Argument 2 (default true)
8 BOOL3 Bool Argument 3 (env $BOOL3)
9 STR1 String Argument 1 (env $STR1)
10 STR2 String Argument 2 (env $STR2) (default "a value")
11 STR3 String Argument 3 (env $STR3)
12 INT1 Int Argument 1 (env $INT1) (default 0)
13 INT2 Int Argument 2 (env $INT2) (default 1)
14 INT3 Int Argument 3 (env $INT3)
15 STRS1 Strings Argument 1 (env $STRS1)
16 STRS2 (env $STRS2) (default ["value1", "value2"])
17 STRS3 Strings Argument 3 (env $STRS3)
18 INTS1 Ints Argument 1 (env $INTS1)
19 INTS2 Ints Argument 2 (env $INTS2) (default [1, 2, 3])
20 INTS3 Ints Argument 3 (env $INTS3)
21
22 Options:
23 -b, --bool1 Bool Option 1 (env $BOOL1)
24 --bool2 Bool Option 2 (default true)
25 -d Bool Option 3 (env $BOOL3)
26 -s, --str1 String Option 1 (env $STR1)
27 --str2 String Option 2 (default "a value")
28 -v String Option 3 (env $STR3)
29 -i, --int1 (env $INT1, $ALIAS_INT1) (default 0)
30 --int2 Int Option 2 (env $INT2) (default 1)
31 -k Int Option 3 (env $INT3)
32 -x, --strs1 Strings Option 1 (env $STRS1)
33 --strs2 Strings Option 2 (env $STRS2) (default ["value1", "value2"])
34 -z Strings Option 3 (env $STRS3)
35 -q, --ints1 Ints Option 1 (env $INTS1)
36 --ints2 Ints Option 2 (env $INTS2) (default [1, 2, 3])
37 -j Ints Option 3 (env $INTS3)
38
39 Commands:
40 command1 command1 description
41 command2 command2 description
42 command3 command3 description
43
44 Run 'app COMMAND --help' for more information on a command.
+0
-45
testdata/help-output.txt less more
0
1 Usage: app [-bdsuikqs] BOOL1 [STR1] INT3... COMMAND [arg...]
2
3 App Desc
4
5 Arguments:
6 BOOL1 Bool Argument 1 (env $BOOL1)
7 BOOL2 Bool Argument 2 (default true)
8 BOOL3 Bool Argument 3 (env $BOOL3)
9 STR1 String Argument 1 (env $STR1)
10 STR2 String Argument 2 (env $STR2) (default "a value")
11 STR3 String Argument 3 (env $STR3)
12 INT1 Int Argument 1 (env $INT1) (default 0)
13 INT2 Int Argument 2 (env $INT2) (default 1)
14 INT3 Int Argument 3 (env $INT3)
15 STRS1 Strings Argument 1 (env $STRS1)
16 STRS2 (env $STRS2) (default ["value1", "value2"])
17 STRS3 Strings Argument 3 (env $STRS3)
18 INTS1 Ints Argument 1 (env $INTS1)
19 INTS2 Ints Argument 2 (env $INTS2) (default [1, 2, 3])
20 INTS3 Ints Argument 3 (env $INTS3)
21
22 Options:
23 -b, --bool1 Bool Option 1 (env $BOOL1)
24 --bool2 Bool Option 2 (default true)
25 -d Bool Option 3 (env $BOOL3)
26 -s, --str1 String Option 1 (env $STR1)
27 --str2 String Option 2 (default "a value")
28 -v String Option 3 (env $STR3)
29 -i, --int1 (env $INT1, $ALIAS_INT1) (default 0)
30 --int2 Int Option 2 (env $INT2) (default 1)
31 -k Int Option 3 (env $INT3)
32 -x, --strs1 Strings Option 1 (env $STRS1)
33 --strs2 Strings Option 2 (env $STRS2) (default ["value1", "value2"])
34 -z Strings Option 3 (env $STRS3)
35 -q, --ints1 Ints Option 1 (env $INTS1)
36 --ints2 Ints Option 2 (env $INTS2) (default [1, 2, 3])
37 -j Ints Option 3 (env $INTS3)
38
39 Commands:
40 command1 command1 description
41 command2 command2 description
42 command3 command3 description
43
44 Run 'app COMMAND --help' for more information on a command.