Import upstream version 1.2.0+git20210725.1.d9d0f2e
Kali Janitor
1 year, 4 months ago
0 | testdata/*.golden | |
1 | coverage.out | |
2 | *.coverprofile | |
3 | README.generated.md | |
4 | README.original.md | |
5 | bin/ |
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 | 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" |
0 | 0 | test: |
1 | 1 | 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 | |
7 | 2 | |
8 | 3 | check: readmecheck |
9 | 4 | bin/golangci-lint run |
12 | 7 | autoreadme -f |
13 | 8 | |
14 | 9 | readmecheck: |
15 | sed '$ d' README.md > README.original.md | |
10 | head -n -1 README.md > README.original.md | |
16 | 11 | autoreadme -f |
17 | sed '$ d' README.md > README.generated.md | |
12 | head -n -1 README.md > README.generated.md | |
18 | 13 | diff README.generated.md README.original.md |
19 | 14 | |
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 | |
26 | 17 | |
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 |
0 | 0 | # 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) | |
3 | 3 | [![Coverage Status](https://coveralls.io/repos/github/jawher/mow.cli/badge.svg?branch=master)](https://coveralls.io/github/jawher/mow.cli?branch=master) |
4 | 4 | |
5 | 5 | 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. |
106 | 106 | familiar commands such as git and docker. We build a fictional utility called |
107 | 107 | uman to manage users in a system. It provides two commands that can be invoked: |
108 | 108 | 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, | |
110 | 110 | and takes an optional flag to specify a detailed listing. |
111 | 111 | |
112 | 112 | ```go |
154 | 154 | // Declare our second command, which is invocable with "uman get" |
155 | 155 | app.Command("get", "get a user details", func(cmd *cli.Cmd) { |
156 | 156 | var ( |
157 | detailed = cmd.BoolOpt("detailed", false, "Disaply detailed info") | |
157 | detailed = cmd.BoolOpt("detailed", false, "Display detailed info") | |
158 | 158 | id = cmd.StringArg("ID", "", "The user id to display") |
159 | 159 | ) |
160 | 160 | |
615 | 615 | $ docker job log clear |
616 | 616 | ``` |
617 | 617 | |
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 | ||
618 | 628 | As a convenience, to assign an Action to a func with no arguments, use |
619 | 629 | ActionCommand when defining the Command. For example, the following two |
620 | 630 | statements are equivalent: |
1061 | 1071 | Please see the `LICENSE` file for details. |
1062 | 1072 | |
1063 | 1073 | * * * |
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 |
0 | 0 | # 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) | |
4 | 4 | |
5 | 5 | {{.Synopsis}} |
6 | 6 | |
106 | 106 | familiar commands such as git and docker. We build a fictional utility called |
107 | 107 | uman to manage users in a system. It provides two commands that can be invoked: |
108 | 108 | 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, | |
110 | 110 | and takes an optional flag to specify a detailed listing. |
111 | 111 | |
112 | 112 | ```go |
154 | 154 | // Declare our second command, which is invocable with "uman get" |
155 | 155 | app.Command("get", "get a user details", func(cmd *cli.Cmd) { |
156 | 156 | var ( |
157 | detailed = cmd.BoolOpt("detailed", false, "Disaply detailed info") | |
157 | detailed = cmd.BoolOpt("detailed", false, "Display detailed info") | |
158 | 158 | id = cmd.StringArg("ID", "", "The user id to display") |
159 | 159 | ) |
160 | 160 | |
304 | 304 | Please see the `LICENSE` file for details. |
305 | 305 | |
306 | 306 | * * * |
307 | Automatically generated by [autoreadme](https://github.com/jimmyfrasche/autoreadme) on {{.Today}} | |
307 | Automatically generated by [autoreadme](https://github.com/jawher/autoreadme) on {{.Today}} |
393 | 393 | panic(fmt.Sprintf("duplicate argument name %q", arg.Name)) |
394 | 394 | } |
395 | 395 | |
396 | arg.DefaultValue = values.DefaultValue(arg.Value) | |
397 | ||
396 | 398 | arg.ValueSetFromEnv = values.SetFromEnv(arg.Value, arg.EnvVar) |
397 | 399 | |
398 | 400 | c.args = append(c.args, &arg) |
76 | 76 | } |
77 | 77 | |
78 | 78 | func (cli *Cli) versionSetAndRequested(args []string) bool { |
79 | return cli.version != nil && cli.isFlagSet(args, cli.version.option.Names) | |
79 | return cli.version != nil && cli.isFirstItemAmong(args, cli.version.option.Names) | |
80 | 80 | } |
81 | 81 | |
82 | 82 | /* |
751 | 751 | } |
752 | 752 | } |
753 | 753 | |
754 | func testHelpAndVersionWithOptionsEnd(flag string, t *testing.T) { | |
755 | t.Logf("Testing help/version with --: flag=%q", flag) | |
756 | defer suppressOutput()() | |
757 | ||
758 | exitCalled := false | |
759 | defer exitShouldBeCalledWith(t, 0, &exitCalled)() | |
760 | ||
761 | app := App("x", "") | |
762 | app.Version("v version", "1.0") | |
763 | app.Spec = "CMD" | |
764 | ||
765 | cmd := app.String(StringArg{Name: "CMD", Value: "", Desc: ""}) | |
766 | ||
767 | actionCalled := false | |
768 | app.Action = func() { | |
769 | actionCalled = true | |
770 | require.Equal(t, flag, *cmd) | |
771 | } | |
772 | ||
773 | require.NoError(t, | |
774 | app.Run([]string{"x", "--", flag})) | |
775 | ||
776 | require.True(t, actionCalled, "action should have been called") | |
777 | require.False(t, exitCalled, "exit should not have been called") | |
754 | func TestHelpCommandSkipsValidation(t *testing.T) { | |
755 | t.Run("1 level deep", func(t *testing.T) { | |
756 | for _, args := range [][]string{ | |
757 | {"app", "command", "-h"}, | |
758 | {"app", "--opt1", "command", "-h"}, | |
759 | {"app", "--opt1", "value1", "command", "-h"}, | |
760 | {"app", "--opt2", "command", "-h"}, | |
761 | {"app", "--opt2", "--opt3", "command", "-h"}, | |
762 | {"app", "--wrong", "command", "-h"}, | |
763 | } { | |
764 | t.Run(fmt.Sprintf("%v", args), func(t *testing.T) { | |
765 | app := App("app", "app desc") | |
766 | app.StringArg("ARG", "", "arg desc") | |
767 | app.StringOpt("opt1", "", "opt1 desc") | |
768 | app.BoolOpt("opt2", false, "opt2 desc") | |
769 | app.BoolOpt("opt3", false, "opt3 desc") | |
770 | app.Command("command", "command desc", func(cmd *Cmd) {}) | |
771 | ||
772 | var out, stdErr string | |
773 | defer captureAndRestoreOutput(&out, &stdErr)() | |
774 | ||
775 | exitCalled := false | |
776 | defer exitShouldBeCalledWith(t, 0, &exitCalled)() | |
777 | ||
778 | require.NoError(t, | |
779 | // calling help on a command should skip validating the parents required arguments | |
780 | app.Run(args)) | |
781 | ||
782 | require.Equal(t, ` | |
783 | Usage: app command | |
784 | ||
785 | command desc | |
786 | `, stdErr) | |
787 | }) | |
788 | } | |
789 | }) | |
790 | ||
791 | t.Run("2 level deep", func(t *testing.T) { | |
792 | for _, args := range [][]string{ | |
793 | {"app", "command", "child", "-h"}, | |
794 | {"app", "--opt1", "command", "child", "-h"}, | |
795 | {"app", "--opt1", "value1", "command", "child", "-h"}, | |
796 | {"app", "--opt2", "command", "child", "-h"}, | |
797 | {"app", "--opt2", "--opt3", "command", "child", "-h"}, | |
798 | {"app", "--wrong", "command", "child", "-h"}, | |
799 | } { | |
800 | t.Run(fmt.Sprintf("%v", args), func(t *testing.T) { | |
801 | app := App("app", "app desc") | |
802 | app.StringArg("ARG1", "", "arg1 desc") | |
803 | app.StringOpt("opt1", "", "opt1 desc") | |
804 | app.BoolOpt("opt2", false, "opt2 desc") | |
805 | app.BoolOpt("opt3", false, "opt3 desc") | |
806 | ||
807 | app.Command("command", "command desc", func(cmd *Cmd) { | |
808 | cmd.StringArg("ARG2", "", "arg2 desc") | |
809 | ||
810 | cmd.Command("child", "child desc", func(cmd *Cmd) {}) | |
811 | }) | |
812 | ||
813 | var out, stdErr string | |
814 | defer captureAndRestoreOutput(&out, &stdErr)() | |
815 | ||
816 | exitCalled := false | |
817 | defer exitShouldBeCalledWith(t, 0, &exitCalled)() | |
818 | ||
819 | require.NoError(t, | |
820 | // calling help on a command should skip validating the parents required arguments | |
821 | app.Run(args)) | |
822 | ||
823 | require.Equal(t, ` | |
824 | Usage: app command child | |
825 | ||
826 | child desc | |
827 | `, stdErr) | |
828 | }) | |
829 | } | |
830 | }) | |
778 | 831 | } |
779 | 832 | |
780 | 833 | func TestHelpAndVersionWithOptionsEnd(t *testing.T) { |
781 | for _, flag := range []string{"-h", "--help", "-v", "--version"} { | |
782 | testHelpAndVersionWithOptionsEnd(flag, t) | |
834 | for _, opt := range []string{"-h", "--help", "-v", "--version"} { | |
835 | t.Run(opt, func(t *testing.T) { | |
836 | t.Logf("Testing help/version with --: opt=%q", opt) | |
837 | defer suppressOutput()() | |
838 | ||
839 | exitCalled := false | |
840 | defer exitShouldBeCalledWith(t, 0, &exitCalled)() | |
841 | ||
842 | app := App("x", "") | |
843 | app.Version("v version", "1.0") | |
844 | app.Spec = "CMD" | |
845 | ||
846 | cmd := app.String(StringArg{Name: "CMD", Value: "", Desc: ""}) | |
847 | ||
848 | actionCalled := false | |
849 | app.Action = func() { | |
850 | actionCalled = true | |
851 | require.Equal(t, opt, *cmd) | |
852 | } | |
853 | ||
854 | require.NoError(t, | |
855 | app.Run([]string{"x", "--", opt})) | |
856 | ||
857 | require.True(t, actionCalled, "action should have been called") | |
858 | require.False(t, exitCalled, "exit should not have been called") | |
859 | }) | |
783 | 860 | } |
784 | 861 | } |
785 | 862 | |
786 | 863 | var genGolden = flag.Bool("g", false, "Generate golden file(s)") |
787 | 864 | |
788 | 865 | 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)) | |
866 | cases := []struct { | |
867 | name string | |
868 | params []string | |
869 | env map[string]string | |
870 | exitCode int | |
871 | }{ | |
872 | {name: "top-help", params: []string{"app", "-h"}}, | |
873 | {name: "top-help-i-user", params: []string{"app", "-i=5"}, exitCode: 2}, | |
874 | {name: "top-help-i-env", params: []string{"app"}, env: map[string]string{"INT1": "25"}, exitCode: 2}, | |
875 | {name: "command1", params: []string{"app", "command1", "-h"}}, | |
876 | {name: "command2", params: []string{"app", "command2", "-h"}}, | |
877 | {name: "command3", params: []string{"app", "command3", "-h"}}, | |
878 | {name: "command3-child1", params: []string{"app", "command3", "child1", "-h"}}, | |
879 | {name: "command3-child2", params: []string{"app", "command3", "child2", "-h"}}, | |
880 | {name: "command4", params: []string{"app", "command4", "-h"}}, | |
881 | } | |
882 | for _, cas := range cases { | |
883 | cas := cas | |
884 | t.Run(cas.name, func(t *testing.T) { | |
885 | t.Logf("case: %+v", cas) | |
886 | var out, stdErr string | |
887 | defer captureAndRestoreOutput(&out, &stdErr)() | |
888 | defer setAndRestoreEnv(cas.env)() | |
889 | ||
890 | exitCalled := false | |
891 | defer exitShouldBeCalledWith(t, cas.exitCode, &exitCalled)() | |
892 | ||
893 | app := App("app", "App Desc") | |
894 | app.Spec = "[-bdsuikqs] [BOOL1 STR1 INT3...]" | |
895 | ||
896 | // Options | |
897 | app.Bool(BoolOpt{Name: "b bool1 u uuu", Value: false, EnvVar: "BOOL1", Desc: "Bool Option 1"}) | |
898 | app.Bool(BoolOpt{Name: "bool2", Value: true, EnvVar: " ", Desc: "Bool Option 2"}) | |
899 | app.Bool(BoolOpt{Name: "d", Value: true, EnvVar: "BOOL3", Desc: "Bool Option 3", HideValue: true}) | |
900 | ||
901 | app.String(StringOpt{Name: "s str1", Value: "", EnvVar: "STR1", Desc: "String Option 1"}) | |
902 | app.String(StringOpt{Name: "str2", Value: "a value", Desc: "String Option 2"}) | |
903 | app.String(StringOpt{Name: "v", Value: "another value", EnvVar: "STR3", Desc: "String Option 3", HideValue: true}) | |
904 | ||
905 | app.Int(IntOpt{Name: "i int1", Value: 0, EnvVar: "INT1 ALIAS_INT1"}) | |
906 | app.Int(IntOpt{Name: "int2", Value: 1, EnvVar: "INT2", Desc: "Int Option 2"}) | |
907 | app.Int(IntOpt{Name: "k", Value: 1, EnvVar: "INT3", Desc: "Int Option 3", HideValue: true}) | |
908 | ||
909 | app.Strings(StringsOpt{Name: "x strs1", Value: nil, EnvVar: "STRS1", Desc: "Strings Option 1"}) | |
910 | app.Strings(StringsOpt{Name: "strs2", Value: []string{"value1", "value2"}, EnvVar: "STRS2", Desc: "Strings Option 2"}) | |
911 | app.Strings(StringsOpt{Name: "z", Value: []string{"another value"}, EnvVar: "STRS3", Desc: "Strings Option 3", HideValue: true}) | |
912 | ||
913 | app.Ints(IntsOpt{Name: "q ints1", Value: nil, EnvVar: "INTS1", Desc: "Ints Option 1"}) | |
914 | app.Ints(IntsOpt{Name: "ints2", Value: []int{1, 2, 3}, EnvVar: "INTS2", Desc: "Ints Option 2"}) | |
915 | app.Ints(IntsOpt{Name: "j", Value: []int{1}, EnvVar: "INTS3", Desc: "Ints Option 3", HideValue: true}) | |
916 | ||
917 | // Args | |
918 | app.Bool(BoolArg{Name: "BOOL1", Value: false, EnvVar: "BOOL1", Desc: "Bool Argument 1"}) | |
919 | app.Bool(BoolArg{Name: "BOOL2", Value: true, Desc: "Bool Argument 2"}) | |
920 | app.Bool(BoolArg{Name: "BOOL3", Value: true, EnvVar: "BOOL3", Desc: "Bool Argument 3", HideValue: true}) | |
921 | ||
922 | app.String(StringArg{Name: "STR1", Value: "", EnvVar: "STR1", Desc: "String Argument 1"}) | |
923 | app.String(StringArg{Name: "STR2", Value: "a value", EnvVar: "STR2", Desc: "String Argument 2"}) | |
924 | app.String(StringArg{Name: "STR3", Value: "another value", EnvVar: "STR3", Desc: "String Argument 3", HideValue: true}) | |
925 | ||
926 | app.Int(IntArg{Name: "INT1", Value: 0, EnvVar: "INT1", Desc: "Int Argument 1"}) | |
927 | app.Int(IntArg{Name: "INT2", Value: 1, EnvVar: "INT2", Desc: "Int Argument 2"}) | |
928 | app.Int(IntArg{Name: "INT3", Value: 1, EnvVar: "INT3", Desc: "Int Argument 3", HideValue: true}) | |
929 | ||
930 | app.Strings(StringsArg{Name: "STRS1", Value: nil, EnvVar: "STRS1", Desc: "Strings Argument 1"}) | |
931 | app.Strings(StringsArg{Name: "STRS2", Value: []string{"value1", "value2"}, EnvVar: "STRS2"}) | |
932 | app.Strings(StringsArg{Name: "STRS3", Value: []string{"another value"}, EnvVar: "STRS3", Desc: "Strings Argument 3", HideValue: true}) | |
933 | ||
934 | app.Ints(IntsArg{Name: "INTS1", Value: nil, EnvVar: "INTS1", Desc: "Ints Argument 1"}) | |
935 | app.Ints(IntsArg{Name: "INTS2", Value: []int{1, 2, 3}, EnvVar: "INTS2", Desc: "Ints Argument 2"}) | |
936 | app.Ints(IntsArg{Name: "INTS3", Value: []int{1}, EnvVar: "INTS3", Desc: "Ints Argument 3", HideValue: true}) | |
937 | ||
938 | app.Command("command1", "command1 description", func(cmd *Cmd) {}) | |
939 | app.Command("command2", "command2 description", func(cmd *Cmd) {}) | |
940 | app.Command("command3", "command3 description", func(cmd *Cmd) { | |
941 | cmd.Command("child1", "child1 description", func(cmd *Cmd) { | |
942 | cmd.StringArg("ARG1", "", "arg1 desc") | |
943 | }) | |
944 | cmd.Command("child2", "child2 description", func(cmd *Cmd) { | |
945 | cmd.Hidden = true | |
946 | cmd.StringOpt("o opt", "", "opt desc") | |
947 | }) | |
948 | }) | |
949 | app.Command("command4", "command4 description", func(cmd *Cmd) { | |
950 | cmd.Hidden = true | |
951 | }) | |
952 | ||
953 | t.Logf("calling app with %+v", cas.params) | |
954 | require.NoError(t, | |
955 | app.Run(cas.params)) | |
956 | ||
957 | filename := fmt.Sprintf("testdata/help-output-%s.txt", cas.name) | |
958 | ||
959 | if *genGolden { | |
960 | require.NoError(t, | |
961 | ioutil.WriteFile(filename, []byte(stdErr), 0644)) | |
962 | } | |
963 | ||
964 | expected, e := ioutil.ReadFile(filename) | |
965 | require.NoError(t, e, "Failed to read the expected help output from %s", filename) | |
966 | ||
967 | require.Equal(t, string(expected), stdErr) | |
968 | }) | |
969 | } | |
858 | 970 | } |
859 | 971 | |
860 | 972 | func TestLongHelpMessage(t *testing.T) { |
2200 | 2312 | return captureAndRestoreOutput(nil, nil) |
2201 | 2313 | } |
2202 | 2314 | |
2315 | func setAndRestoreEnv(env map[string]string) func() { | |
2316 | backup := map[string]string{} | |
2317 | for k, v := range env { | |
2318 | backup[k] = os.Getenv(k) | |
2319 | os.Setenv(k, v) | |
2320 | } | |
2321 | ||
2322 | return func() { | |
2323 | for k, v := range backup { | |
2324 | os.Setenv(k, v) | |
2325 | } | |
2326 | } | |
2327 | } | |
2328 | ||
2203 | 2329 | func captureAndRestoreOutput(out, err *string) func() { |
2204 | 2330 | oldStdOut := stdOut |
2205 | 2331 | oldStdErr := stdErr |
11 | 11 | "github.com/jawher/mow.cli/internal/fsm" |
12 | 12 | "github.com/jawher/mow.cli/internal/lexer" |
13 | 13 | "github.com/jawher/mow.cli/internal/parser" |
14 | "github.com/jawher/mow.cli/internal/values" | |
15 | 14 | ) |
16 | 15 | |
17 | 16 | /* |
30 | 29 | Spec string |
31 | 30 | // The command long description to be shown when help is requested |
32 | 31 | LongDesc string |
32 | // Hide this command in the help messages | |
33 | Hidden bool | |
33 | 34 | // The command error handling strategy |
34 | 35 | ErrorHandling flag.ErrorHandling |
35 | 36 | |
543 | 544 | for _, arg := range c.args { |
544 | 545 | var ( |
545 | 546 | env = formatEnvVarsForHelp(arg.EnvVar) |
546 | value = formatValueForHelp(arg.HideValue, arg.Value) | |
547 | value = formatValueForHelp(arg.HideValue, arg.DefaultValue) | |
547 | 548 | ) |
548 | 549 | printTabbedRow(w, arg.Name, joinStrings(arg.Desc, env, value)) |
549 | 550 | } |
556 | 557 | var ( |
557 | 558 | optNames = formatOptNamesForHelp(opt) |
558 | 559 | env = formatEnvVarsForHelp(opt.EnvVar) |
559 | value = formatValueForHelp(opt.HideValue, opt.Value) | |
560 | value = formatValueForHelp(opt.HideValue, opt.DefaultValue) | |
560 | 561 | ) |
561 | 562 | printTabbedRow(w, optNames, joinStrings(opt.Desc, env, value)) |
562 | 563 | } |
563 | 564 | } |
564 | 565 | |
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 { | |
566 | 580 | fmt.Fprint(w, "\t\nCommands:\t\n") |
567 | 581 | |
568 | for _, c := range c.commands { | |
582 | for _, c := range commands { | |
569 | 583 | fmt.Fprintf(w, " %s\t%s\n", strings.Join(c.aliases, ", "), c.desc) |
570 | 584 | } |
571 | 585 | } |
572 | 586 | |
573 | if len(c.commands) > 0 { | |
587 | if len(commands) > 0 { | |
574 | 588 | fmt.Fprintf(w, "\t\nRun '%s COMMAND --help' for more information on a command.\n", path) |
575 | 589 | } |
576 | 590 | |
603 | 617 | } |
604 | 618 | } |
605 | 619 | |
606 | func formatValueForHelp(hide bool, v flag.Value) string { | |
620 | func formatValueForHelp(hide bool, v string) string { | |
607 | 621 | if hide { |
608 | 622 | return "" |
609 | 623 | } |
610 | 624 | |
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) | |
618 | 630 | } |
619 | 631 | |
620 | 632 | func formatEnvVarsForHelp(envVars string) string { |
635 | 647 | } |
636 | 648 | |
637 | 649 | func (c *Cmd) parse(args []string, entry, inFlow, outFlow *flow.Step) error { |
638 | if c.helpRequested(args) { | |
650 | helpIndex := c.helpIndex(args) | |
651 | nargsLen := c.getOptsAndArgs(args) | |
652 | ||
653 | if helpIndex >= 0 && helpIndex < nargsLen { | |
639 | 654 | c.PrintLongHelp() |
640 | 655 | c.onError(errHelpRequested) |
641 | 656 | return nil |
642 | 657 | } |
643 | 658 | |
644 | nargsLen := c.getOptsAndArgs(args) | |
659 | // help was requested, but not for this command, skip the validation | |
660 | if helpIndex >= 0 { | |
661 | arg := args[nargsLen] | |
662 | for _, sub := range c.commands { | |
663 | if !sub.isAlias(arg) { | |
664 | continue | |
665 | } | |
666 | ||
667 | if err := sub.doInit(); err != nil { | |
668 | panic(err) | |
669 | } | |
670 | ||
671 | return sub.parse(args[nargsLen+1:], entry, nil, nil) | |
672 | } | |
673 | // impossible case | |
674 | panic("wut") | |
675 | } | |
645 | 676 | |
646 | 677 | if err := c.fsm.Parse(args[:nargsLen]); err != nil { |
647 | 678 | fmt.Fprintf(stdErr, "Error: %s\n", err.Error()) |
710 | 741 | |
711 | 742 | } |
712 | 743 | |
713 | func (c *Cmd) helpRequested(args []string) bool { | |
714 | return c.isFlagSet(args, []string{"-h", "--help"}) | |
715 | } | |
716 | ||
717 | func (c *Cmd) isFlagSet(args []string, searchArgs []string) bool { | |
744 | func (c *Cmd) helpIndex(args []string) int { | |
745 | searchSet := []string{"-h", "--help"} | |
746 | for i, arg := range args { | |
747 | if arg == "--" { | |
748 | return -1 | |
749 | } | |
750 | for _, searchArg := range searchSet { | |
751 | if arg == searchArg { | |
752 | return i | |
753 | } | |
754 | } | |
755 | } | |
756 | return -1 | |
757 | } | |
758 | ||
759 | func (c *Cmd) isFirstItemAmong(args []string, searchSet []string) bool { | |
718 | 760 | if len(args) == 0 { |
719 | 761 | return false |
720 | 762 | } |
721 | 763 | |
722 | 764 | arg := args[0] |
723 | for _, searchArg := range searchArgs { | |
765 | for _, searchArg := range searchSet { | |
724 | 766 | if arg == searchArg { |
725 | 767 | return true |
726 | 768 | } |
286 | 286 | $ docker job r # using the alias we defined |
287 | 287 | $ docker job log show |
288 | 288 | $ 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 | } | |
289 | 297 | |
290 | 298 | As a convenience, to assign an Action to a func with no arguments, use |
291 | 299 | ActionCommand when defining the Command. For example, the following two |
0 | 0 | module github.com/jawher/mow.cli |
1 | 1 | |
2 | 2 | require ( |
3 | github.com/stretchr/objx v0.2.0 // indirect | |
4 | github.com/stretchr/testify v1.3.0 | |
3 | github.com/davecgh/go-spew v1.1.1 // indirect | |
4 | github.com/stretchr/testify v1.4.0 | |
5 | gopkg.in/yaml.v2 v2.2.5 // indirect | |
5 | 6 | ) |
7 | ||
8 | go 1.13 |
3 | 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
4 | 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
5 | 5 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
6 | 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= | |
9 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= | |
10 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | |
6 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= | |
7 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | |
8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | |
9 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |
10 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |
11 | gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= | |
12 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
13 | 13 | ValueSetFromEnv bool |
14 | 14 | ValueSetByUser *bool |
15 | 15 | Value flag.Value |
16 | DefaultValue string | |
16 | 17 | } |
53 | 53 | |
54 | 54 | return nil |
55 | 55 | } |
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 | } |
466 | 466 | } |
467 | 467 | |
468 | 468 | func (c *Cmd) mkOpt(opt container.Container) { |
469 | opt.DefaultValue = values.DefaultValue(opt.Value) | |
469 | 470 | opt.ValueSetFromEnv = values.SetFromEnv(opt.Value, opt.EnvVar) |
470 | 471 | |
471 | 472 | opt.Names = mkOptStrs(opt.Name) |
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 [-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 | ||
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. |