├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── action.go
├── cli.go
├── cli_test.go
├── clir.go
├── clir_logo.png
├── clir_test.go
├── command.go
├── command_test.go
├── examples
├── basic
│ └── main.go
├── chained
│ └── main.go
├── custom-banner
│ └── main.go
├── custom-flag-error
│ └── main.go
├── default
│ └── main.go
├── flags-compact
│ └── main.go
├── flags-function
│ └── main.go
├── flags-positional
│ └── main.go
├── flags-slice
│ └── main.go
├── flags
│ └── main.go
├── flagstruct
│ └── main.go
├── hidden
│ └── main.go
├── nested-subcommands
│ └── main.go
├── otherargs
│ └── main.go
├── subcommandinheritflags
│ └── main.go
└── subcommands
│ └── main.go
├── go.mod
├── go.sum
└── website
├── docs
├── examples
│ ├── basic.md
│ ├── chained.md
│ ├── custom-banner.md
│ ├── custom-flag-error.md
│ ├── default.md
│ ├── flags-compact.md
│ ├── flags-function.md
│ ├── flags-positional.md
│ ├── flags-slice.md
│ ├── flags.md
│ ├── flagstruct.md
│ ├── hidden.md
│ ├── nested-subcommands.md
│ ├── otherargs.md
│ ├── subcommandinheritflags.md
│ └── subcommands.md
├── faq.md
├── gettingstarted.md
├── guide
│ ├── actions.md
│ ├── cli.md
│ ├── custombanner.md
│ ├── flags.md
│ ├── index.md
│ ├── otherargs.md
│ ├── prepostrun.md
│ └── subcommands.md
├── index.md
└── static
│ ├── clir_logo.png
│ └── clir_logo_white.png
├── mkdocs.yml
└── requirements.txt
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: build
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 | types: [assigned, opened, synchronize, reopened]
9 |
10 | jobs:
11 | build:
12 | name: Build & run examples
13 | runs-on: ${{ matrix.os }}
14 | strategy:
15 | matrix:
16 | os: [macos-latest, ubuntu-latest, windows-latest]
17 | steps:
18 |
19 | - name: Set up Go 1.19
20 | uses: actions/setup-go@v5
21 | with:
22 | go-version: 1.22
23 | id: go
24 |
25 | - name: Check out code
26 | uses: actions/checkout@master
27 |
28 | - name: Build basic
29 | run: go build -v ./examples/basic
30 |
31 | - name: Run basic
32 | run: ./basic
33 |
34 | - name: Build chained
35 | run: go build -v ./examples/chained
36 |
37 | - name: Run chained
38 | run: ./chained -name World -age 30 -awesome true
39 |
40 | - name: Build custom-banner
41 | run: go build -v ./examples/custom-banner
42 |
43 | - name: Run custom-banner
44 | run: ./custom-banner -help
45 |
46 | - name: Build flags
47 | run: go build -v ./examples/flags
48 |
49 | - name: Run flags
50 | run: ./flags -name World -age 30 -awesome true
51 |
52 | - name: Build flags-compact
53 | run: go build -v ./examples/flags-compact
54 |
55 | - name: Run flags-compact
56 | run: ./flags-compact -name World -age 30 -awesome true
57 |
58 | - name: Build nested-subcommands
59 | run: go build -v ./examples/nested-subcommands
60 |
61 | - name: Run nested-subcommands top
62 | run: ./nested-subcommands top
63 |
64 | - name: Run nested-subcommands middle
65 | run: ./nested-subcommands top middle
66 |
67 | - name: Run nested-subcommands bottom
68 | run: ./nested-subcommands top middle bottom
69 |
70 | - name: Build subcommands
71 | run: go build -v ./examples/subcommands
72 |
73 | - name: Run subcommands init
74 | run: ./subcommands init
75 |
76 | - name: Run subcommands test
77 | run: ./subcommands test
78 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, build with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 | examples/otherargs/otherargs
14 | .idea
15 | website/site
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 |
8 | - `Added` for new features.
9 | - `Changed` for changes in existing functionality.
10 | - `Deprecated` for soon-to-be removed features.
11 | - `Removed` for now removed features.
12 | - `Fixed` for any bug fixes.
13 | - `Security` in case of vulnerabilities.
14 |
15 | ## [Unreleased]
16 |
17 | ### Added
18 | - Added support for slice flags. Added by @zkep in [PR](https://github.com/leaanthony/clir/pull/23)
19 |
20 | ### Fixed
21 |
22 | ### Changed
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Lea Anthony
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | 
3 |
4 |
5 | A Simple and Clear CLI library. Dependency free.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ### Features
18 |
19 | * Nested Subcommands
20 | * Uses the standard library `flag` package
21 | * Struct based flags
22 | * Positional Args
23 | * Auto-generated help
24 | * Custom banners
25 | * Hidden Subcommands
26 | * Default Subcommand
27 | * Dependency free
28 |
29 | ### Example
30 |
31 | ```go
32 | package main
33 |
34 | import (
35 | "fmt"
36 |
37 | "github.com/leaanthony/clir"
38 | )
39 |
40 | func main() {
41 | // Create new cli
42 | cli := clir.NewCli("Flags", "A simple example", "v0.0.1")
43 |
44 | // Name
45 | name := "Anonymous"
46 | cli.StringFlag("name", "Your name", &name)
47 |
48 | // Define action for the command
49 | cli.Action(func() error {
50 | fmt.Printf("Hello %s!\n", name)
51 | return nil
52 | })
53 |
54 | if err := cli.Run(); err != nil {
55 | fmt.Printf("Error encountered: %v\n", err)
56 | }
57 | }
58 | ```
59 |
60 | #### Generated Help
61 |
62 | ```shell
63 | $ flags --help
64 | Flags v0.0.1 - A simple example
65 |
66 | Flags:
67 |
68 | -help
69 | Get help on the 'flags' command.
70 | -name string
71 | Your name
72 | ```
73 |
74 | #### Documentation
75 |
76 | The main documentation may be found [here](https://clir.leaanthony.com).
77 |
78 | #### License Status
79 |
80 | [](https://app.fossa.com/projects/git%2Bgithub.com%2Fleaanthony%2Fclir?ref=badge_large)
81 |
--------------------------------------------------------------------------------
/action.go:
--------------------------------------------------------------------------------
1 | package clir
2 |
3 | // Action represents a function that gets calls when the command is called by
4 | // the user
5 | type Action func() error
6 |
--------------------------------------------------------------------------------
/cli.go:
--------------------------------------------------------------------------------
1 | package clir
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | )
7 |
8 | // Cli - The main application object.
9 | type Cli struct {
10 | version string
11 | rootCommand *Command
12 | defaultCommand *Command
13 | preRunCommand func(*Cli) error
14 | postRunCommand func(*Cli) error
15 | bannerFunction func(*Cli) string
16 | errorHandler func(string, error) error
17 | }
18 |
19 | // Version - Get the Application version string.
20 | func (c *Cli) Version() string {
21 | return c.version
22 | }
23 |
24 | // Name - Get the Application Name
25 | func (c *Cli) Name() string {
26 | return c.rootCommand.name
27 | }
28 |
29 | // ShortDescription - Get the Application short description.
30 | func (c *Cli) ShortDescription() string {
31 | return c.rootCommand.shortdescription
32 | }
33 |
34 | // SetBannerFunction - Set the function that is called
35 | // to get the banner string.
36 | func (c *Cli) SetBannerFunction(fn func(*Cli) string) {
37 | c.bannerFunction = fn
38 | }
39 |
40 | // SetErrorFunction - Set custom error message when undefined
41 | // flags are used by the user. First argument is a string containing
42 | // the command path used. Second argument is the undefined flag error.
43 | func (c *Cli) SetErrorFunction(fn func(string, error) error) {
44 | c.errorHandler = fn
45 | }
46 |
47 | // AddCommand - Adds a command to the application.
48 | func (c *Cli) AddCommand(command *Command) {
49 | c.rootCommand.AddCommand(command)
50 | }
51 |
52 | // PrintBanner - Prints the application banner!
53 | func (c *Cli) PrintBanner() {
54 | fmt.Println(c.bannerFunction(c))
55 | fmt.Println("")
56 | }
57 |
58 | // PrintHelp - Prints the application's help.
59 | func (c *Cli) PrintHelp() {
60 | c.rootCommand.PrintHelp()
61 | }
62 |
63 | // Run - Runs the application with the given arguments.
64 | func (c *Cli) Run(args ...string) error {
65 | if c.preRunCommand != nil {
66 | err := c.preRunCommand(c)
67 | if err != nil {
68 | return err
69 | }
70 | }
71 | if len(args) == 0 {
72 | args = os.Args[1:]
73 | }
74 | if err := c.rootCommand.run(args); err != nil {
75 | return err
76 | }
77 |
78 | if c.postRunCommand != nil {
79 | err := c.postRunCommand(c)
80 | if err != nil {
81 | return err
82 | }
83 | }
84 |
85 | return nil
86 | }
87 |
88 | // DefaultCommand - Sets the given command as the command to run when
89 | // no other commands given.
90 | func (c *Cli) DefaultCommand(defaultCommand *Command) *Cli {
91 | c.defaultCommand = defaultCommand
92 | return c
93 | }
94 |
95 | // NewSubCommand - Creates a new SubCommand for the application.
96 | func (c *Cli) NewSubCommand(name, description string) *Command {
97 | return c.rootCommand.NewSubCommand(name, description)
98 | }
99 |
100 | // NewSubCommandInheritFlags - Creates a new SubCommand for the application, inherit flags from parent Command
101 | func (c *Cli) NewSubCommandInheritFlags(name, description string) *Command {
102 | return c.rootCommand.NewSubCommandInheritFlags(name, description)
103 | }
104 |
105 | // PreRun - Calls the given function before running the specific command.
106 | func (c *Cli) PreRun(callback func(*Cli) error) {
107 | c.preRunCommand = callback
108 | }
109 |
110 | // PostRun - Calls the given function after running the specific command.
111 | func (c *Cli) PostRun(callback func(*Cli) error) {
112 | c.postRunCommand = callback
113 | }
114 |
115 | // BoolFlag - Adds a boolean flag to the root command.
116 | func (c *Cli) BoolFlag(name, description string, variable *bool) *Cli {
117 | c.rootCommand.BoolFlag(name, description, variable)
118 | return c
119 | }
120 |
121 | // StringFlag - Adds a string flag to the root command.
122 | func (c *Cli) StringFlag(name, description string, variable *string) *Cli {
123 | c.rootCommand.StringFlag(name, description, variable)
124 | return c
125 | }
126 |
127 | // IntFlag - Adds an int flag to the root command.
128 | func (c *Cli) IntFlag(name, description string, variable *int) *Cli {
129 | c.rootCommand.IntFlag(name, description, variable)
130 | return c
131 | }
132 |
133 | func (c *Cli) AddFlags(flags interface{}) *Cli {
134 | c.rootCommand.AddFlags(flags)
135 | return c
136 | }
137 |
138 | // Action - Define an action from this command.
139 | func (c *Cli) Action(callback Action) *Cli {
140 | c.rootCommand.Action(callback)
141 | return c
142 | }
143 |
144 | // LongDescription - Sets the long description for the command.
145 | func (c *Cli) LongDescription(longdescription string) *Cli {
146 | c.rootCommand.LongDescription(longdescription)
147 | return c
148 | }
149 |
150 | // OtherArgs - Returns the non-flag arguments passed to the cli.
151 | // NOTE: This should only be called within the context of an action.
152 | func (c *Cli) OtherArgs() []string {
153 | return c.rootCommand.flags.Args()
154 | }
155 |
156 | func (c *Cli) NewSubCommandFunction(name string, description string, test interface{}) *Cli {
157 | c.rootCommand.NewSubCommandFunction(name, description, test)
158 | return c
159 | }
160 |
--------------------------------------------------------------------------------
/cli_test.go:
--------------------------------------------------------------------------------
1 | package clir
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "testing"
7 | )
8 |
9 | func TestCli(t *testing.T) {
10 | c := NewCli("test", "description", "0")
11 |
12 | t.Run("Run SetBannerFunction()", func(t *testing.T) {
13 | c.SetBannerFunction(func(*Cli) string { return "" })
14 | })
15 |
16 | t.Run("Run SetFlagFunction()", func(t *testing.T) {
17 | c.SetErrorFunction(func(cmdPath string, err error) error { return err })
18 | })
19 |
20 | t.Run("Run AddCommand()", func(t *testing.T) {
21 | c.AddCommand(&Command{name: "test"})
22 | })
23 |
24 | t.Run("Run PrintBanner()", func(t *testing.T) {
25 | c.PrintBanner()
26 | })
27 |
28 | t.Run("Run Run()", func(t *testing.T) {
29 | c.Run("test")
30 | c.Run()
31 |
32 | c.preRunCommand = func(*Cli) error { return errors.New("testing coverage") }
33 | c.Run("test")
34 | c.postRunCommand = func(*Cli) error { return errors.New("testing coverage") }
35 | })
36 |
37 | t.Run("Run DefaultCommand()", func(t *testing.T) {
38 | c.DefaultCommand(&Command{})
39 | })
40 |
41 | t.Run("Run NewSubCommand()", func(t *testing.T) {
42 | c.NewSubCommand("name", "description")
43 | })
44 |
45 | t.Run("Run PreRun()", func(t *testing.T) {
46 | c.PreRun(func(*Cli) error { return nil })
47 | })
48 |
49 | t.Run("Run PostRun()", func(t *testing.T) {
50 | c.PostRun(func(*Cli) error { return nil })
51 | })
52 |
53 | t.Run("Run BoolFlag()", func(t *testing.T) {
54 | var variable bool
55 | c.BoolFlag("bool", "description", &variable)
56 | })
57 |
58 | t.Run("Run StringFlag()", func(t *testing.T) {
59 | var variable string
60 | c.StringFlag("string", "description", &variable)
61 | })
62 |
63 | t.Run("Run IntFlag()", func(t *testing.T) {
64 | var variable int
65 | c.IntFlag("int", "description", &variable)
66 | })
67 |
68 | t.Run("Run Action()", func(t *testing.T) {
69 | c.Action(func() error { return nil })
70 | })
71 |
72 | t.Run("Run LongDescription()", func(t *testing.T) {
73 | c.LongDescription("long description")
74 | })
75 | }
76 |
77 | type testStruct struct {
78 | Mode string `name:"mode" description:"The mode of build"`
79 | Count int
80 | }
81 |
82 | func TestCli_CLIAddFlags(t *testing.T) {
83 | c := NewCli("test", "description", "0")
84 |
85 | ts := &testStruct{}
86 | c.AddFlags(ts)
87 |
88 | modeFlag := c.rootCommand.flags.Lookup("mode")
89 | if modeFlag == nil {
90 | t.Errorf("expected flag mode to be added")
91 | }
92 | if modeFlag.Name != "mode" {
93 | t.Errorf("expected flag name to be added")
94 | }
95 | if modeFlag.Usage != "The mode of build" {
96 | t.Errorf("expected flag description to be added")
97 | }
98 |
99 | c.Action(func() error {
100 | if ts.Mode != "123" {
101 | t.Errorf("expected flag value to be set")
102 | }
103 | return nil
104 | })
105 | e := c.Run("-mode", "123")
106 | if e != nil {
107 | t.Errorf("expected no error, got %v", e)
108 | }
109 | }
110 |
111 | func TestCli_CommandAddFlags(t *testing.T) {
112 | c := NewCli("test", "description", "0")
113 | sub := c.NewSubCommand("sub", "sub description")
114 |
115 | ts := &testStruct{}
116 | sub.AddFlags(ts)
117 |
118 | sub.Action(func() error {
119 | if ts.Mode != "123" {
120 | t.Errorf("expected flag value to be set")
121 | }
122 | return nil
123 | })
124 | e := c.Run("sub", "-mode", "123")
125 | if e != nil {
126 | t.Errorf("expected no error, got %v", e)
127 | }
128 | }
129 |
130 | func TestCli_InheritFlags(t *testing.T) {
131 | c := NewCli("test", "description", "0")
132 | var name string
133 | c.StringFlag("name", "name of person", &name)
134 | sub := c.NewSubCommandInheritFlags("sub", "sub description")
135 |
136 | sub.Action(func() error {
137 | if name != "Janet" {
138 | t.Errorf("expected name to be Janet")
139 | }
140 | return nil
141 | })
142 | e := c.Run("sub", "-name", "Janet")
143 | if e != nil {
144 | t.Errorf("expected no error, got %v", e)
145 | }
146 |
147 | }
148 |
149 | func TestCli_CommandAddFlagsWrongType(t *testing.T) {
150 | c := NewCli("test", "description", "0")
151 | sub := c.NewSubCommand("sub", "sub description")
152 |
153 | recoverTest := func() {
154 | var r interface{}
155 | if r = recover(); r == nil {
156 | t.Errorf("expected panic")
157 | }
158 | if r.(string) != "AddFlags() requires a pointer to a struct" {
159 | t.Errorf(`Expected: "AddFlags() requires a pointer to a struct". Got: "` + r.(string) + `"`)
160 | }
161 | }
162 |
163 | defer recoverTest()
164 |
165 | ts := testStruct{}
166 | sub.AddFlags(ts)
167 |
168 | e := c.Run("sub", "-mode", "123")
169 | if e != nil {
170 | t.Errorf("expected no error, got %v", e)
171 | }
172 |
173 | }
174 |
175 | func TestCli_CommandAddFlagsWrongPointerType(t *testing.T) {
176 | c := NewCli("test", "description", "0")
177 | sub := c.NewSubCommand("sub", "sub description")
178 |
179 | recoverTest := func() {
180 | var r interface{}
181 | if r = recover(); r == nil {
182 | t.Errorf("expected panic")
183 | }
184 | if r.(string) != "AddFlags() requires a pointer to a struct" {
185 | t.Errorf(`Expected: "AddFlags() requires a pointer to a struct". Got: "` + r.(string) + `"`)
186 | }
187 | }
188 |
189 | defer recoverTest()
190 |
191 | var i *int
192 | sub.AddFlags(i)
193 |
194 | e := c.Run("sub", "-mode", "123")
195 | if e != nil {
196 | t.Errorf("expected no error, got %v", e)
197 | }
198 |
199 | }
200 |
201 | func TestCli_CommandOtherSubArgs(t *testing.T) {
202 | c := NewCli("test", "description", "0")
203 | sub := c.NewSubCommand("sub", "sub description")
204 |
205 | ts := &testStruct{}
206 | sub.AddFlags(ts)
207 |
208 | sub.Action(func() error {
209 | if ts.Mode != "123" {
210 | t.Errorf("expected flag value to be set")
211 | }
212 | other := sub.OtherArgs()
213 | if len(other) != 2 {
214 | t.Errorf("expected 2 other args, got %v", other)
215 | }
216 | if other[0] != "other" {
217 | t.Errorf("expected other arg to be 'other', got %v", other[0])
218 | }
219 | if other[1] != "args" {
220 | t.Errorf("expected other arg to be 'args', got %v", other[1])
221 | }
222 | return nil
223 | })
224 | e := c.Run("sub", "-mode", "123", "other", "args")
225 | if e != nil {
226 | t.Errorf("expected no error, got %v", e)
227 | }
228 |
229 | }
230 | func TestCli_CommandOtherCLIArgs(t *testing.T) {
231 | c := NewCli("test", "description", "0")
232 |
233 | c.Action(func() error {
234 | other := c.OtherArgs()
235 | if len(other) != 2 {
236 | t.Errorf("expected 2 other args, got %v", other)
237 | }
238 | if other[0] != "other" {
239 | t.Errorf("expected other arg to be 'other', got %v", other[0])
240 | }
241 | if other[1] != "args" {
242 | t.Errorf("expected other arg to be 'args', got %v", other[1])
243 | }
244 | return nil
245 | })
246 | e := c.Run("other", "args")
247 | if e != nil {
248 | t.Errorf("expected no error, got %v", e)
249 | }
250 |
251 | }
252 |
253 | type Person struct {
254 | Name string `description:"The name of the person"`
255 | Age int `description:"The age of the person"`
256 | SSN uint `description:"The SSN of the person"`
257 | Age64 int64 `description:"The age of the person"`
258 | SSN64 uint64 `description:"The SSN of the person"`
259 | BankBalance float64 `description:"The bank balance of the person"`
260 | Married bool `description:"Whether the person is married"`
261 | }
262 |
263 | func TestCli_CommandAddFunction(t *testing.T) {
264 | c := NewCli("test", "description", "0")
265 |
266 | createPerson := func(person *Person) error {
267 | if person.Name != "Bob" {
268 | t.Errorf("expected name flag to be 'Bob', got %v", person.Name)
269 | }
270 | if person.Age != 30 {
271 | t.Errorf("expected age flag to be 30, got %v", person.Age)
272 | }
273 | if person.SSN != 123456789 {
274 | t.Errorf("expected ssn flag to be 123456789, got %v", person.SSN)
275 | }
276 | if person.Age64 != 30 {
277 | t.Errorf("expected age64 flag to be 30, got %v", person.Age64)
278 | }
279 | if person.SSN64 != 123456789 {
280 | t.Errorf("expected ssn64 flag to be 123456789, got %v", person.SSN64)
281 | }
282 | if person.BankBalance != 123.45 {
283 | t.Errorf("expected bankbalance flag to be 123.45, got %v", person.BankBalance)
284 | }
285 | if person.Married != true {
286 | t.Errorf("expected married flag to be true, got %v", person.Married)
287 | }
288 | return nil
289 | }
290 |
291 | c.NewSubCommandFunction("create", "create a person", createPerson)
292 |
293 | e := c.Run("create", "-name", "Bob", "-age", "30", "-ssn", "123456789", "-age64", "30", "-ssn64", "123456789", "-bankbalance", "123.45", "-married")
294 | if e != nil {
295 | t.Errorf("expected no error, got %v", e)
296 | }
297 |
298 | }
299 |
300 | type Person2 struct {
301 | Name string `description:"The name of the person" default:"Janet"`
302 | }
303 |
304 | func TestCli_CommandAddFunctionDefaults(t *testing.T) {
305 | c := NewCli("test", "description", "0")
306 |
307 | createPerson := func(person *Person2) error {
308 | if person.Name != "Janet" {
309 | t.Errorf("expected name flag to be 'Janet', got %v", person.Name)
310 | }
311 | return nil
312 | }
313 |
314 | c.NewSubCommandFunction("create", "create a person", createPerson)
315 |
316 | e := c.Run("create")
317 | if e != nil {
318 | t.Errorf("expected no error, got %v", e)
319 | }
320 |
321 | }
322 |
323 | func TestCli_CommandAddFunctionNoFunctionError(t *testing.T) {
324 | c := NewCli("test", "description", "0")
325 |
326 | recoverTest := func() {
327 | var r interface{}
328 | if r = recover(); r == nil {
329 | t.Errorf("expected panic")
330 | }
331 | if r.(string) != "NewSubFunction 'create' requires a function with the signature 'func(*struct) error'" {
332 | t.Errorf(`expected error message to be: "NewSubFunction 'create' requires a function with the signature 'func(*struct) error'". Got: "` + r.(string) + `"`)
333 | }
334 | }
335 |
336 | defer recoverTest()
337 |
338 | c.NewSubCommandFunction("create", "create a person", 0)
339 |
340 | e := c.Run("create")
341 | if e != nil {
342 | t.Errorf("expected no error, got %v", e)
343 | }
344 |
345 | }
346 | func TestCli_CommandAddFunctionNoPointerError(t *testing.T) {
347 | c := NewCli("test", "description", "0")
348 |
349 | recoverTest := func() {
350 | var r interface{}
351 | if r = recover(); r == nil {
352 | t.Errorf("expected panic")
353 | }
354 | if r.(string) != "NewSubFunction 'create' requires a function with the signature 'func(*struct) error'" {
355 | t.Errorf(`expected error message to be: "NewSubFunction 'create' requires a function with the signature 'func(*struct) error'". Got: "` + r.(string) + `"`)
356 | }
357 | }
358 |
359 | defer recoverTest()
360 |
361 | c.NewSubCommandFunction("create", "create a person", func(person Person2) error {
362 | return nil
363 | })
364 |
365 | e := c.Run("create")
366 | if e != nil {
367 | t.Errorf("expected no error, got %v", e)
368 | }
369 |
370 | }
371 |
372 | func TestCli_CommandAddFunctionMultipleInputError(t *testing.T) {
373 | c := NewCli("test", "description", "0")
374 |
375 | recoverTest := func() {
376 | var r interface{}
377 | if r = recover(); r == nil {
378 | t.Errorf("expected panic")
379 | }
380 | if r.(string) != "NewSubFunction 'create' requires a function with the signature 'func(*struct) error'" {
381 | t.Errorf(`expected error message to be: "NewSubFunction 'create' requires a function with the signature 'func(*struct) error'". Got: "` + r.(string) + `"`)
382 | }
383 | }
384 |
385 | defer recoverTest()
386 |
387 | c.NewSubCommandFunction("create", "create a person", func(person *Person2, count int) error {
388 | return nil
389 | })
390 |
391 | e := c.Run("create")
392 | if e != nil {
393 | t.Errorf("expected no error, got %v", e)
394 | }
395 |
396 | }
397 |
398 | func TestCli_CommandAddFunctionNoInputError(t *testing.T) {
399 | c := NewCli("test", "description", "0")
400 |
401 | recoverTest := func() {
402 | var r interface{}
403 | if r = recover(); r == nil {
404 | t.Errorf("expected panic")
405 | }
406 | if r.(string) != "NewSubFunction 'create' requires a function with the signature 'func(*struct) error'" {
407 | t.Errorf(`expected error message to be: "NewSubFunction 'create' requires a function with the signature 'func(*struct) error'". Got: "` + r.(string) + `"`)
408 | }
409 | }
410 |
411 | defer recoverTest()
412 |
413 | c.NewSubCommandFunction("create", "create a person", func() error {
414 | return nil
415 | })
416 |
417 | e := c.Run("create")
418 | if e != nil {
419 | t.Errorf("expected no error, got %v", e)
420 | }
421 |
422 | }
423 |
424 | func TestCli_CommandAddFunctionNoReturnError(t *testing.T) {
425 | c := NewCli("test", "description", "0")
426 |
427 | recoverTest := func() {
428 | var r interface{}
429 | if r = recover(); r == nil {
430 | t.Errorf("expected panic")
431 | }
432 | if r.(string) != "NewSubFunction 'create' requires a function with the signature 'func(*struct) error'" {
433 | t.Errorf(`expected error message to be: "NewSubFunction 'create' requires a function with the signature 'func(*struct) error'". Got: "` + r.(string) + `"`)
434 | }
435 | }
436 |
437 | defer recoverTest()
438 |
439 | c.NewSubCommandFunction("create", "create a person", func(person *Person2) {
440 | })
441 |
442 | e := c.Run("create")
443 | if e != nil {
444 | t.Errorf("expected no error, got %v", e)
445 | }
446 | }
447 |
448 | func TestCli_CommandAddFunctionWrongReturnError(t *testing.T) {
449 | c := NewCli("test", "description", "0")
450 |
451 | recoverTest := func() {
452 | var r interface{}
453 | if r = recover(); r == nil {
454 | t.Errorf("expected panic")
455 | }
456 | if r.(string) != "NewSubFunction 'create' requires a function with the signature 'func(*struct) error'" {
457 | t.Errorf(`expected error message to be: "NewSubFunction 'create' requires a function with the signature 'func(*struct) error'". Got: "` + r.(string) + `"`)
458 | }
459 | }
460 |
461 | defer recoverTest()
462 |
463 | c.NewSubCommandFunction("create", "create a person", func(person *Person2) int {
464 | return 0
465 | })
466 |
467 | e := c.Run("create")
468 | if e != nil {
469 | t.Errorf("expected no error, got %v", e)
470 | }
471 | }
472 |
473 | func TestCli_CommandAddFunctionDefaultWrongTypeOfInputsError(t *testing.T) {
474 | c := NewCli("test", "description", "0")
475 |
476 | recoverTest := func() {
477 | var r interface{}
478 | if r = recover(); r == nil {
479 | t.Errorf("expected panic")
480 | }
481 | if r.(string) != "NewSubFunction 'create' requires a function with the signature 'func(*struct) error'" {
482 | t.Errorf(`expected error message to be: "NewSubFunction 'create' requires a function with the signature 'func(*struct) error'". Got: "` + r.(string) + `"`)
483 | }
484 | }
485 |
486 | defer recoverTest()
487 |
488 | c.NewSubCommandFunction("create", "create a person", func(person *int) error {
489 | return nil
490 | })
491 |
492 | e := c.Run("create")
493 | if e != nil {
494 | t.Errorf("expected no error, got %v", e)
495 | }
496 | }
497 |
498 | type Person7 struct {
499 | Name string `description:"The name of the person"`
500 | Admin bool `description:"Is the person an admin"`
501 | }
502 |
503 | func TestCli_CommandAddFunctionReturnsAnError(t *testing.T) {
504 | c := NewCli("test", "description", "0")
505 |
506 | c.NewSubCommandFunction("create", "create a person", func(person *Person7) error {
507 | return fmt.Errorf("error")
508 | })
509 |
510 | e := c.Run("create")
511 | if e == nil {
512 | t.Errorf("expected error, got nil")
513 | }
514 | }
515 |
516 | type PosPerson struct {
517 | Name string `description:"The name of the person" pos:"1"`
518 | Admin bool `description:"Is the person an admin" pos:"2"`
519 | }
520 |
521 | func TestCli_PositionalArgs(t *testing.T) {
522 | c := NewCli("test", "test positional args", "0")
523 |
524 | c.NewSubCommandFunction("create", "create a person", func(person *PosPerson) error {
525 | if person.Name != "bob" {
526 | t.Errorf("expected 'bob', got '%v'", person.Name)
527 | }
528 | if person.Admin != true {
529 | t.Errorf("expected true, got %v", person.Admin)
530 | }
531 | return nil
532 | })
533 |
534 | e := c.Run("create", "bob", "true")
535 |
536 | if e != nil {
537 | t.Errorf("unexpected error")
538 | }
539 | }
540 |
541 | type Person8 struct {
542 | Name string `description:"The name of the person" default:"bob"`
543 | Age uint `description:"The age of the person" default:"40"`
544 | NumberOfPets int `description:"The number of pets the person has" default:"2"`
545 | Salary float64 `description:"The salary of the person" default:"100000.00"`
546 | Admin bool `description:"Is the person an admin" default:"true"`
547 | }
548 |
549 | func TestCli_CommandAddFunctionUsesDefaults(t *testing.T) {
550 | c := NewCli("test", "description", "0")
551 |
552 | createPerson := func(person *Person8) error {
553 | if person.Name != "bob" {
554 | t.Errorf("expected name flag to be 'Bob', got %v", person.Name)
555 | }
556 | if person.Age != 40 {
557 | t.Errorf("expected age flag to be 40, got %v", person.Age)
558 | }
559 | if person.NumberOfPets != 2 {
560 | t.Errorf("expected NumberOfPets flag to be 2, got %v", person.NumberOfPets)
561 | }
562 | if person.Salary != 100000.00 {
563 | t.Errorf("expected Salary flag to be 100000.00, got %v", person.Salary)
564 | }
565 | if person.Admin != true {
566 | t.Errorf("expected Admin flag to be true, got %v", person.Admin)
567 | }
568 | return nil
569 | }
570 |
571 | c.NewSubCommandFunction("create", "create a person", createPerson)
572 |
573 | e := c.Run("create")
574 | if e != nil {
575 | t.Errorf("expected no error, got %v", e)
576 | }
577 | }
578 |
--------------------------------------------------------------------------------
/clir.go:
--------------------------------------------------------------------------------
1 | // Package clir provides a simple API for creating command line apps
2 | package clir
3 |
4 | import (
5 | "fmt"
6 | )
7 |
8 | // defaultBannerFunction prints a banner for the application.
9 | // If version is a blank string, it is ignored.
10 | func defaultBannerFunction(c *Cli) string {
11 | version := ""
12 | if len(c.Version()) > 0 {
13 | version = " " + c.Version()
14 | }
15 | return fmt.Sprintf("%s%s - %s", c.Name(), version, c.ShortDescription())
16 | }
17 |
18 | // NewCli - Creates a new Cli application object
19 | func NewCli(name, description, version string) *Cli {
20 | result := &Cli{
21 | version: version,
22 | bannerFunction: defaultBannerFunction,
23 | }
24 | result.rootCommand = NewCommand(name, description)
25 | result.rootCommand.setApp(result)
26 | result.rootCommand.setParentCommandPath("")
27 | return result
28 | }
29 |
--------------------------------------------------------------------------------
/clir_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leaanthony/clir/a8d9462bce754819cbd5a5596f22d68b3f318fb6/clir_logo.png
--------------------------------------------------------------------------------
/clir_test.go:
--------------------------------------------------------------------------------
1 | package clir
2 |
3 | import "testing"
4 |
5 | func TestClir(t *testing.T) {
6 | var mockCli *Cli
7 | t.Run("Run NewCli()", func(t *testing.T) {
8 | mockCli = NewCli("name", "description", "version")
9 | t.Log(mockCli)
10 | })
11 |
12 | t.Run("Run defaultBannerFunction()", func(t *testing.T) {
13 | err := defaultBannerFunction(mockCli)
14 | t.Log(err)
15 | })
16 | }
17 |
--------------------------------------------------------------------------------
/command.go:
--------------------------------------------------------------------------------
1 | package clir
2 |
3 | import (
4 | "errors"
5 | "flag"
6 | "fmt"
7 | "os"
8 | "reflect"
9 | "strconv"
10 | "strings"
11 | )
12 |
13 | // Command represents a command that may be run by the user
14 | type Command struct {
15 | name string
16 | commandPath string
17 | shortdescription string
18 | longdescription string
19 | subCommands []*Command
20 | subCommandsMap map[string]*Command
21 | longestSubcommand int
22 | actionCallback Action
23 | app *Cli
24 | flags *flag.FlagSet
25 | flagCount int
26 | helpFlag bool
27 | hidden bool
28 | positionalArgsMap map[string]reflect.Value
29 | sliceSeparator map[string]string
30 | }
31 |
32 | // NewCommand creates a new Command
33 | // func NewCommand(name string, description string, app *Cli, parentCommandPath string) *Command {
34 | func NewCommand(name string, description string) *Command {
35 | result := &Command{
36 | name: name,
37 | shortdescription: description,
38 | subCommandsMap: make(map[string]*Command),
39 | hidden: false,
40 | positionalArgsMap: make(map[string]reflect.Value),
41 | sliceSeparator: make(map[string]string),
42 | }
43 |
44 | return result
45 | }
46 |
47 | func (c *Command) setParentCommandPath(parentCommandPath string) {
48 | // Set up command path
49 | if parentCommandPath != "" {
50 | c.commandPath += parentCommandPath + " "
51 | }
52 | c.commandPath += c.name
53 |
54 | // Set up flag set
55 | c.flags = flag.NewFlagSet(c.commandPath, flag.ContinueOnError)
56 | c.BoolFlag("help", "Get help on the '"+strings.ToLower(c.commandPath)+"' command.", &c.helpFlag)
57 |
58 | // result.Flags.Usage = result.PrintHelp
59 |
60 | }
61 |
62 | func (c *Command) inheritFlags(inheritFlags *flag.FlagSet) {
63 | // inherit flags
64 | inheritFlags.VisitAll(func(f *flag.Flag) {
65 | if f.Name != "help" {
66 | c.flags.Var(f.Value, f.Name, f.Usage)
67 | }
68 | })
69 | }
70 |
71 | func (c *Command) setApp(app *Cli) {
72 | c.app = app
73 | }
74 |
75 | // parseFlags parses the given flags
76 | func (c *Command) parseFlags(args []string) error {
77 | // Parse flags
78 | tmp := os.Stderr
79 | os.Stderr = nil
80 | defer func() {
81 | os.Stderr = tmp
82 | }()
83 |
84 | // Credit: https://stackoverflow.com/a/74146375
85 | var positionalArgs []string
86 | for {
87 | if err := c.flags.Parse(args); err != nil {
88 | return err
89 | }
90 | // Consume all the flags that were parsed as flags.
91 | args = args[len(args)-c.flags.NArg():]
92 | if len(args) == 0 {
93 | break
94 | }
95 | // There's at least one flag remaining and it must be a positional arg since
96 | // we consumed all args that were parsed as flags. Consume just the first
97 | // one, and retry parsing, since subsequent args may be flags.
98 | positionalArgs = append(positionalArgs, args[0])
99 | args = args[1:]
100 | }
101 |
102 | // Parse just the positional args so that flagset.Args()/flagset.NArgs()
103 | // return the expected value.
104 | // Note: This should never return an error.
105 | err := c.flags.Parse(positionalArgs)
106 | if err != nil {
107 | return err
108 | }
109 |
110 | if len(positionalArgs) > 0 {
111 | return c.parsePositionalArgs(positionalArgs)
112 | }
113 | return nil
114 | }
115 |
116 | // Run - Runs the Command with the given arguments
117 | func (c *Command) run(args []string) error {
118 |
119 | // If we have arguments, process them
120 | if len(args) > 0 {
121 | // Check for subcommand
122 | subcommand := c.subCommandsMap[args[0]]
123 | if subcommand != nil {
124 | return subcommand.run(args[1:])
125 | }
126 |
127 | // Parse flags
128 | err := c.parseFlags(args)
129 | if err != nil {
130 | if c.app.errorHandler != nil {
131 | return c.app.errorHandler(c.commandPath, err)
132 | }
133 | return fmt.Errorf("Error: %s\nSee '%s --help' for usage", err, c.commandPath)
134 | }
135 |
136 | // Help takes precedence
137 | if c.helpFlag {
138 | c.PrintHelp()
139 | return nil
140 | }
141 | }
142 |
143 | // Do we have an action?
144 | if c.actionCallback != nil {
145 | return c.actionCallback()
146 | }
147 |
148 | // If we haven't specified a subcommand
149 | // check for an app level default command
150 | if c.app.defaultCommand != nil {
151 | // Prevent recursion!
152 | if c.app.defaultCommand != c {
153 | // only run default command if no args passed
154 | if len(args) == 0 {
155 | return c.app.defaultCommand.run(args)
156 | }
157 | }
158 | }
159 |
160 | // Nothing left we can do
161 | c.PrintHelp()
162 |
163 | return nil
164 | }
165 |
166 | // Action - Define an action from this command
167 | func (c *Command) Action(callback Action) *Command {
168 | c.actionCallback = callback
169 | return c
170 | }
171 |
172 | // PrintHelp - Output the help text for this command
173 | func (c *Command) PrintHelp() {
174 | c.app.PrintBanner()
175 |
176 | commandTitle := c.commandPath
177 | if c.shortdescription != "" {
178 | commandTitle += " - " + c.shortdescription
179 | }
180 | // Ignore root command
181 | if c.commandPath != c.name {
182 | fmt.Println(commandTitle)
183 | }
184 | if c.longdescription != "" {
185 | fmt.Println(c.longdescription + "\n")
186 | }
187 | if len(c.subCommands) > 0 {
188 | fmt.Println("Available commands:")
189 | fmt.Println("")
190 | for _, subcommand := range c.subCommands {
191 | if subcommand.isHidden() {
192 | continue
193 | }
194 | spacer := strings.Repeat(" ", 3+c.longestSubcommand-len(subcommand.name))
195 | isDefault := ""
196 | if subcommand.isDefaultCommand() {
197 | isDefault = "[default]"
198 | }
199 | fmt.Printf(" %s%s%s %s\n", subcommand.name, spacer, subcommand.shortdescription, isDefault)
200 | }
201 | fmt.Println("")
202 | }
203 | if c.flagCount > 0 {
204 | fmt.Println("Flags:")
205 | fmt.Println()
206 | c.flags.SetOutput(os.Stdout)
207 | c.flags.PrintDefaults()
208 | c.flags.SetOutput(os.Stderr)
209 |
210 | }
211 | fmt.Println()
212 | }
213 |
214 | // isDefaultCommand returns true if called on the default command
215 | func (c *Command) isDefaultCommand() bool {
216 | return c.app.defaultCommand == c
217 | }
218 |
219 | // isHidden returns true if the command is a hidden command
220 | func (c *Command) isHidden() bool {
221 | return c.hidden
222 | }
223 |
224 | // Hidden hides the command from the Help system
225 | func (c *Command) Hidden() {
226 | c.hidden = true
227 | }
228 |
229 | // NewSubCommand - Creates a new subcommand
230 | func (c *Command) NewSubCommand(name, description string) *Command {
231 | result := NewCommand(name, description)
232 | c.AddCommand(result)
233 | return result
234 | }
235 |
236 | // AddCommand - Adds a subcommand
237 | func (c *Command) AddCommand(command *Command) {
238 | command.setApp(c.app)
239 | command.setParentCommandPath(c.commandPath)
240 | name := command.name
241 | c.subCommands = append(c.subCommands, command)
242 | c.subCommandsMap[name] = command
243 | if len(name) > c.longestSubcommand {
244 | c.longestSubcommand = len(name)
245 | }
246 | }
247 |
248 | // NewSubCommandInheritFlags - Creates a new subcommand, inherits flags from command
249 | func (c *Command) NewSubCommandInheritFlags(name, description string) *Command {
250 | result := c.NewSubCommand(name, description)
251 | result.inheritFlags(c.flags)
252 | return result
253 | }
254 |
255 | func (c *Command) AddFlags(optionStruct interface{}) *Command {
256 | // use reflection to determine if this is a pointer to a struct
257 | // if not, panic
258 |
259 | t := reflect.TypeOf(optionStruct)
260 |
261 | // Check for a pointer to a struct
262 | if t.Kind() != reflect.Ptr {
263 | panic("AddFlags() requires a pointer to a struct")
264 | }
265 | if t.Elem().Kind() != reflect.Struct {
266 | panic("AddFlags() requires a pointer to a struct")
267 | }
268 |
269 | // Iterate through the fields of the struct reading the struct tags
270 | // and adding the flags
271 | v := reflect.ValueOf(optionStruct).Elem()
272 | for i := 0; i < v.NumField(); i++ {
273 | field := v.Field(i)
274 | fieldType := t.Elem().Field(i)
275 | if !fieldType.IsExported() {
276 | continue
277 | }
278 | // If this is an embedded struct, recurse
279 | if fieldType.Type.Kind() == reflect.Struct {
280 | c.AddFlags(field.Addr().Interface())
281 | continue
282 | }
283 |
284 | tag := t.Elem().Field(i).Tag
285 | name := tag.Get("name")
286 | description := tag.Get("description")
287 | defaultValue := tag.Get("default")
288 | pos := tag.Get("pos")
289 | sep := tag.Get("sep")
290 | c.positionalArgsMap[pos] = field
291 | if sep != "" {
292 | c.sliceSeparator[pos] = sep
293 | }
294 | if name == "" {
295 | name = strings.ToLower(t.Elem().Field(i).Name)
296 | }
297 | switch field.Kind() {
298 | case reflect.Bool:
299 | var defaultValueBool bool
300 | if defaultValue != "" {
301 | var err error
302 | defaultValueBool, err = strconv.ParseBool(defaultValue)
303 | if err != nil {
304 | panic("Invalid default value for bool flag")
305 | }
306 | }
307 | field.SetBool(defaultValueBool)
308 | c.BoolFlag(name, description, field.Addr().Interface().(*bool))
309 | case reflect.String:
310 | if defaultValue != "" {
311 | // set value of field to default value
312 | field.SetString(defaultValue)
313 | }
314 | c.StringFlag(name, description, field.Addr().Interface().(*string))
315 | case reflect.Int:
316 | if defaultValue != "" {
317 | // set value of field to default value
318 | value, err := strconv.Atoi(defaultValue)
319 | if err != nil {
320 | panic("Invalid default value for int flag")
321 | }
322 | field.SetInt(int64(value))
323 | }
324 | c.IntFlag(name, description, field.Addr().Interface().(*int))
325 | case reflect.Int8:
326 | if defaultValue != "" {
327 | // set value of field to default value
328 | value, err := strconv.Atoi(defaultValue)
329 | if err != nil {
330 | panic("Invalid default value for int8 flag")
331 | }
332 | field.SetInt(int64(value))
333 | }
334 | c.Int8Flag(name, description, field.Addr().Interface().(*int8))
335 | case reflect.Int16:
336 | if defaultValue != "" {
337 | // set value of field to default value
338 | value, err := strconv.Atoi(defaultValue)
339 | if err != nil {
340 | panic("Invalid default value for int16 flag")
341 | }
342 | field.SetInt(int64(value))
343 | }
344 | c.Int16Flag(name, description, field.Addr().Interface().(*int16))
345 | case reflect.Int32:
346 | if defaultValue != "" {
347 | // set value of field to default value
348 | value, err := strconv.Atoi(defaultValue)
349 | if err != nil {
350 | panic("Invalid default value for int32 flag")
351 | }
352 | field.SetInt(int64(value))
353 | }
354 | c.Int32Flag(name, description, field.Addr().Interface().(*int32))
355 | case reflect.Int64:
356 | if defaultValue != "" {
357 | // set value of field to default value
358 | value, err := strconv.Atoi(defaultValue)
359 | if err != nil {
360 | panic("Invalid default value for int64 flag")
361 | }
362 | field.SetInt(int64(value))
363 | }
364 | c.Int64Flag(name, description, field.Addr().Interface().(*int64))
365 | case reflect.Uint:
366 | if defaultValue != "" {
367 | // set value of field to default value
368 | value, err := strconv.Atoi(defaultValue)
369 | if err != nil {
370 | panic("Invalid default value for uint flag")
371 | }
372 | field.SetUint(uint64(value))
373 | }
374 | c.UintFlag(name, description, field.Addr().Interface().(*uint))
375 | case reflect.Uint8:
376 | if defaultValue != "" {
377 | // set value of field to default value
378 | value, err := strconv.Atoi(defaultValue)
379 | if err != nil {
380 | panic("Invalid default value for uint8 flag")
381 | }
382 | field.SetUint(uint64(value))
383 | }
384 | c.Uint8Flag(name, description, field.Addr().Interface().(*uint8))
385 | case reflect.Uint16:
386 | if defaultValue != "" {
387 | // set value of field to default value
388 | value, err := strconv.Atoi(defaultValue)
389 | if err != nil {
390 | panic("Invalid default value for uint16 flag")
391 | }
392 | field.SetUint(uint64(value))
393 | }
394 | c.Uint16Flag(name, description, field.Addr().Interface().(*uint16))
395 | case reflect.Uint32:
396 | if defaultValue != "" {
397 | // set value of field to default value
398 | value, err := strconv.Atoi(defaultValue)
399 | if err != nil {
400 | panic("Invalid default value for uint32 flag")
401 | }
402 | field.SetUint(uint64(value))
403 | }
404 | c.Uint32Flag(name, description, field.Addr().Interface().(*uint32))
405 | case reflect.Uint64:
406 | if defaultValue != "" {
407 | // set value of field to default value
408 | value, err := strconv.Atoi(defaultValue)
409 | if err != nil {
410 | panic("Invalid default value for uint64 flag")
411 | }
412 | field.SetUint(uint64(value))
413 | }
414 | c.UInt64Flag(name, description, field.Addr().Interface().(*uint64))
415 | case reflect.Float32:
416 | if defaultValue != "" {
417 | // set value of field to default value
418 | value, err := strconv.ParseFloat(defaultValue, 64)
419 | if err != nil {
420 | panic("Invalid default value for float32 flag")
421 | }
422 | field.SetFloat(value)
423 | }
424 | c.Float32Flag(name, description, field.Addr().Interface().(*float32))
425 | case reflect.Float64:
426 | if defaultValue != "" {
427 | // set value of field to default value
428 | value, err := strconv.ParseFloat(defaultValue, 64)
429 | if err != nil {
430 | panic("Invalid default value for float64 flag")
431 | }
432 | field.SetFloat(value)
433 | }
434 | c.Float64Flag(name, description, field.Addr().Interface().(*float64))
435 | case reflect.Slice:
436 | c.addSliceField(field, defaultValue, sep)
437 | c.addSliceFlags(name, description, field)
438 | default:
439 | if pos != "" {
440 | println("WARNING: Unsupported type for flag: ", fieldType.Type.Kind(), name)
441 | }
442 | }
443 | }
444 |
445 | return c
446 | }
447 |
448 | func (c *Command) addSliceFlags(name, description string, field reflect.Value) *Command {
449 | if field.Kind() != reflect.Slice {
450 | panic("addSliceFlags() requires a pointer to a slice")
451 | }
452 | t := reflect.TypeOf(field.Addr().Interface())
453 | if t.Kind() != reflect.Ptr {
454 | panic("addSliceFlags() requires a pointer to a slice")
455 | }
456 | if t.Elem().Kind() != reflect.Slice {
457 | panic("addSliceFlags() requires a pointer to a slice")
458 | }
459 | switch t.Elem().Elem().Kind() {
460 | case reflect.Bool:
461 | c.BoolsFlag(name, description, field.Addr().Interface().(*[]bool))
462 | case reflect.String:
463 | c.StringsFlag(name, description, field.Addr().Interface().(*[]string))
464 | case reflect.Int:
465 | c.IntsFlag(name, description, field.Addr().Interface().(*[]int))
466 | case reflect.Int8:
467 | c.Int8sFlag(name, description, field.Addr().Interface().(*[]int8))
468 | case reflect.Int16:
469 | c.Int16sFlag(name, description, field.Addr().Interface().(*[]int16))
470 | case reflect.Int32:
471 | c.Int32sFlag(name, description, field.Addr().Interface().(*[]int32))
472 | case reflect.Int64:
473 | c.Int64sFlag(name, description, field.Addr().Interface().(*[]int64))
474 | case reflect.Uint:
475 | c.UintsFlag(name, description, field.Addr().Interface().(*[]uint))
476 | case reflect.Uint8:
477 | c.Uint8sFlag(name, description, field.Addr().Interface().(*[]uint8))
478 | case reflect.Uint16:
479 | c.Uint16sFlag(name, description, field.Addr().Interface().(*[]uint16))
480 | case reflect.Uint32:
481 | c.Uint32sFlag(name, description, field.Addr().Interface().(*[]uint32))
482 | case reflect.Uint64:
483 | c.Uint64sFlag(name, description, field.Addr().Interface().(*[]uint64))
484 | case reflect.Float32:
485 | c.Float32sFlag(name, description, field.Addr().Interface().(*[]float32))
486 | case reflect.Float64:
487 | c.Float64sFlag(name, description, field.Addr().Interface().(*[]float64))
488 | default:
489 | panic(fmt.Sprintf("addSliceFlags() not supported slice type %s", t.Elem().Elem().Kind().String()))
490 | }
491 | return c
492 | }
493 |
494 | func (c *Command) addSliceField(field reflect.Value, defaultValue, separator string) *Command {
495 | if defaultValue == "" {
496 | return c
497 | }
498 | if field.Kind() != reflect.Slice {
499 | panic("addSliceField() requires a pointer to a slice")
500 | }
501 | t := reflect.TypeOf(field.Addr().Interface())
502 | if t.Kind() != reflect.Ptr {
503 | panic("addSliceField() requires a pointer to a slice")
504 | }
505 | if t.Elem().Kind() != reflect.Slice {
506 | panic("addSliceField() requires a pointer to a slice")
507 | }
508 | defaultSlice := []string{defaultValue}
509 | if separator != "" {
510 | defaultSlice = strings.Split(defaultValue, separator)
511 | }
512 | switch t.Elem().Elem().Kind() {
513 | case reflect.Bool:
514 | defaultValues := make([]bool, 0, len(defaultSlice))
515 | for _, value := range defaultSlice {
516 | val, err := strconv.ParseBool(value)
517 | if err != nil {
518 | panic("Invalid default value for bool flag")
519 | }
520 | defaultValues = append(defaultValues, val)
521 | }
522 | field.Set(reflect.ValueOf(defaultValues))
523 | case reflect.String:
524 | field.Set(reflect.ValueOf(defaultSlice))
525 | case reflect.Int:
526 | defaultValues := make([]int, 0, len(defaultSlice))
527 | for _, value := range defaultSlice {
528 | val, err := strconv.Atoi(value)
529 | if err != nil {
530 | panic("Invalid default value for int flag")
531 | }
532 | defaultValues = append(defaultValues, val)
533 | }
534 | field.Set(reflect.ValueOf(defaultValues))
535 | case reflect.Int8:
536 | defaultValues := make([]int8, 0, len(defaultSlice))
537 | for _, value := range defaultSlice {
538 | val, err := strconv.Atoi(value)
539 | if err != nil {
540 | panic("Invalid default value for int8 flag")
541 | }
542 | defaultValues = append(defaultValues, int8(val))
543 | }
544 | field.Set(reflect.ValueOf(defaultValues))
545 | case reflect.Int16:
546 | defaultValues := make([]int16, 0, len(defaultSlice))
547 | for _, value := range defaultSlice {
548 | val, err := strconv.Atoi(value)
549 | if err != nil {
550 | panic("Invalid default value for int16 flag")
551 | }
552 | defaultValues = append(defaultValues, int16(val))
553 | }
554 | field.Set(reflect.ValueOf(defaultValues))
555 | case reflect.Int32:
556 | defaultValues := make([]int32, 0, len(defaultSlice))
557 | for _, value := range defaultSlice {
558 | val, err := strconv.ParseInt(value, 10, 32)
559 | if err != nil {
560 | panic("Invalid default value for int32 flag")
561 | }
562 | defaultValues = append(defaultValues, int32(val))
563 | }
564 | field.Set(reflect.ValueOf(defaultValues))
565 | case reflect.Int64:
566 | defaultValues := make([]int64, 0, len(defaultSlice))
567 | for _, value := range defaultSlice {
568 | val, err := strconv.ParseInt(value, 10, 64)
569 | if err != nil {
570 | panic("Invalid default value for int64 flag")
571 | }
572 | defaultValues = append(defaultValues, val)
573 | }
574 | field.Set(reflect.ValueOf(defaultValues))
575 | case reflect.Uint:
576 | defaultValues := make([]uint, 0, len(defaultSlice))
577 | for _, value := range defaultSlice {
578 | val, err := strconv.Atoi(value)
579 | if err != nil {
580 | panic("Invalid default value for uint flag")
581 | }
582 | defaultValues = append(defaultValues, uint(val))
583 | }
584 | field.Set(reflect.ValueOf(defaultValues))
585 | case reflect.Uint8:
586 | defaultValues := make([]uint8, 0, len(defaultSlice))
587 | for _, value := range defaultSlice {
588 | val, err := strconv.Atoi(value)
589 | if err != nil {
590 | panic("Invalid default value for uint8 flag")
591 | }
592 | defaultValues = append(defaultValues, uint8(val))
593 | }
594 | field.Set(reflect.ValueOf(defaultValues))
595 | case reflect.Uint16:
596 | defaultValues := make([]uint16, 0, len(defaultSlice))
597 | for _, value := range defaultSlice {
598 | val, err := strconv.Atoi(value)
599 | if err != nil {
600 | panic("Invalid default value for uint16 flag")
601 | }
602 | defaultValues = append(defaultValues, uint16(val))
603 | }
604 | field.Set(reflect.ValueOf(defaultValues))
605 | case reflect.Uint32:
606 | defaultValues := make([]uint32, 0, len(defaultSlice))
607 | for _, value := range defaultSlice {
608 | val, err := strconv.Atoi(value)
609 | if err != nil {
610 | panic("Invalid default value for uint32 flag")
611 | }
612 | defaultValues = append(defaultValues, uint32(val))
613 | }
614 | field.Set(reflect.ValueOf(defaultValues))
615 | case reflect.Uint64:
616 | defaultValues := make([]uint64, 0, len(defaultSlice))
617 | for _, value := range defaultSlice {
618 | val, err := strconv.Atoi(value)
619 | if err != nil {
620 | panic("Invalid default value for uint64 flag")
621 | }
622 | defaultValues = append(defaultValues, uint64(val))
623 | }
624 | field.Set(reflect.ValueOf(defaultValues))
625 | case reflect.Float32:
626 | defaultValues := make([]float32, 0, len(defaultSlice))
627 | for _, value := range defaultSlice {
628 | val, err := strconv.Atoi(value)
629 | if err != nil {
630 | panic("Invalid default value for float32 flag")
631 | }
632 | defaultValues = append(defaultValues, float32(val))
633 | }
634 | field.Set(reflect.ValueOf(defaultValues))
635 | case reflect.Float64:
636 | defaultValues := make([]float64, 0, len(defaultSlice))
637 | for _, value := range defaultSlice {
638 | val, err := strconv.Atoi(value)
639 | if err != nil {
640 | panic("Invalid default value for float64 flag")
641 | }
642 | defaultValues = append(defaultValues, float64(val))
643 | }
644 | field.Set(reflect.ValueOf(defaultValues))
645 | default:
646 | panic(fmt.Sprintf("addSliceField() not supported slice type %s", t.Elem().Elem().Kind().String()))
647 | }
648 | return c
649 | }
650 |
651 | // BoolFlag - Adds a boolean flag to the command
652 | func (c *Command) BoolFlag(name, description string, variable *bool) *Command {
653 | c.flags.BoolVar(variable, name, *variable, description)
654 | c.flagCount++
655 | return c
656 | }
657 |
658 | // BoolsFlag - Adds a booleans flag to the command
659 | func (c *Command) BoolsFlag(name, description string, variable *[]bool) *Command {
660 | c.flags.Var(newBoolsValue(*variable, variable), name, description)
661 | c.flagCount++
662 | return c
663 | }
664 |
665 | // StringFlag - Adds a string flag to the command
666 | func (c *Command) StringFlag(name, description string, variable *string) *Command {
667 | c.flags.StringVar(variable, name, *variable, description)
668 | c.flagCount++
669 | return c
670 | }
671 |
672 | // StringsFlag - Adds a strings flag to the command
673 | func (c *Command) StringsFlag(name, description string, variable *[]string) *Command {
674 | c.flags.Var(newStringsValue(*variable, variable), name, description)
675 | c.flagCount++
676 | return c
677 | }
678 |
679 | // IntFlag - Adds an int flag to the command
680 | func (c *Command) IntFlag(name, description string, variable *int) *Command {
681 | c.flags.IntVar(variable, name, *variable, description)
682 | c.flagCount++
683 | return c
684 | }
685 |
686 | // IntsFlag - Adds an ints flag to the command
687 | func (c *Command) IntsFlag(name, description string, variable *[]int) *Command {
688 | c.flags.Var(newIntsValue(*variable, variable), name, description)
689 | c.flagCount++
690 | return c
691 | }
692 |
693 | // Int8Flag - Adds an int8 flag to the command
694 | func (c *Command) Int8Flag(name, description string, variable *int8) *Command {
695 | c.flags.Var(newInt8Value(*variable, variable), name, description)
696 | c.flagCount++
697 | return c
698 | }
699 |
700 | // Int8sFlag - Adds an int8 s flag to the command
701 | func (c *Command) Int8sFlag(name, description string, variable *[]int8) *Command {
702 | c.flags.Var(newInt8sValue(*variable, variable), name, description)
703 | c.flagCount++
704 | return c
705 | }
706 |
707 | // Int16Flag - Adds an int16 flag to the command
708 | func (c *Command) Int16Flag(name, description string, variable *int16) *Command {
709 | c.flags.Var(newInt16Value(*variable, variable), name, description)
710 | c.flagCount++
711 | return c
712 | }
713 |
714 | // Int16sFlag - Adds an int16s flag to the command
715 | func (c *Command) Int16sFlag(name, description string, variable *[]int16) *Command {
716 | c.flags.Var(newInt16sValue(*variable, variable), name, description)
717 | c.flagCount++
718 | return c
719 | }
720 |
721 | // Int32Flag - Adds an int32 flag to the command
722 | func (c *Command) Int32Flag(name, description string, variable *int32) *Command {
723 | c.flags.Var(newInt32Value(*variable, variable), name, description)
724 | c.flagCount++
725 | return c
726 | }
727 |
728 | // Int32sFlag - Adds an int32s flag to the command
729 | func (c *Command) Int32sFlag(name, description string, variable *[]int32) *Command {
730 | c.flags.Var(newInt32sValue(*variable, variable), name, description)
731 | c.flagCount++
732 | return c
733 | }
734 |
735 | // Int64Flag - Adds an int64 flag to the command
736 | func (c *Command) Int64Flag(name, description string, variable *int64) *Command {
737 | c.flags.Int64Var(variable, name, *variable, description)
738 | c.flagCount++
739 | return c
740 | }
741 |
742 | // Int64sFlag - Adds an int64s flag to the command
743 | func (c *Command) Int64sFlag(name, description string, variable *[]int64) *Command {
744 | c.flags.Var(newInt64sValue(*variable, variable), name, description)
745 | c.flagCount++
746 | return c
747 | }
748 |
749 | // UintFlag - Adds an uint flag to the command
750 | func (c *Command) UintFlag(name, description string, variable *uint) *Command {
751 | c.flags.UintVar(variable, name, *variable, description)
752 | c.flagCount++
753 | return c
754 | }
755 |
756 | // UintsFlag - Adds an uints flag to the command
757 | func (c *Command) UintsFlag(name, description string, variable *[]uint) *Command {
758 | c.flags.Var(newUintsValue(*variable, variable), name, description)
759 | c.flagCount++
760 | return c
761 | }
762 |
763 | // Uint8Flag - Adds an uint8 flag to the command
764 | func (c *Command) Uint8Flag(name, description string, variable *uint8) *Command {
765 | c.flags.Var(newUint8Value(*variable, variable), name, description)
766 | c.flagCount++
767 | return c
768 | }
769 |
770 | // Uint8sFlag - Adds an uint8 s flag to the command
771 | func (c *Command) Uint8sFlag(name, description string, variable *[]uint8) *Command {
772 | c.flags.Var(newUint8sValue(*variable, variable), name, description)
773 | c.flagCount++
774 | return c
775 | }
776 |
777 | // Uint16Flag - Adds an uint16 flag to the command
778 | func (c *Command) Uint16Flag(name, description string, variable *uint16) *Command {
779 | c.flags.Var(newUint16Value(*variable, variable), name, description)
780 | c.flagCount++
781 | return c
782 | }
783 |
784 | // Uint16sFlag - Adds an uint16s flag to the command
785 | func (c *Command) Uint16sFlag(name, description string, variable *[]uint16) *Command {
786 | c.flags.Var(newUint16sValue(*variable, variable), name, description)
787 | c.flagCount++
788 | return c
789 | }
790 |
791 | // Uint32Flag - Adds an uint32 flag to the command
792 | func (c *Command) Uint32Flag(name, description string, variable *uint32) *Command {
793 | c.flags.Var(newUint32Value(*variable, variable), name, description)
794 | c.flagCount++
795 | return c
796 | }
797 |
798 | // Uint32sFlag - Adds an uint32s flag to the command
799 | func (c *Command) Uint32sFlag(name, description string, variable *[]uint32) *Command {
800 | c.flags.Var(newUint32sValue(*variable, variable), name, description)
801 | c.flagCount++
802 | return c
803 | }
804 |
805 | // UInt64Flag - Adds an uint64 flag to the command
806 | func (c *Command) UInt64Flag(name, description string, variable *uint64) *Command {
807 | c.flags.Uint64Var(variable, name, *variable, description)
808 | c.flagCount++
809 | return c
810 | }
811 |
812 | // Uint64sFlag - Adds an uint64s flag to the command
813 | func (c *Command) Uint64sFlag(name, description string, variable *[]uint64) *Command {
814 | c.flags.Var(newUint64sValue(*variable, variable), name, description)
815 | c.flagCount++
816 | return c
817 | }
818 |
819 | // Float64Flag - Adds a float64 flag to the command
820 | func (c *Command) Float64Flag(name, description string, variable *float64) *Command {
821 | c.flags.Float64Var(variable, name, *variable, description)
822 | c.flagCount++
823 | return c
824 | }
825 |
826 | // Float32Flag - Adds a float32 flag to the command
827 | func (c *Command) Float32Flag(name, description string, variable *float32) *Command {
828 | c.flags.Var(newFloat32Value(*variable, variable), name, description)
829 | c.flagCount++
830 | return c
831 | }
832 |
833 | // Float32sFlag - Adds a float32s flag to the command
834 | func (c *Command) Float32sFlag(name, description string, variable *[]float32) *Command {
835 | c.flags.Var(newFloat32sValue(*variable, variable), name, description)
836 | c.flagCount++
837 | return c
838 | }
839 |
840 | // Float64sFlag - Adds a float64s flag to the command
841 | func (c *Command) Float64sFlag(name, description string, variable *[]float64) *Command {
842 | c.flags.Var(newFloat64sValue(*variable, variable), name, description)
843 | c.flagCount++
844 | return c
845 | }
846 |
847 | type boolsFlagVar []bool
848 |
849 | func (f *boolsFlagVar) String() string { return fmt.Sprint([]bool(*f)) }
850 |
851 | func (f *boolsFlagVar) Set(value string) error {
852 | if value == "" {
853 | *f = append(*f, false)
854 | return nil
855 | }
856 | b, err := strconv.ParseBool(value)
857 | if err != nil {
858 | return err
859 | }
860 | *f = append(*f, b)
861 | return nil
862 | }
863 |
864 | func (f *boolsFlagVar) IsBoolFlag() bool {
865 | return true
866 | }
867 |
868 | func newBoolsValue(val []bool, p *[]bool) *boolsFlagVar {
869 | *p = val
870 | return (*boolsFlagVar)(p)
871 | }
872 |
873 | type stringsFlagVar []string
874 |
875 | func (f *stringsFlagVar) String() string { return fmt.Sprint([]string(*f)) }
876 |
877 | func (f *stringsFlagVar) Set(value string) error {
878 | *f = append(*f, value)
879 | return nil
880 | }
881 |
882 | func newStringsValue(val []string, p *[]string) *stringsFlagVar {
883 | *p = val
884 | return (*stringsFlagVar)(p)
885 | }
886 |
887 | type intsFlagVar []int
888 |
889 | func (f *intsFlagVar) String() string { return fmt.Sprint([]int(*f)) }
890 |
891 | func (f *intsFlagVar) Set(value string) error {
892 | i, err := strconv.Atoi(value)
893 | if err != nil {
894 | return err
895 | }
896 | *f = append(*f, i)
897 | return nil
898 | }
899 |
900 | func newIntsValue(val []int, p *[]int) *intsFlagVar {
901 | *p = val
902 | return (*intsFlagVar)(p)
903 | }
904 |
905 | type int8Value int8
906 |
907 | func newInt8Value(val int8, p *int8) *int8Value {
908 | *p = val
909 | return (*int8Value)(p)
910 | }
911 |
912 | func (f *int8Value) Set(value string) error {
913 | i, err := strconv.Atoi(value)
914 | if err != nil {
915 | return err
916 | }
917 | *f = int8Value(i)
918 | return nil
919 | }
920 |
921 | func (f *int8Value) String() string { return fmt.Sprint(int8(*f)) }
922 |
923 | type int8sFlagVar []int8
924 |
925 | func (f *int8sFlagVar) String() string { return fmt.Sprint([]int8(*f)) }
926 |
927 | func (f *int8sFlagVar) Set(value string) error {
928 | i, err := strconv.Atoi(value)
929 | if err != nil {
930 | return err
931 | }
932 | *f = append(*f, int8(i))
933 | return nil
934 | }
935 |
936 | func newInt8sValue(val []int8, p *[]int8) *int8sFlagVar {
937 | *p = val
938 | return (*int8sFlagVar)(p)
939 | }
940 |
941 | type int16Value int16
942 |
943 | func newInt16Value(val int16, p *int16) *int16Value {
944 | *p = val
945 | return (*int16Value)(p)
946 | }
947 |
948 | func (f *int16Value) Set(value string) error {
949 | i, err := strconv.Atoi(value)
950 | if err != nil {
951 | return err
952 | }
953 | *f = int16Value(i)
954 | return nil
955 | }
956 |
957 | func (f *int16Value) String() string { return fmt.Sprint(int16(*f)) }
958 |
959 | type int16sFlagVar []int16
960 |
961 | func (f *int16sFlagVar) String() string { return fmt.Sprint([]int16(*f)) }
962 |
963 | func (f *int16sFlagVar) Set(value string) error {
964 | i, err := strconv.Atoi(value)
965 | if err != nil {
966 | return err
967 | }
968 | *f = append(*f, int16(i))
969 | return nil
970 | }
971 |
972 | func newInt16sValue(val []int16, p *[]int16) *int16sFlagVar {
973 | *p = val
974 | return (*int16sFlagVar)(p)
975 | }
976 |
977 | type int32Value int32
978 |
979 | func newInt32Value(val int32, p *int32) *int32Value {
980 | *p = val
981 | return (*int32Value)(p)
982 | }
983 |
984 | func (f *int32Value) Set(value string) error {
985 | i, err := strconv.Atoi(value)
986 | if err != nil {
987 | return err
988 | }
989 | *f = int32Value(i)
990 | return nil
991 | }
992 |
993 | func (f *int32Value) String() string { return fmt.Sprint(int32(*f)) }
994 |
995 | type int32sFlagVar []int32
996 |
997 | func (f *int32sFlagVar) String() string { return fmt.Sprint([]int32(*f)) }
998 |
999 | func (f *int32sFlagVar) Set(value string) error {
1000 | i, err := strconv.Atoi(value)
1001 | if err != nil {
1002 | return err
1003 | }
1004 | *f = append(*f, int32(i))
1005 | return nil
1006 | }
1007 |
1008 | func newInt32sValue(val []int32, p *[]int32) *int32sFlagVar {
1009 | *p = val
1010 | return (*int32sFlagVar)(p)
1011 | }
1012 |
1013 | type int64sFlagVar []int64
1014 |
1015 | func (f *int64sFlagVar) String() string { return fmt.Sprint([]int64(*f)) }
1016 |
1017 | func (f *int64sFlagVar) Set(value string) error {
1018 | i, err := strconv.ParseInt(value, 10, 64)
1019 | if err != nil {
1020 | return err
1021 | }
1022 | *f = append(*f, i)
1023 | return nil
1024 | }
1025 |
1026 | func newInt64sValue(val []int64, p *[]int64) *int64sFlagVar {
1027 | *p = val
1028 | return (*int64sFlagVar)(p)
1029 | }
1030 |
1031 | type uintsFlagVar []uint
1032 |
1033 | func (f *uintsFlagVar) String() string {
1034 | return fmt.Sprint([]uint(*f))
1035 | }
1036 |
1037 | func (f *uintsFlagVar) Set(value string) error {
1038 | i, err := strconv.Atoi(value)
1039 | if err != nil {
1040 | return err
1041 | }
1042 | *f = append(*f, uint(i))
1043 | return nil
1044 | }
1045 |
1046 | func newUintsValue(val []uint, p *[]uint) *uintsFlagVar {
1047 | *p = val
1048 | return (*uintsFlagVar)(p)
1049 | }
1050 |
1051 | type uint8FlagVar uint8
1052 |
1053 | func newUint8Value(val uint8, p *uint8) *uint8FlagVar {
1054 | *p = val
1055 | return (*uint8FlagVar)(p)
1056 | }
1057 |
1058 | func (f *uint8FlagVar) String() string {
1059 | return fmt.Sprint(uint8(*f))
1060 | }
1061 |
1062 | func (f *uint8FlagVar) Set(value string) error {
1063 | i, err := strconv.Atoi(value)
1064 | if err != nil {
1065 | return err
1066 | }
1067 | *f = uint8FlagVar(i)
1068 | return nil
1069 | }
1070 |
1071 | type uint8sFlagVar []uint8
1072 |
1073 | func (f *uint8sFlagVar) String() string {
1074 | return fmt.Sprint([]uint8(*f))
1075 | }
1076 |
1077 | func (f *uint8sFlagVar) Set(value string) error {
1078 | i, err := strconv.Atoi(value)
1079 | if err != nil {
1080 | return err
1081 | }
1082 | *f = append(*f, uint8(i))
1083 | return nil
1084 | }
1085 |
1086 | func newUint8sValue(val []uint8, p *[]uint8) *uint8sFlagVar {
1087 | *p = val
1088 | return (*uint8sFlagVar)(p)
1089 | }
1090 |
1091 | type uint16FlagVar uint16
1092 |
1093 | func newUint16Value(val uint16, p *uint16) *uint16FlagVar {
1094 | *p = val
1095 | return (*uint16FlagVar)(p)
1096 | }
1097 |
1098 | func (f *uint16FlagVar) String() string {
1099 | return fmt.Sprint(uint16(*f))
1100 | }
1101 |
1102 | func (f *uint16FlagVar) Set(value string) error {
1103 | i, err := strconv.Atoi(value)
1104 | if err != nil {
1105 | return err
1106 | }
1107 | *f = uint16FlagVar(i)
1108 | return nil
1109 | }
1110 |
1111 | type uint16sFlagVar []uint16
1112 |
1113 | func (f *uint16sFlagVar) String() string {
1114 | return fmt.Sprint([]uint16(*f))
1115 | }
1116 |
1117 | func (f *uint16sFlagVar) Set(value string) error {
1118 | i, err := strconv.Atoi(value)
1119 | if err != nil {
1120 | return err
1121 | }
1122 | *f = append(*f, uint16(i))
1123 | return nil
1124 | }
1125 |
1126 | func newUint16sValue(val []uint16, p *[]uint16) *uint16sFlagVar {
1127 | *p = val
1128 | return (*uint16sFlagVar)(p)
1129 | }
1130 |
1131 | type uint32FlagVar uint32
1132 |
1133 | func newUint32Value(val uint32, p *uint32) *uint32FlagVar {
1134 | *p = val
1135 | return (*uint32FlagVar)(p)
1136 | }
1137 |
1138 | func (f *uint32FlagVar) String() string {
1139 | return fmt.Sprint(uint32(*f))
1140 | }
1141 |
1142 | func (f *uint32FlagVar) Set(value string) error {
1143 | i, err := strconv.Atoi(value)
1144 | if err != nil {
1145 | return err
1146 | }
1147 | *f = uint32FlagVar(i)
1148 | return nil
1149 | }
1150 |
1151 | type uint32sFlagVar []uint32
1152 |
1153 | func (f *uint32sFlagVar) String() string {
1154 | return fmt.Sprint([]uint32(*f))
1155 | }
1156 |
1157 | func (f *uint32sFlagVar) Set(value string) error {
1158 | i, err := strconv.Atoi(value)
1159 | if err != nil {
1160 | return err
1161 | }
1162 | *f = append(*f, uint32(i))
1163 | return nil
1164 | }
1165 |
1166 | func newUint32sValue(val []uint32, p *[]uint32) *uint32sFlagVar {
1167 | *p = val
1168 | return (*uint32sFlagVar)(p)
1169 | }
1170 |
1171 | type uint64sFlagVar []uint64
1172 |
1173 | func (f *uint64sFlagVar) String() string { return fmt.Sprint([]uint64(*f)) }
1174 |
1175 | func (f *uint64sFlagVar) Set(value string) error {
1176 | i, err := strconv.ParseUint(value, 10, 64)
1177 | if err != nil {
1178 | return err
1179 | }
1180 | *f = append(*f, i)
1181 | return nil
1182 | }
1183 |
1184 | func newUint64sValue(val []uint64, p *[]uint64) *uint64sFlagVar {
1185 | *p = val
1186 | return (*uint64sFlagVar)(p)
1187 | }
1188 |
1189 | type float32sFlagVar []float32
1190 |
1191 | func (f *float32sFlagVar) String() string { return fmt.Sprint([]float32(*f)) }
1192 |
1193 | func (f *float32sFlagVar) Set(value string) error {
1194 | i, err := strconv.ParseFloat(value, 64)
1195 | if err != nil {
1196 | return err
1197 | }
1198 | *f = append(*f, float32(i))
1199 | return nil
1200 | }
1201 |
1202 | func newFloat32sValue(val []float32, p *[]float32) *float32sFlagVar {
1203 | *p = val
1204 | return (*float32sFlagVar)(p)
1205 | }
1206 |
1207 | type float32FlagVar float32
1208 |
1209 | func (f *float32FlagVar) String() string { return fmt.Sprint(float32(*f)) }
1210 |
1211 | func (f *float32FlagVar) Set(value string) error {
1212 | i, err := strconv.ParseFloat(value, 64)
1213 | if err != nil {
1214 | return err
1215 | }
1216 | *f = float32FlagVar(i)
1217 | return nil
1218 | }
1219 |
1220 | func newFloat32Value(val float32, p *float32) *float32FlagVar {
1221 | *p = val
1222 | return (*float32FlagVar)(p)
1223 | }
1224 |
1225 | type float64sFlagVar []float64
1226 |
1227 | func (f *float64sFlagVar) String() string { return fmt.Sprint([]float64(*f)) }
1228 |
1229 | func (f *float64sFlagVar) Set(value string) error {
1230 | i, err := strconv.ParseFloat(value, 64)
1231 | if err != nil {
1232 | return err
1233 | }
1234 | *f = append(*f, i)
1235 | return nil
1236 | }
1237 |
1238 | func newFloat64sValue(val []float64, p *[]float64) *float64sFlagVar {
1239 | *p = val
1240 | return (*float64sFlagVar)(p)
1241 | }
1242 |
1243 | // LongDescription - Sets the long description for the command
1244 | func (c *Command) LongDescription(longdescription string) *Command {
1245 | c.longdescription = longdescription
1246 | return c
1247 | }
1248 |
1249 | // OtherArgs - Returns the non-flag arguments passed to the subcommand. NOTE: This should only be called within the context of an action.
1250 | func (c *Command) OtherArgs() []string {
1251 | return c.flags.Args()
1252 | }
1253 |
1254 | func (c *Command) NewSubCommandFunction(name string, description string, fn interface{}) *Command {
1255 | result := c.NewSubCommand(name, description)
1256 | // use reflection to determine if this is a function
1257 | // if not, panic
1258 | t := reflect.TypeOf(fn)
1259 | if t.Kind() != reflect.Func {
1260 | panic("NewSubFunction '" + name + "' requires a function with the signature 'func(*struct) error'")
1261 | }
1262 |
1263 | // Check the function has 1 input ant it's a struct pointer
1264 | fnValue := reflect.ValueOf(fn)
1265 | if t.NumIn() != 1 {
1266 | panic("NewSubFunction '" + name + "' requires a function with the signature 'func(*struct) error'")
1267 | }
1268 | // Check the input is a struct pointer
1269 | if t.In(0).Kind() != reflect.Ptr {
1270 | panic("NewSubFunction '" + name + "' requires a function with the signature 'func(*struct) error'")
1271 | }
1272 | if t.In(0).Elem().Kind() != reflect.Struct {
1273 | panic("NewSubFunction '" + name + "' requires a function with the signature 'func(*struct) error'")
1274 | }
1275 | // Check only 1 output and it's an error
1276 | if t.NumOut() != 1 {
1277 | panic("NewSubFunction '" + name + "' requires a function with the signature 'func(*struct) error'")
1278 | }
1279 | if t.Out(0) != reflect.TypeOf((*error)(nil)).Elem() {
1280 | panic("NewSubFunction '" + name + "' requires a function with the signature 'func(*struct) error'")
1281 | }
1282 | flags := reflect.New(t.In(0).Elem())
1283 | result.Action(func() error {
1284 | result := fnValue.Call([]reflect.Value{flags})[0].Interface()
1285 | if result != nil {
1286 | return result.(error)
1287 | }
1288 | return nil
1289 | })
1290 | result.AddFlags(flags.Interface())
1291 | return result
1292 | }
1293 |
1294 | func (c *Command) parsePositionalArgs(args []string) error {
1295 | for index, posArg := range args {
1296 | // Check the map for a field for this arg
1297 | key := strconv.Itoa(index + 1)
1298 | field, ok := c.positionalArgsMap[key]
1299 | if !ok {
1300 | continue
1301 | }
1302 | fieldType := field.Type()
1303 | switch fieldType.Kind() {
1304 | case reflect.Bool:
1305 | // set value of field to true
1306 | field.SetBool(true)
1307 | case reflect.String:
1308 | field.SetString(posArg)
1309 | case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
1310 | value, err := strconv.ParseInt(posArg, 10, 64)
1311 | if err != nil {
1312 | return err
1313 | }
1314 | field.SetInt(value)
1315 | case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint:
1316 | value, err := strconv.ParseUint(posArg, 10, 64)
1317 | if err != nil {
1318 | return err
1319 | }
1320 | field.SetUint(value)
1321 | case reflect.Float64, reflect.Float32:
1322 | value, err := strconv.ParseFloat(posArg, 64)
1323 | if err != nil {
1324 | return err
1325 | }
1326 | field.SetFloat(value)
1327 | case reflect.Slice:
1328 | c.addSliceField(field, posArg, c.sliceSeparator[key])
1329 | default:
1330 | return errors.New("Unsupported type for positional argument: " + fieldType.Name())
1331 | }
1332 | }
1333 | return nil
1334 | }
1335 |
--------------------------------------------------------------------------------
/command_test.go:
--------------------------------------------------------------------------------
1 | package clir
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestCommand(t *testing.T) {
8 | c := &Command{}
9 |
10 | t.Run("Run NewCommand()", func(t *testing.T) {
11 | c = NewCommand("test", "test description")
12 | })
13 |
14 | t.Run("Run setParentCommandPath()", func(t *testing.T) {
15 | c.setParentCommandPath("path")
16 | })
17 |
18 | t.Run("Run setApp()", func(t *testing.T) {
19 | c.setApp(&Cli{})
20 | })
21 |
22 | t.Run("Run parseFlags()", func(t *testing.T) {
23 | err := c.parseFlags([]string{"test", "flags"})
24 | t.Log(err)
25 | })
26 |
27 | t.Run("Run run()", func(t *testing.T) {
28 | cl := NewCli("test", "description", "0")
29 | cl.rootCommand.run([]string{"test"})
30 |
31 | cl.rootCommand.subCommandsMap["test"] = &Command{
32 | name: "subcom",
33 | shortdescription: "short description",
34 | hidden: false,
35 | app: cl,
36 | }
37 | cl.rootCommand.run([]string{"test"})
38 |
39 | cl.rootCommand.run([]string{"---"})
40 |
41 | cl.rootCommand.run([]string{"-help"})
42 |
43 | // cl.rootCommand.actionCallback = func() error {
44 | // println("Hello World!")
45 | // return nil
46 | // }
47 | // cl.rootCommand.run([]string{"test"})
48 |
49 | cl.rootCommand.app.defaultCommand = &Command{
50 | name: "subcom",
51 | shortdescription: "short description",
52 | hidden: false,
53 | app: cl,
54 | }
55 | cl.rootCommand.run([]string{"test"})
56 | })
57 |
58 | t.Run("Run Action()", func(t *testing.T) {
59 | c.Action(func() error { return nil })
60 |
61 | })
62 |
63 | t.Run("Run PrintHelp()", func(t *testing.T) {
64 | cl := NewCli("test", "description", "0")
65 |
66 | // co.shortdescription = ""
67 | cl.PrintHelp()
68 |
69 | cl.rootCommand.shortdescription = "test"
70 | cl.PrintHelp()
71 |
72 | cl.rootCommand.commandPath = "notTest"
73 | cl.PrintHelp()
74 |
75 | cl.rootCommand.longdescription = ""
76 | cl.PrintHelp()
77 |
78 | cl.rootCommand.longdescription = "test"
79 | cl.PrintHelp()
80 |
81 | mockCommand := &Command{
82 | name: "test",
83 | shortdescription: "short description",
84 | hidden: true,
85 | longestSubcommand: len("test"),
86 | }
87 | cl.rootCommand.subCommands = append(cl.rootCommand.subCommands, mockCommand)
88 | cl.PrintHelp()
89 |
90 | mockCommand = &Command{
91 | name: "subcom",
92 | shortdescription: "short description",
93 | hidden: false,
94 | app: cl,
95 | }
96 | cl.rootCommand.longestSubcommand = 10
97 | cl.rootCommand.subCommands = append(cl.rootCommand.subCommands, mockCommand)
98 | cl.PrintHelp()
99 |
100 | mockCommand = &Command{
101 | name: "subcom",
102 | shortdescription: "short description",
103 | hidden: false,
104 | app: cl,
105 | }
106 | cl.rootCommand.longestSubcommand = 10
107 | cl.defaultCommand = mockCommand
108 | cl.rootCommand.subCommands = append(cl.rootCommand.subCommands, mockCommand)
109 | cl.PrintHelp()
110 |
111 | cl.rootCommand.flagCount = 3
112 | cl.PrintHelp()
113 | })
114 |
115 | t.Run("Run isDefaultCommand()", func(t *testing.T) {
116 | c.isDefaultCommand()
117 |
118 | })
119 |
120 | t.Run("Run isHidden()", func(t *testing.T) {
121 | c.isHidden()
122 |
123 | })
124 |
125 | t.Run("Run Hidden()", func(t *testing.T) {
126 | c.Hidden()
127 | })
128 |
129 | t.Run("Run NewSubCommand()", func(t *testing.T) {
130 | c.NewSubCommand("name", "description")
131 |
132 | })
133 |
134 | t.Run("Run NewSubCommandInheritFlags()", func(t *testing.T) {
135 | inherit := false
136 | c.BoolFlag("inherit", "test inherence", &inherit)
137 | s := c.NewSubCommandInheritFlags("name", "description")
138 | if s.flags.Lookup("inherit") == nil {
139 | t.Error("flag inherence")
140 | t.Fail()
141 | }
142 | })
143 |
144 | t.Run("Run inheritFlags()", func(t *testing.T) {
145 | inheritFlag := false
146 | c.BoolFlag("inheritFlag", "test inherence", &inheritFlag)
147 | s := c.NewSubCommand("name", "description")
148 | s.inheritFlags(c.flags)
149 | if s.flags.Lookup("inheritFlag") == nil {
150 | t.Error("flag inherence")
151 | t.Fail()
152 | }
153 | })
154 |
155 | t.Run("Run AddCommand()", func(t *testing.T) {
156 | c.AddCommand(c)
157 | })
158 |
159 | t.Run("Run StringFlag()", func(t *testing.T) {
160 | variable := "variable"
161 | c.StringFlag("name", "description", &variable)
162 | })
163 |
164 | t.Run("Run IntFlag()", func(t *testing.T) {
165 | var variable int
166 | c.IntFlag("test", "description", &variable)
167 | })
168 |
169 | t.Run("Run LongDescription()", func(t *testing.T) {
170 | c.LongDescription("name")
171 | })
172 | }
173 |
--------------------------------------------------------------------------------
/examples/basic/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/leaanthony/clir"
5 | )
6 |
7 | func main() {
8 |
9 | // Create new cli
10 | cli := clir.NewCli("Basic", "A basic example", "v0.0.1")
11 |
12 | // Set long description
13 | cli.LongDescription("This app prints hello world")
14 |
15 | // Define action
16 | cli.Action(func() error {
17 | println("Hello World!")
18 | return nil
19 | })
20 |
21 | // Run!
22 | cli.Run()
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/examples/chained/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/leaanthony/clir"
7 | )
8 |
9 | func main() {
10 |
11 | // Vars
12 | var name string
13 | var age int
14 | var awesome bool
15 |
16 | // More chain than Fleetwood Mac
17 | clir.NewCli("Flags", "An example of using flags", "v0.0.1").
18 | StringFlag("name", "Your name", &name).
19 | IntFlag("age", "Your age", &age).
20 | BoolFlag("awesome", "Are you awesome?", &awesome).
21 | Action(func() error {
22 |
23 | if name == "" {
24 | name = "Anonymous"
25 | }
26 | fmt.Printf("Hello %s!\n", name)
27 |
28 | if age > 0 {
29 | fmt.Printf("You are %d years old!\n", age)
30 | }
31 |
32 | if awesome {
33 | fmt.Println("You are awesome!")
34 | }
35 |
36 | return nil
37 | }).Run()
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/examples/custom-banner/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/leaanthony/clir"
5 | )
6 |
7 | func customBanner(cli *clir.Cli) string {
8 |
9 | return `
10 | ______ __ __ ______ _________ ______ ___ __ __
11 | /_____/\ /_/\/_/\ /_____/\ /________/\/_____/\ /__//_//_/\
12 | \:::__\/ \:\ \:\ \\::::_\/_\__.::.__\/\:::_ \ \\::\| \| \ \
13 | \:\ \ __\:\ \:\ \\:\/___/\ \::\ \ \:\ \ \ \\:. \ \
14 | \:\ \/_/\\:\ \:\ \\_::._\:\ \::\ \ \:\ \ \ \\:.\-/\ \ \
15 | \:\_\ \ \\:\_\:\ \ /____\:\ \::\ \ \:\_\ \ \\. \ \ \ \
16 | \_____\/ \_____\/ \_____\/ \__\/ \_____\/ \__\/ \__\/
17 | ` + cli.Version() + " - " + cli.ShortDescription()
18 | }
19 |
20 | func main() {
21 |
22 | // Create new cli
23 | cli := clir.NewCli("Banner", "A custom banner example", "v0.0.1")
24 |
25 | cli.SetBannerFunction(customBanner)
26 |
27 | // Define action
28 | cli.Action(func() error {
29 | println("Hello World!")
30 | return nil
31 | })
32 |
33 | // Run!
34 | cli.Run()
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/examples/custom-flag-error/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/leaanthony/clir"
7 | )
8 |
9 | func customFlagError(cmdPath string, err error) error {
10 | return fmt.Errorf(`%s
11 | flag v0.0.1 - A custom error example
12 |
13 | Flags:
14 |
15 | --help
16 | Get help on the '%s' command`, err, cmdPath)
17 | }
18 |
19 | func main() {
20 |
21 | // Create new cli
22 | cli := clir.NewCli("flag", "A custom error example", "v0.0.1")
23 |
24 | cli.SetErrorFunction(customFlagError)
25 |
26 | cli.NewSubCommand("test", "Testing whether subcommand path returns correctly via err callback")
27 |
28 | // Run!
29 | if err := cli.Run(); err != nil {
30 | fmt.Println(err)
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/examples/default/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/leaanthony/clir"
5 | )
6 |
7 | func main() {
8 |
9 | // Create new cli
10 | cli := clir.NewCli("subcommands", "An example of subcommands", "v0.0.1")
11 |
12 | // Create an init subcommand
13 | init := cli.NewSubCommand("init", "Initialise the app")
14 | init.Action(func() error {
15 | println("I am initialising!")
16 | return nil
17 | })
18 |
19 | // Create a test subcommand
20 | test := cli.NewSubCommand("test", "Test the app")
21 | test.Action(func() error {
22 | println("I am testing!")
23 | return nil
24 | })
25 |
26 | // Set default command to run
27 | cli.DefaultCommand(init)
28 |
29 | // Run!
30 | cli.Run()
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/examples/flags-compact/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/leaanthony/clir"
7 | )
8 |
9 | func main() {
10 |
11 | // Vars
12 | var name string
13 | var age int
14 | var awesome bool
15 |
16 | // Create new cli
17 | cli := clir.NewCli("Flags", "An example of using flags", "v0.0.1")
18 |
19 | // Define flags
20 | cli.StringFlag("name", "Your name", &name).
21 | IntFlag("age", "Your age", &age).
22 | BoolFlag("awesome", "Are you awesome?", &awesome)
23 |
24 | // Define action
25 | cli.Action(func() error {
26 |
27 | if name == "" {
28 | name = "Anonymous"
29 | }
30 | fmt.Printf("Hello %s!\n", name)
31 |
32 | if age > 0 {
33 | fmt.Printf("You are %d years old!\n", age)
34 | }
35 |
36 | if awesome {
37 | fmt.Println("You are awesome!")
38 | }
39 |
40 | return nil
41 | })
42 |
43 | cli.Run()
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/examples/flags-function/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/leaanthony/clir"
7 | )
8 |
9 | type EmbeddedFlags struct {
10 | Address string `flag:"address" description:"The address of the person" default:"123 Main Street"`
11 | }
12 |
13 | type AppFlags struct {
14 | EmbeddedFlags
15 | Name string `default:"Bob" pos:"1"`
16 | Age int `default:"20" pos:"2"`
17 | }
18 |
19 | func main() {
20 |
21 | // Create new cli
22 | cli := clir.NewCli("Flags", "An example of using flags", "v0.0.1")
23 |
24 | cli.NewSubCommandFunction("create", "Create a new person", createPerson)
25 | cli.Run("create", "bob", "20", "--address", "123 Main Street")
26 | }
27 |
28 | func createPerson(flags *AppFlags) error {
29 | fmt.Println("Name:", flags.Name)
30 | fmt.Println("Age:", flags.Age)
31 | fmt.Println("Address:", flags.Address)
32 | return nil
33 | }
34 |
--------------------------------------------------------------------------------
/examples/flags-positional/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/leaanthony/clir"
7 | )
8 |
9 | type EmbeddedFlags struct {
10 | Address string `flag:"address" description:"The address of the person" default:"123 Main Street"`
11 | }
12 |
13 | type AppFlags struct {
14 | EmbeddedFlags
15 | Name string `default:"Bob"`
16 | Age int `default:"20"`
17 | }
18 |
19 | func main() {
20 |
21 | // Create new cli
22 | cli := clir.NewCli("Flags", "An example of using flags", "v0.0.1")
23 |
24 | cli.NewSubCommandFunction("create", "Create a new person", createPerson)
25 | cli.Run()
26 |
27 | }
28 |
29 | func createPerson(flags *AppFlags) error {
30 | fmt.Println("Name:", flags.Name)
31 | fmt.Println("Age:", flags.Age)
32 | fmt.Println("Address:", flags.Address)
33 | return nil
34 | }
35 |
--------------------------------------------------------------------------------
/examples/flags-slice/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/leaanthony/clir"
6 | "reflect"
7 | )
8 |
9 | type Flags struct {
10 | String string `name:"string" description:"The string" pos:"1"`
11 | Strings []string `name:"strings" description:"The strings" pos:"2"`
12 | StringsDefault []string `name:"strings_default" description:"The strings default" default:"one|two|three" sep:"|" pos:"3"`
13 |
14 | Int int `name:"int" description:"The int" pos:"4"`
15 | Ints []int `name:"ints" description:"The ints" pos:"5"`
16 | IntsDefault []int `name:"ints_default" description:"The ints default" default:"3|4|5" sep:"|" pos:"6"`
17 |
18 | Int8 int8 `name:"int8" description:"The int8" pos:"7"`
19 | Int8s []int8 `name:"int8s" description:"The int8s" pos:"8"`
20 | Int8sDefault []int8 `name:"int8s_default" description:"The int8s default" default:"3,4,5" sep:"," pos:"9"`
21 |
22 | Int16 int16 `name:"int16" description:"The int16" pos:"10"`
23 | Int16s []int16 `name:"int16s" description:"The int16s" pos:"11"`
24 | Int16sDefault []int16 `name:"int16s_default" description:"The int16s default" default:"3,4,5" sep:"," pos:"12"`
25 |
26 | Int32 int32 `name:"int32" description:"The int32" pos:"13"`
27 | Int32s []int32 `name:"int32s" description:"The int32s" pos:"14"`
28 | Int32sDefault []int32 `name:"int32s_default" description:"The int32 default" default:"3,4,5" sep:"," pos:"15"`
29 |
30 | Int64 int64 `name:"int64" description:"The int64" pos:"16"`
31 | Int64s []int64 `name:"int64s" description:"The int64s" pos:"17"`
32 | Int64sDefault []int64 `name:"int64s_default" description:"The int64s default" default:"3,4,5" sep:"," pos:"18"`
33 |
34 | Uint uint `name:"uint" description:"The uint" pos:"19"`
35 | Uints []uint `name:"uints" description:"The uints" pos:"20"`
36 | UintsDefault []uint `name:"uints_default" description:"The uints default" default:"3,4,5" sep:"," pos:"21"`
37 |
38 | Uint8 uint8 `name:"uint8" description:"The uint8" pos:"22"`
39 | Uint8s []uint8 `name:"uint8s" description:"The uint8s" pos:"23"`
40 | Uint8sDefault []uint8 `name:"uint8s_default" description:"The uint8s default" default:"3,4,5" sep:"," pos:"24"`
41 |
42 | Uint16 uint16 `name:"uint16" description:"The uint16" pos:"25"`
43 | Uint16s []uint16 `name:"uint16s" description:"The uint16s" pos:"26"`
44 | Uint16sDefault []uint16 `name:"uint16s_default" description:"The uint16 default" default:"3,4,5" sep:"," pos:"27"`
45 |
46 | Uint32 uint32 `name:"uint32" description:"The uint32" pos:"28"`
47 | Uint32s []uint32 `name:"uint32s" description:"The uint32s" pos:"29"`
48 | Uint32sDefault []uint32 `name:"uint32s_default" description:"The uint32s default" default:"3,4,5" sep:"," pos:"30"`
49 |
50 | Uint64 uint64 `name:"uint64" description:"The uint64" pos:"31"`
51 | Uint64s []uint64 `name:"uint64s" description:"The uint64s" pos:"32"`
52 | Uint64sDefault []uint64 `name:"uint64s_default" description:"The uint64s default" default:"3,4,5" sep:"," pos:"33"`
53 |
54 | Float32 float32 `name:"float32" description:"The float32" pos:"34"`
55 | Float32s []float32 `name:"float32s" description:"The float32s" pos:"35"`
56 | Float32sDefault []float32 `name:"float32s_default" description:"The float32s default" default:"3|4|5" sep:"|" pos:"36"`
57 |
58 | Float64 float64 `name:"float64" description:"The float64" pos:"37"`
59 | Float64s []float64 `name:"float64s" description:"The float64s" pos:"38"`
60 | Float64sDefault []float64 `name:"float64s_default" description:"The float64s default" default:"3|4|5" sep:"|" pos:"39"`
61 |
62 | Bool bool `name:"bool" description:"The bool" pos:"40"`
63 | Bools []bool `name:"bools" description:"The bools" pos:"41"`
64 | BoolsDefault []bool `name:"bools_default" description:"The bools default" default:"false|true|false|true" sep:"|" pos:"42"`
65 | }
66 |
67 | func main() {
68 |
69 | // Create new cli
70 | cli := clir.NewCli("flagstruct", "An example of subcommands with flag inherence", "v0.0.1")
71 |
72 | // Create an init subcommand with flag inheritance
73 | init := cli.NewSubCommand("flag", "print default")
74 |
75 | flags := &Flags{
76 | String: "zkep",
77 | Strings: []string{"one", "two", "three"},
78 | Int: 1,
79 | Ints: []int{1, 2, 3},
80 | Int8: int8(1),
81 | Int8s: []int8{1, 2, 3},
82 | Int16: int16(1),
83 | Int16s: []int16{1, 2, 3},
84 | Int32: int32(1),
85 | Int32s: []int32{1, 2, 3},
86 | Int64: int64(1),
87 | Int64s: []int64{1, 2, 3},
88 | Uint: uint(1),
89 | Uints: []uint{1, 2, 3},
90 | Uint8: uint8(1),
91 | Uint8s: []uint8{1, 2, 3},
92 | Uint16: uint16(1),
93 | Uint16s: []uint16{1, 2, 3},
94 | Uint32: uint32(1),
95 | Uint32s: []uint32{1, 2, 3},
96 | Uint64: uint64(1),
97 | Uint64s: []uint64{1, 2, 3},
98 | Float32: float32(3.14),
99 | Float32s: []float32{1.1, 2.2, 3.3},
100 | Float64: float64(3.14),
101 | Float64s: []float64{1.1, 2.2, 3.3},
102 | Bool: false,
103 | Bools: []bool{true, false, false},
104 | }
105 | init.AddFlags(flags)
106 |
107 | init.Action(func() error {
108 |
109 | println("string:", fmt.Sprintf("%#v", flags.String))
110 | println("strings:", fmt.Sprintf("%#v", flags.Strings))
111 | println("strings_default:", fmt.Sprintf("%#v", flags.StringsDefault))
112 | println("\n")
113 |
114 | println("int:", fmt.Sprintf("%#v", flags.Int))
115 | println("ints:", fmt.Sprintf("%#v", flags.Ints))
116 | println("ints_default:", fmt.Sprintf("%#v", flags.IntsDefault))
117 | println("\n")
118 |
119 | println("int8:", fmt.Sprintf("%#v", flags.Int8))
120 | println("int8s:", fmt.Sprintf("%#v", flags.Int8s))
121 | println("int8s_default:", fmt.Sprintf("%#v", flags.Int8sDefault))
122 | println("\n")
123 |
124 | println("int16:", fmt.Sprintf("%#v", flags.Int16))
125 | println("int16s:", fmt.Sprintf("%#v", flags.Int16s))
126 | println("int16s_default:", fmt.Sprintf("%#v", flags.Int16sDefault))
127 | println("\n")
128 |
129 | println("int32:", fmt.Sprintf("%#v", flags.Int32))
130 | println("int32s:", fmt.Sprintf("%#v", flags.Int32s))
131 | println("int32s_default:", fmt.Sprintf("%#v", flags.Int32sDefault))
132 | println("\n")
133 |
134 | println("int64:", fmt.Sprintf("%#v", flags.Int64))
135 | println("int64s:", fmt.Sprintf("%#v", flags.Int64s))
136 | println("int64s_default:", fmt.Sprintf("%#v", flags.Int64sDefault))
137 | println("\n")
138 |
139 | println("uint:", fmt.Sprintf("%#v", flags.Uint))
140 | println("uints:", fmt.Sprintf("%#v", flags.Uints))
141 | println("uints_default:", fmt.Sprintf("%#v", flags.UintsDefault))
142 | println("\n")
143 |
144 | println("uint8:", fmt.Sprintf("%#v", flags.Uint8))
145 | println("uint8s:", fmt.Sprintf("%#v", flags.Uint8s))
146 | println("uint8s_default:", fmt.Sprintf("%#v", flags.Uint8sDefault))
147 | println("\n")
148 |
149 | println("uint16:", fmt.Sprintf("%#v", flags.Uint16))
150 | println("uint16s:", fmt.Sprintf("%#v", flags.Uint16s))
151 | println("uint16s_default:", fmt.Sprintf("%#v", flags.Uint16sDefault))
152 | println("\n")
153 |
154 | println("uint32:", fmt.Sprintf("%#v", flags.Uint32))
155 | println("uint32s:", fmt.Sprintf("%#v", flags.Uint32s))
156 | println("uint32s_default:", fmt.Sprintf("%#v", flags.Uint32sDefault))
157 | println("\n")
158 |
159 | println("uint64:", fmt.Sprintf("%#v", flags.Uint))
160 | println("uint64s:", fmt.Sprintf("%#v", flags.Uint64s))
161 | println("uint64s_default:", fmt.Sprintf("%#v", flags.Uint64sDefault))
162 | println("\n")
163 |
164 | println("float32:", fmt.Sprintf("%#v", flags.Float32))
165 | println("float32s:", fmt.Sprintf("%#v", flags.Float32s))
166 | println("float32s_default:", fmt.Sprintf("%#v", flags.Float32sDefault))
167 | println("\n")
168 |
169 | println("float64:", fmt.Sprintf("%#v", flags.Float64))
170 | println("float64s:", fmt.Sprintf("%#v", flags.Float64s))
171 | println("float64s_default:", fmt.Sprintf("%#v", flags.Float64sDefault))
172 | println("\n")
173 |
174 | println("bool:", fmt.Sprintf("%#v", flags.Bool))
175 | println("bools:", fmt.Sprintf("%#v", flags.Bools))
176 | println("bools_default:", fmt.Sprintf("%#v", flags.BoolsDefault))
177 | println("\n")
178 |
179 | return nil
180 | })
181 |
182 | // Run!
183 | if err := cli.Run("flag"); err != nil {
184 | panic(err)
185 | }
186 |
187 | cli.NewSubCommandFunction("positional", "test positional args", func(f *Flags) error {
188 |
189 | if f.String != "hello" {
190 | panic(fmt.Sprintf("expected 'hello', got '%v'", f.String))
191 | }
192 |
193 | if !reflect.DeepEqual(f.Strings, []string{"zkep,hello,clir"}) {
194 | panic(fmt.Sprintf("expected 'zkep,hello,clir', got '%v'", f.Strings))
195 | }
196 |
197 | if !reflect.DeepEqual(f.StringsDefault, []string{"zkep", "clir", "hello"}) {
198 | panic(fmt.Sprintf("expected '[zkep,clir,hello]', got '%v'", f.StringsDefault))
199 | }
200 |
201 | println("string:", fmt.Sprintf("%#v", f.String))
202 | println("strings:", fmt.Sprintf("%#v", f.Strings))
203 | println("strings_default:", fmt.Sprintf("%#v", f.StringsDefault))
204 | println("\n")
205 |
206 | return nil
207 | })
208 |
209 | // Run!
210 | // The pos 3 slice separator is '|' in struct tag
211 | if err := cli.Run("positional", "hello", "zkep,hello,clir", "zkep|clir|hello"); err != nil {
212 | panic(err)
213 | }
214 |
215 | }
216 |
--------------------------------------------------------------------------------
/examples/flags/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/leaanthony/clir"
7 | )
8 |
9 | func main() {
10 |
11 | // Create new cli
12 | cli := clir.NewCli("Flags", "An example of using flags", "v0.0.1")
13 |
14 | // Name
15 | var name string
16 | cli.StringFlag("name", "Your name", &name)
17 |
18 | // Age
19 | var age int
20 | cli.IntFlag("age", "Your age", &age)
21 |
22 | // Awesome
23 | var awesome bool
24 | cli.BoolFlag("awesome", "Are you awesome?", &awesome)
25 |
26 | // Define action for the command
27 | cli.Action(func() error {
28 |
29 | if name == "" {
30 | name = "Anonymous"
31 | }
32 | fmt.Printf("Hello %s!\n", name)
33 |
34 | if age > 0 {
35 | fmt.Printf("You are %d years old!\n", age)
36 | }
37 |
38 | if awesome {
39 | fmt.Println("You are awesome!")
40 | }
41 |
42 | return nil
43 | })
44 |
45 | cli.Run()
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/examples/flagstruct/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/leaanthony/clir"
5 | )
6 |
7 | type Flags struct {
8 | Name string `name:"name" description:"The name of the person"`
9 | Age int `name:"age" description:"The age of the person"`
10 | }
11 |
12 | func main() {
13 |
14 | // Create new cli
15 | cli := clir.NewCli("flagstruct", "An example of subcommands with flag inherence", "v0.0.1")
16 |
17 | // Create an init subcommand with flag inheritance
18 | init := cli.NewSubCommand("create", "Create a person")
19 | person := &Flags{
20 | Age: 20,
21 | }
22 | init.AddFlags(person)
23 | init.Action(func() error {
24 | println("Name:", person.Name, "Age:", person.Age)
25 | return nil
26 | })
27 |
28 | // Run!
29 | if err := cli.Run(); err != nil {
30 | panic(err)
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/examples/hidden/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/leaanthony/clir"
5 | )
6 |
7 | func main() {
8 |
9 | // Create new cli
10 | cli := clir.NewCli("subcommands", "An example of subcommands", "v0.0.1")
11 |
12 | // Create an init subcommand
13 | init := cli.NewSubCommand("init", "Initialise the app")
14 | init.Action(func() error {
15 | println("I am initialising!")
16 | return nil
17 | })
18 |
19 | // Create a test subcommand
20 | test := cli.NewSubCommand("test", "Test the app")
21 | test.Action(func() error {
22 | println("I am testing!")
23 | return nil
24 | })
25 |
26 | // Make test hidden
27 | test.Hidden()
28 |
29 | // Run!
30 | cli.Run()
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/examples/nested-subcommands/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/leaanthony/clir"
5 | )
6 |
7 | func main() {
8 |
9 | // Create new cli
10 | cli := clir.NewCli("Nested Subcommands", "An example of nested subcommands", "v0.0.1")
11 |
12 | // Create a top level subcommand
13 | // Run with: `nested-subcommand top`
14 | top := cli.NewSubCommand("top", "top level command")
15 | top.Action(func() error {
16 | println("I am the top-level command!")
17 | return nil
18 | })
19 |
20 | // Create a middle subcommand on the top command
21 | // Run with: `nested-subcommand top middle`
22 | middle := top.NewSubCommand("middle", "middle level command")
23 | middle.Action(func() error {
24 | println("I am the middle-level command!")
25 | return nil
26 | })
27 |
28 | // Create a bottom subcommand on the middle command
29 | // Run with: `nested-subcommand top middle bottom`
30 | bottom := middle.NewSubCommand("bottom", "bottom level command")
31 | bottom.Action(func() error {
32 | println("I am the bottom-level command!")
33 | return nil
34 | })
35 |
36 | // Run!
37 | cli.Run()
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/examples/otherargs/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/leaanthony/clir"
7 | )
8 |
9 | func main() {
10 |
11 | // Create new cli
12 | cli := clir.NewCli("Other Args", "A basic example", "v0.0.1")
13 |
14 | // Set long description
15 | cli.LongDescription("This app shows additional arguments passed to your commands")
16 |
17 | // Name
18 | var name string
19 | cli.StringFlag("name", "Your name", &name)
20 |
21 | // Define action
22 | cli.Action(func() error {
23 | println("Your name is", name)
24 | fmt.Printf("The remaining arguments were: %+v\n", cli.OtherArgs())
25 | return nil
26 | })
27 | // Using a subcommand instead of a flag
28 | nameCommand := cli.NewSubCommand("namecommand", "Shows your name!")
29 | nameCommand.Action(func() error {
30 | fmt.Printf("The remaining arguments were: %+v\n", nameCommand.OtherArgs())
31 | return nil
32 | })
33 |
34 | // Run!
35 | cli.Run()
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/examples/subcommandinheritflags/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/leaanthony/clir"
5 | )
6 |
7 | func main() {
8 |
9 | // Create new cli
10 | cli := clir.NewCli("subcommandinheritflags", "An example of subcommands with flag inherence", "v0.0.1")
11 |
12 | inheritFlag := false
13 | cli.BoolFlag("inherit", "flag to inherit", &inheritFlag)
14 |
15 | // Create an init subcommand with flag inheritance
16 | init := cli.NewSubCommandInheritFlags("init", "Initialise the app")
17 | init.Action(func() error {
18 | println("I am initializing!", "inherit flag:", inheritFlag)
19 | return nil
20 | })
21 |
22 | // Run!
23 | if err := cli.Run(); err != nil {
24 | panic(err)
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/examples/subcommands/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/leaanthony/clir"
5 | )
6 |
7 | func main() {
8 |
9 | // Create new cli
10 | cli := clir.NewCli("subcommands", "An example of subcommands", "v0.0.1")
11 |
12 | // Create an init subcommand
13 | init := cli.NewSubCommand("init", "Initialise the app")
14 | init.Action(func() error {
15 | println("I am initialising!")
16 | return nil
17 | })
18 |
19 | // Create a test subcommand that's hidden
20 | test := cli.NewSubCommand("test", "Test the app")
21 | test.Action(func() error {
22 | println("I am testing!")
23 | return nil
24 | })
25 |
26 | // Run!
27 | cli.Run()
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/leaanthony/clir
2 |
3 | go 1.12
4 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leaanthony/clir/a8d9462bce754819cbd5a5596f22d68b3f318fb6/go.sum
--------------------------------------------------------------------------------
/website/docs/examples/basic.md:
--------------------------------------------------------------------------------
1 |
2 | # Basic
3 |
4 | ```go
5 | --8<-- "../examples/basic/main.go"
6 | ```
7 |
--------------------------------------------------------------------------------
/website/docs/examples/chained.md:
--------------------------------------------------------------------------------
1 |
2 | # Chained
3 |
4 | ```go
5 | --8<-- "../examples/chained/main.go"
6 | ```
7 |
--------------------------------------------------------------------------------
/website/docs/examples/custom-banner.md:
--------------------------------------------------------------------------------
1 |
2 | # Custom Banner
3 |
4 | ```go
5 | --8<-- "../examples/custom-banner/main.go"
6 | ```
7 |
--------------------------------------------------------------------------------
/website/docs/examples/custom-flag-error.md:
--------------------------------------------------------------------------------
1 |
2 | # Custom Flag Error
3 |
4 | ```go
5 | --8<-- "../examples/custom-flag-error/main.go"
6 | ```
7 |
--------------------------------------------------------------------------------
/website/docs/examples/default.md:
--------------------------------------------------------------------------------
1 |
2 | # Default Command
3 |
4 | ```go
5 | --8<-- "../examples/default/main.go"
6 | ```
7 |
--------------------------------------------------------------------------------
/website/docs/examples/flags-compact.md:
--------------------------------------------------------------------------------
1 |
2 | # Flags Compact
3 |
4 | ```go
5 | --8<-- "../examples/flags-compact/main.go"
6 | ```
7 |
--------------------------------------------------------------------------------
/website/docs/examples/flags-function.md:
--------------------------------------------------------------------------------
1 |
2 | # Flags Function
3 |
4 | ```go
5 | --8<-- "../examples/flags-function/main.go"
6 | ```
7 |
--------------------------------------------------------------------------------
/website/docs/examples/flags-positional.md:
--------------------------------------------------------------------------------
1 |
2 | # Flags Positional
3 |
4 | ```go
5 | --8<-- "../examples/flags-positional/main.go"
6 | ```
7 |
--------------------------------------------------------------------------------
/website/docs/examples/flags-slice.md:
--------------------------------------------------------------------------------
1 |
2 | # Flags Slice
3 |
4 | ```go
5 | --8<-- "../examples/flags-slice/main.go"
6 | ```
--------------------------------------------------------------------------------
/website/docs/examples/flags.md:
--------------------------------------------------------------------------------
1 | # Flags
2 |
3 | ```go
4 | --8<-- "../examples/flags/main.go"
5 | ```
6 |
--------------------------------------------------------------------------------
/website/docs/examples/flagstruct.md:
--------------------------------------------------------------------------------
1 |
2 | # Flag Struct
3 |
4 | ```go
5 | --8<-- "../examples/flagstruct/main.go"
6 | ```
7 |
--------------------------------------------------------------------------------
/website/docs/examples/hidden.md:
--------------------------------------------------------------------------------
1 |
2 | # Hidden
3 |
4 | ```go
5 | --8<-- "../examples/hidden/main.go"
6 | ```
7 |
--------------------------------------------------------------------------------
/website/docs/examples/nested-subcommands.md:
--------------------------------------------------------------------------------
1 |
2 | # Nested Subcommands
3 |
4 | ```go
5 | --8<-- "../examples/nested-subcommands/main.go"
6 | ```
7 |
--------------------------------------------------------------------------------
/website/docs/examples/otherargs.md:
--------------------------------------------------------------------------------
1 |
2 | # Other Args
3 |
4 | ```go
5 | --8<-- "../examples/otherargs/main.go"
6 | ```
7 |
--------------------------------------------------------------------------------
/website/docs/examples/subcommandinheritflags.md:
--------------------------------------------------------------------------------
1 |
2 | # Subcommand Inherit Flags
3 |
4 | ```go
5 | --8<-- "../examples/subcommandinheritflags/main.go"
6 | ```
7 |
--------------------------------------------------------------------------------
/website/docs/examples/subcommands.md:
--------------------------------------------------------------------------------
1 |
2 | # Subcommands
3 |
4 | ```go
5 | --8<-- "../examples/subcommands/main.go"
6 | ```
7 |
--------------------------------------------------------------------------------
/website/docs/faq.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "FAQ"
3 | ---
4 |
5 | # FAQ
6 |
7 | ## Why did you write this?
8 |
9 | Because other libraries did not easily do what I wanted. They were also pretty heavyweight and I wanted lean 'n' mean.
10 |
11 | ## What does Clîr mean?
12 |
13 | It's the [Welsh](https://en.wikipedia.org/wiki/Welsh_language) word for "Clear". It sounds almost identical but it's Cleeeer rather than Clee-ur.
14 |
15 | ## Will you support feature X?
16 |
17 | Probably not.
18 |
19 | #### What about double dashes?
20 |
21 | Probably not.
22 |
23 | #### Why not?
24 |
25 | Stability and Simplicity.
--------------------------------------------------------------------------------
/website/docs/gettingstarted.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Getting Started"
3 | date: 2019-11-21T16:15:09+08:00
4 | draft: false
5 | weight: 10
6 | ---
7 |
8 | ## Installation
9 |
10 | `go get github.com/leaanthony/clir`
11 |
12 | ## Basic Usage
13 |
14 | ```go
15 | package main
16 |
17 | import (
18 | "fmt"
19 | "log"
20 |
21 | "github.com/leaanthony/clir"
22 | )
23 |
24 | func main() {
25 |
26 | // Create new cli
27 | cli := clir.NewCli("Flags", "A simple example", "v0.0.1")
28 |
29 | // Name
30 | name := "Anonymous"
31 | cli.StringFlag("name", "Your name", &name)
32 |
33 | // Define action for the command
34 | cli.Action(func() error {
35 | fmt.Printf("Hello %s!\n", name)
36 | return nil
37 | })
38 |
39 | // Run the application
40 | err := cli.Run()
41 | if err != nil {
42 | // We had an error
43 | log.Fatal(err)
44 | }
45 |
46 | }
47 | ```
--------------------------------------------------------------------------------
/website/docs/guide/actions.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Actions"
3 | date: 2019-11-21T16:15:09+08:00
4 | draft: false
5 | weight: 50
6 | chapter: false
7 | ---
8 |
9 | Actions define what code will be executed when your application is run. A basic example of this is:
10 |
11 | ```go
12 | package main
13 |
14 | import "github.com/leaanthony/clir"
15 | import "log"
16 |
17 | func main() {
18 |
19 | // Create the application
20 | cli := clir.NewCli("Actions", "A simple example", "v0.0.1")
21 |
22 | // Define main action
23 | cli.Action(func() error {
24 | println("Hello World!")
25 | return nil
26 | })
27 |
28 | // Run application
29 | err := cli.Run()
30 | if err != nil {
31 | // We had an error
32 | log.Fatal(err)
33 | }
34 | }
35 | ```
36 |
37 | Running this command will simply run our action:
38 |
39 | ```shell
40 | > actions
41 | Hello World!
42 | ```
43 |
44 | To interact with the flags passed in, we simply use scoping:
45 |
46 | ```go
47 | package main
48 |
49 | import (
50 | "fmt"
51 | "log"
52 |
53 | "github.com/leaanthony/clir"
54 | )
55 |
56 | func main() {
57 |
58 | // Create the application
59 | cli := clir.NewCli("Actions", "A simple example", "v0.0.1")
60 |
61 | // Set our default name to "Anonymous"
62 | name := "Anonymous"
63 | cli.StringFlag("name", "Your name", &name)
64 |
65 | // Define action for the command
66 | cli.Action(func() error {
67 | fmt.Printf("Hello %s!\n", name)
68 | return nil
69 | })
70 |
71 | // Run application
72 | err := cli.Run()
73 | if err != nil {
74 | // We had an error
75 | log.Fatal(err)
76 | }
77 |
78 | }
79 | ```
80 |
81 | When we run this with no flags we get:
82 | ```shell
83 | > actions
84 | Hello Anonymous!
85 | ```
86 |
87 | Passing in a name produces the expected output:
88 | ```shell
89 | > actions -name Debbie
90 | Hello Debbie!
91 | ```
92 |
93 | ## API
94 |
95 | **Cli.Action(fn func() error)**
96 |
97 | Action binds the given function to the application. It is called when the application is executed. Any errors returned by actions are passed back to via the main `Cli.Run` method.
98 |
99 | Example:
100 |
101 | ```go
102 | package main
103 |
104 | import (
105 | "fmt"
106 | "log"
107 |
108 | "github.com/leaanthony/clir"
109 | )
110 |
111 | func main() {
112 |
113 | // Create the application
114 | cli := clir.NewCli("Actions", "A simple example", "v0.0.1")
115 |
116 | // Define action for the command
117 | cli.Action(func() error {
118 | return fmt.Errorf("I am an error")
119 | })
120 |
121 | // We will receive our error here
122 | err := cli.Run()
123 | if err != nil {
124 | log.Fatal(err)
125 | }
126 | }
127 | ```
128 |
129 | Running this will produce:
130 |
131 | ```shell
132 | > actions
133 | 2019/11/23 08:03:56 I am an error
134 | ```
--------------------------------------------------------------------------------
/website/docs/guide/cli.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "CLI"
3 | date: 2019-11-21T16:15:09+08:00
4 | draft: false
5 | weight: 30
6 | chapter: false
7 | ---
8 |
9 | The main entry point for a Clîr application is the Cli object. This is created using the `NewCli` command which takes an application name, description and optional version:
10 |
11 | ```go
12 | package main
13 |
14 | import "github.com/leaanthony/clir"
15 | import "log"
16 |
17 | func main() {
18 |
19 | // Create the application
20 | cli := clir.NewCli("Basic", "A basic example", "v0.0.1")
21 |
22 | // Run the application
23 | err := cli.Run()
24 | if err != nil {
25 | // We had an error
26 | log.Fatal(err)
27 | }
28 | }
29 | ```
30 |
31 | When you run this app, you will get the default help text:
32 |
33 | ```shell
34 | > basic
35 | Basic v0.0.1 - A basic example
36 |
37 | Flags:
38 |
39 | -help
40 | Get help on the 'basic' command.
41 |
42 | ```
43 |
44 | ### API
45 |
46 | **NewCli(name string, description string, version string) *Cli**
47 |
48 | The [NewCli](https://godoc.org/github.com/leaanthony/clir#NewCli) function creates a new Clîr application.
49 |
50 | **Cli.Run(args ...string) error**
51 |
52 | The [Run](https://godoc.org/github.com/leaanthony/clir#Cli.Run) method starts the application. By default it will use `os.Args`, though you are free to pass in arguments for testing purposes. Run returns an error, which may be handled appropriately.
53 |
--------------------------------------------------------------------------------
/website/docs/guide/custombanner.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Custom Banner"
3 | date: 2019-11-21T16:15:09+08:00
4 | draft: false
5 | weight: 90
6 | chapter: false
7 | ---
8 |
9 | It is possible to provide your own banner by setting the Banner function that the application will call:
10 |
11 | ```go
12 | package main
13 |
14 | import (
15 | "log"
16 |
17 | "github.com/leaanthony/clir"
18 | )
19 |
20 | func customBanner(cli *clir.Cli) string {
21 |
22 | return `
23 | ______ __ __ ______ _________ ______ ___ __ __
24 | /_____/\ /_/\/_/\ /_____/\ /________/\/_____/\ /__//_//_/\
25 | \:::__\/ \:\ \:\ \\::::_\/_\__.::.__\/\:::_ \ \\::\| \| \ \
26 | \:\ \ __\:\ \:\ \\:\/___/\ \::\ \ \:\ \ \ \\:. \ \
27 | \:\ \/_/\\:\ \:\ \\_::._\:\ \::\ \ \:\ \ \ \\:.\-/\ \ \
28 | \:\_\ \ \\:\_\:\ \ /____\:\ \::\ \ \:\_\ \ \\. \ \ \ \
29 | \_____\/ \_____\/ \_____\/ \__\/ \_____\/ \__\/ \__\/
30 | ` + cli.Version() + " - " + cli.ShortDescription()
31 | }
32 |
33 | func main() {
34 |
35 | // Create new cli
36 | cli := clir.NewCli("Banner", "A custom banner example", "v0.0.1")
37 |
38 | // Set the custom banner
39 | cli.SetBannerFunction(customBanner)
40 |
41 | // Run the application
42 | err := cli.Run()
43 | if err != nil {
44 | // We had an error
45 | log.Fatal(err)
46 | }
47 |
48 | }
49 | ```
50 |
51 | The `setBannerFunction` method expects a function with the signature `func (*clir.Cli) string`.
52 |
--------------------------------------------------------------------------------
/website/docs/guide/flags.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Flags"
3 | ---
4 |
5 | Flags may be added to your application as follows:
6 |
7 | ```go
8 | package main
9 |
10 | import "github.com/leaanthony/clir"
11 | import "log"
12 |
13 | func main() {
14 |
15 | // Create the application
16 | cli := clir.NewCli("Flags", "A simple example", "v0.0.1")
17 |
18 | // Add a string flag
19 | var name string
20 | cli.StringFlag("name", "Your name", &name)
21 |
22 | // Add an int flag
23 | var age int
24 | cli.IntFlag("age", "Your age", &age)
25 |
26 | // Add a bool flag
27 | var awesome bool
28 | cli.BoolFlag("awesome", "Are you awesome?", &awesome)
29 |
30 | // Run the application
31 | err := cli.Run()
32 | if err != nil {
33 | // We had an error
34 | log.Fatal(err)
35 | }
36 | }
37 | ```
38 |
39 | Running this command prints the default help text as expected:
40 |
41 | ```shell
42 | Flags v0.0.1 - A simple example
43 |
44 | Flags:
45 |
46 | -age int
47 | Your age
48 | -awesome
49 | Are you awesome?
50 | -help
51 | Get help on the 'flags' command.
52 | -name string
53 | Your name
54 | ```
55 |
56 | ### Defining flags using a struct
57 |
58 | It's also possible to add flags using a struct. This is useful as you can easily
59 | add flags to your application without having to define them in multiple places:
60 |
61 | ```go
62 | package main
63 |
64 | import (
65 | "github.com/leaanthony/clir"
66 | )
67 |
68 | type Flags struct {
69 | Name string `name:"name" description:"The name of the person"`
70 | Age int `name:"age" description:"The age of the person"`
71 | }
72 |
73 | func main() {
74 |
75 | // Create new cli
76 | cli := clir.NewCli("flagstruct", "An example of subcommands with flag inherence", "v0.0.1")
77 |
78 | // Create an init subcommand with flag inheritance
79 | init := cli.NewSubCommand("create", "Create a person")
80 | person := &Flags{
81 | Age: 20,
82 | }
83 | init.AddFlags(person)
84 | init.Action(func() error {
85 | println("Name:", person.Name, "Age:", person.Age)
86 | return nil
87 | })
88 |
89 | // Run!
90 | if err := cli.Run(); err != nil {
91 | panic(err)
92 | }
93 |
94 | }
95 | ```
96 |
97 | ### Defining flags using a struct with default values
98 |
99 | It's also possible to add flags using a struct with default values. This is useful as you can easily add flags to your application without having to define them in multiple places:
100 |
101 | ```go
102 | package main
103 |
104 | import (
105 | "github.com/leaanthony/clir"
106 | )
107 |
108 | type Flags struct {
109 | Name string `name:"name" description:"The name of the person" default:"John"`
110 | Age int `name:"age" description:"The age of the person" default:"20"`
111 | }
112 |
113 | func main() {
114 |
115 | // Create new cli
116 | cli := clir.NewCli("default", "An example of subcommands with flag inheritance", "v0.0.1")
117 |
118 | // Create an init subcommand with flag inheritance
119 | init := cli.NewSubCommand("create", "Create a person")
120 | person := &Flags{}
121 | init.AddFlags(person)
122 | init.Action(func() error {
123 | println("Name:", person.Name, "Age:", person.Age)
124 | return nil
125 | })
126 |
127 | // Run!
128 | if err := cli.Run(); err != nil {
129 | panic(err)
130 | }
131 |
132 | }
133 | ```
134 |
135 | ### Defining positional arguments
136 |
137 | It is possible to define positional arguments. These are arguments that are not
138 | flags and are defined in the order they are passed to the application. For
139 | example:
140 |
141 |
142 | ```go
143 | package main
144 |
145 | import (
146 | "github.com/leaanthony/clir"
147 | )
148 |
149 | type Flags struct {
150 | Name string `pos:"1" description:"The name of the person" default:"John"`
151 | Age int `pos:"2" description:"The age of the person" default:"20"`
152 | }
153 |
154 | func main() {
155 |
156 | // Create new cli
157 | cli := clir.NewCli("default", "An example of subcommands with positional args", "v0.0.1")
158 |
159 | // Create an init subcommand with flag inheritance
160 | init := cli.NewSubCommand("create", "Create a person")
161 | person := &Flags{}
162 | init.AddFlags(person)
163 | init.Action(func() error {
164 | println("Name:", person.Name, "Age:", person.Age)
165 | return nil
166 | })
167 |
168 | // Run!
169 | if err := cli.Run("create", "bob", "30"); err != nil {
170 | panic(err)
171 | }
172 |
173 | }
174 | ```
175 |
176 | ### API
177 |
178 | #### Cli.StringFlag(name string, description string, variable *string)
179 |
180 | The [StringFlag](https://godoc.org/github.com/leaanthony/clir#StringFlag) method defines a string flag for your Clîr application.
181 |
182 | For the example above, you would pass in a name as follows:
183 |
184 | ```shell
185 | > flags -name John
186 | ```
187 |
188 |
189 | #### Cli.IntFlag(name string, description string, variable *int)
190 |
191 | The [IntFlag](https://godoc.org/github.com/leaanthony/clir#IntFlag) method defines an integer flag for your Clîr application.
192 |
193 | For the example above, you would pass in a value for age as follows:
194 |
195 | ```shell
196 | > flags -age 32
197 | ```
198 |
199 |
200 | #### Cli.BoolFlag(name string, description string, variable *bool)
201 |
202 | The [BoolFlag](https://godoc.org/github.com/leaanthony/clir#BoolFlag) method defines a boolean flag for your Clîr application.
203 |
204 | For the example above, you would you were awesome by simply passing in the flag:
205 |
206 | ```shell
207 | > flags -awesome
208 | ```
209 |
210 | #### Cli.AddFlags(config interface{})
211 |
212 | The [AddFlags](https://godoc.org/github.com/leaanthony/clir#AddFlags) method defines flags for your Clîr application
213 | using a struct. It uses the `name` and `description` tags to define the flag name and description.
214 | If no `name` tag is given, the field name is used. If no `description` tag is given, the description will be blank.
215 | A struct pointer must be passed in otherwise the method will panic.
--------------------------------------------------------------------------------
/website/docs/guide/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Introduction"
3 | date: 2019-11-21T16:15:09+08:00
4 | draft: false
5 | weight: 20
6 | ---
7 |
8 | # Introduction
9 |
10 | In this guide we will walk through the various parts of Clîr. We will cover:
11 |
12 | * The basic layout of a Clîr application
13 | * Adding flags to your app
14 | * Define actions that get run
15 | * Create SubCommands for additional functionality
16 | * Define a custom banner
--------------------------------------------------------------------------------
/website/docs/guide/otherargs.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Other Args"
3 | ---
4 |
5 | # Other Args
6 |
7 | Other arguments passed to your application are accessible within actions using `cli.OtherArgs()`:
8 |
9 | ```go
10 | package main
11 |
12 | import (
13 | "fmt"
14 |
15 | "github.com/leaanthony/clir"
16 | )
17 |
18 | func main() {
19 |
20 | // Create new cli
21 | cli := clir.NewCli("Other Args", "Access other arguments", "v0.0.1")
22 |
23 | // Set long description
24 | cli.LongDescription("This app shows how to access non-flag arguments")
25 |
26 | // Name
27 | var name string
28 | cli.StringFlag("name", "Your name", &name)
29 |
30 | // Define action
31 | cli.Action(func() error {
32 | println("Your name is", name)
33 | fmt.Printf("The remaining arguments were: %+v\n", cli.OtherArgs())
34 | return nil
35 | })
36 |
37 | // Run!
38 | cli.Run()
39 |
40 | }
41 | ```
42 |
43 | Running this command prints the following:
44 |
45 | ```shell
46 | $ ./otherargs -name test other args
47 | Your name is test
48 | The remaining arguments were: [other args]
49 | ```
50 |
51 | **Cli.OtherArgs() []string**
52 |
53 | The [OtherArgs](https://godoc.org/github.com/leaanthony/clir#Cli.OtherArgs) method returns all arguments to the application that are not handled by the defined flags. *NOTE*: This will only return correct values if accessed in an Action.
54 |
--------------------------------------------------------------------------------
/website/docs/guide/prepostrun.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Pre/Post run"
3 | date: 2023-09-23T16:15:09+08:00
4 | draft: false
5 | weight: 100
6 | chapter: false
7 | ---
8 |
9 | The PreRun and PostRun methods allow you to specify custom functions that should be executed before and after running a command, respectively. These functions can be used for tasks such as setup, cleanup, or any other actions you want to perform before or after executing a command.
10 |
11 | PreRun
12 |
13 | The PreRun method is used to specify a function that should run before executing a command. The function you pass to PreRun takes a *Cli parameter, which represents the CLI application itself. You can use this function to perform any necessary setup or validation before running the command.
14 |
15 | PostRun
16 | The PostRun method is used to specify a function that should run after executing a command. Similar to PreRun, the function you pass to PostRun takes a *Cli parameter. You can use this function to perform any cleanup or post-processing tasks after the command execution.
17 |
18 | Example of postRun
19 | ```go
20 | func main() {
21 | cli := clir.NewCli("MyApp", "My CLI application")
22 |
23 | // Define a command
24 | cmd := cli.NewSubCommand("mycommand", "Description of mycommand")
25 |
26 | // Add flags, actions, and other configurations for the command
27 |
28 | // Define a PostRun function for the command
29 | cmd.PostRun(func(c *clir.Cli) error {
30 | // Perform cleanup or post-processing here
31 | fmt.Println("Running PostRun for 'mycommand'")
32 | return nil // Return an error if something goes wrong
33 | })
34 |
35 | // Run the CLI application
36 | if err := cli.Run(os.Args[1:]...); err != nil {
37 | fmt.Fprintf(os.Stderr, "Error: %v\n", err)
38 | os.Exit(1)
39 | }
40 | }
41 |
42 | ```
--------------------------------------------------------------------------------
/website/docs/guide/subcommands.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "SubCommands"
3 | ---
4 |
5 | SubCommands allow you to add child commands to your main cli app. SubCommands may be nested so there's no limit to how you can structure your app.
6 |
7 | ### Creating Subcommands for your app
8 |
9 | ```go
10 | package main
11 |
12 | import (
13 | "fmt"
14 | "log"
15 |
16 | "github.com/leaanthony/clir"
17 | )
18 |
19 | func main() {
20 |
21 | // Create the application
22 | cli := clir.NewCli("SubCommand", "A simple example", "v0.0.1")
23 |
24 | // Create subcommand
25 | initCmd := cli.NewSubCommand("init", "Initialise a new Project")
26 |
27 | // Define action for the command
28 | initCmd.Action(func() error {
29 | fmt.Println("Initialising Project!")
30 | return nil
31 | })
32 |
33 | // Run the application
34 | err := cli.Run()
35 | if err != nil {
36 | // We had an error
37 | log.Fatal(err)
38 | }
39 |
40 | }
41 | ```
42 |
43 | Running this command will display the default help:
44 |
45 | ```shell
46 | > subcommand
47 | SubCommand v0.0.1 - A simple example
48 |
49 | Available commands:
50 |
51 | init Initialise a new Project
52 |
53 | Flags:
54 |
55 | -help
56 | Get help on the 'subcommand' command.
57 | ```
58 |
59 | If we run `subcommand init`, we will get our output:
60 |
61 | ```shell
62 | > subcommand init
63 | Initialising Project!
64 | ```
65 |
66 | Running `subcommand init -help` will give us the help message for that subcommand.
67 |
68 | ```shell
69 | > subcommand init --help
70 | SubCommand v0.0.1 - A simple example
71 |
72 | SubCommand init - Initialise a new Project
73 | Flags:
74 |
75 | -help
76 | Get help on the 'subcommand init' command.
77 | ```
78 |
79 | If you wish to add more information to help messages, use the `Command.LongDescription()` method:
80 |
81 | ```go
82 | package main
83 |
84 | import (
85 | "fmt"
86 | "log"
87 |
88 | "github.com/leaanthony/clir"
89 | )
90 |
91 | func main() {
92 |
93 | // Create the application
94 | cli := clir.NewCli("SubCommand", "A simple example", "v0.0.1")
95 |
96 | // Create subcommand
97 | initCmd := cli.NewSubCommand("init", "Initialise a new Project")
98 |
99 | // More help
100 | initCmd.LongDescription("The init command initialises a new project in the current working directory.")
101 |
102 | // Define action for the command
103 | initCmd.Action(func() error {
104 | fmt.Println("Initialising Project!")
105 | return nil
106 | })
107 |
108 | // Run the application
109 | err := cli.Run()
110 | if err != nil {
111 | // We had an error
112 | log.Fatal(err)
113 | }
114 |
115 | }
116 | ```
117 | Then when we pass `-help`, we get more information:
118 |
119 | ```shell
120 | > subcommand init --help
121 | SubCommand v0.0.1 - A simple example
122 |
123 | SubCommand init - Initialise a new Project
124 | The init command initialises a new project in the current working directory.
125 |
126 | Flags:
127 |
128 | -help
129 | Get help on the 'subcommand init' command.
130 | ```
131 |
132 | You can add as many subcommands as you like. You can even nest them!
133 |
134 | ### Nested SubCommands
135 |
136 | As Commands have (basically) the same API as the Cli object, we can do everything we did in the previous pages: Add Flags, Actions and SubCommands to any Command:
137 |
138 | ```go
139 | package main
140 |
141 | import (
142 | "fmt"
143 | "log"
144 |
145 | "github.com/leaanthony/clir"
146 | )
147 |
148 | func main() {
149 |
150 | // Create the application
151 | cli := clir.NewCli("SubCommand", "A simple example", "v0.0.1")
152 |
153 | // Create subcommand
154 | initCmd := cli.NewSubCommand("init", "Initialise a component")
155 |
156 | // Create a new "project" command below the "init" command
157 | projectCmd := initCmd.NewSubCommand("project", "Creates a new project")
158 | projectCmd.Action(func() error {
159 | fmt.Println("Initialising Project!")
160 | return nil
161 | })
162 |
163 | // Run the application
164 | err := cli.Run()
165 | if err != nil {
166 | // We had an error
167 | log.Fatal(err)
168 | }
169 |
170 | }
171 | ```
172 |
173 | Running `subcommand init` shows the following help:
174 |
175 | ```shell
176 | > subcommand init
177 | SubCommand v0.0.1 - A simple example
178 |
179 | SubCommand init - Initialise a component
180 | Available commands:
181 |
182 | project Creates a new project
183 |
184 | Flags:
185 |
186 | -help
187 | Get help on the 'subcommand init' command.
188 |
189 | ```
190 |
191 | Whilst running `subcommand init project` will call the project command action:
192 |
193 | ```shell
194 | > subcommand init project
195 | Initialising Project!
196 | ```
197 |
198 | ### Adding SubCommands
199 |
200 | It's possible to define SubCommands in isolation, then add them to a command later. To do this, we use the `Command.AddCommand` method:
201 |
202 | ```go
203 | package main
204 |
205 | import (
206 | "fmt"
207 | "log"
208 |
209 | "github.com/leaanthony/clir"
210 | )
211 |
212 | func newProjectCommand() *clir.Command {
213 | // Create a new Command
214 | result := clir.NewCommand("project", "Creates a new project")
215 |
216 | // Define the Action
217 | result.Action(func() error {
218 | fmt.Println("Initialising Project!")
219 | return nil
220 | })
221 |
222 | return result
223 | }
224 |
225 | func main() {
226 |
227 | // Create the application
228 | cli := clir.NewCli("SubCommand", "A simple example", "v0.0.1")
229 |
230 | // Create subcommand
231 | initCmd := cli.NewSubCommand("init", "Initialise a component")
232 |
233 | // Create a new "project" command and add it to the "init" command
234 | initCmd.AddCommand(newProjectCommand())
235 |
236 | // Run the application
237 | err := cli.Run()
238 | if err != nil {
239 | // We had an error
240 | log.Fatal(err)
241 | }
242 |
243 | }
244 | ```
245 |
246 | This really helps with better code organisation.
247 |
248 | ### Adding Subcommands with Functions
249 |
250 | You can also add SubCommands using a function:
251 |
252 | ```go
253 | type AppFlags struct {
254 | Name string `name:"name" description:"The name of the person" default:"Bob"`
255 | Age int `name:"age" description:"The age of the person" default:"20"`
256 | }
257 |
258 | func main() {
259 | // Create new cli
260 | cli := clir.NewCli("Flags", "An example of using flags", "v0.0.1")
261 |
262 | cli.NewSubCommandFunction("create", "Create a new person", createPerson)
263 | cli.Run()
264 | }
265 |
266 | func createPerson(flags *AppFlags) error {
267 | fmt.Printf("%+v\n", flags)
268 | return nil
269 | }
270 | ```
271 |
272 | The NewSubCommandFunction method takes a function that takes a pointer to the flags struct and returns an error.
273 | The function is called when the command is run and passes in the flags struct with the values set from the command line.
274 |
275 | ### Inheriting Flags
276 |
277 | The `NewSubCommandInheritFlags` method will create a subcommand in the usual way but will inherit all previously defined flags in the parent.
278 |
279 | ### Hidden SubCommands
280 |
281 | It's possible to hide subcommands by calling the `Hidden` method. This will omit the subcommand from any help text.
282 |
283 | ```go
284 | package main
285 |
286 | import (
287 | "fmt"
288 | "log"
289 |
290 | "github.com/leaanthony/clir"
291 | )
292 |
293 | func main() {
294 |
295 | // Create the application
296 | cli := clir.NewCli("SubCommand", "A simple example", "v0.0.1")
297 |
298 | // Create subcommand
299 | initCmd := cli.NewSubCommand("init", "Initialise a component")
300 | initCmd.Action(func() error {
301 | fmt.Println("Initialising")
302 | return nil
303 | })
304 |
305 | // Create a hidden developer command
306 | devtoolsCommand := cli.NewSubCommand("dev", "Developer tools")
307 | devtoolsCommand.Action(func() error {
308 | fmt.Println("I'm a secret command")
309 | return nil
310 | })
311 | devtoolsCommand.Hidden()
312 |
313 | // Run the application
314 | err := cli.Run()
315 | if err != nil {
316 | // We had an error
317 | log.Fatal(err)
318 | }
319 |
320 | }
321 | ```
322 |
323 | The main help hides the command, but it is still possible to run it:
324 |
325 | ```
326 | > subcommand
327 | SubCommand v0.0.1 - A simple example
328 |
329 | Available commands:
330 |
331 | init Initialise a component
332 |
333 | Flags:
334 |
335 | -help
336 | Get help on the 'subcommand' command.
337 |
338 |
339 | > subcommand dev
340 | I'm a secret command
341 | ```
342 |
343 | ### Default Command
344 |
345 | If you would like the default action of your application to be a particular subcommand, you can set it using the `DefaultCommand` method:
346 |
347 | ```go
348 | package main
349 |
350 | import (
351 | "fmt"
352 | "log"
353 |
354 | "github.com/leaanthony/clir"
355 | )
356 |
357 | func main() {
358 |
359 | // Create the application
360 | cli := clir.NewCli("SubCommand", "A simple example", "v0.0.1")
361 |
362 | // Create subcommand
363 | initCmd := cli.NewSubCommand("init", "Initialise a component")
364 | initCmd.Action(func() error {
365 | fmt.Println("Initialising")
366 | return nil
367 | })
368 |
369 | // Make init the default command
370 | cli.DefaultCommand(initCmd)
371 |
372 | // Run the application
373 | err := cli.Run()
374 | if err != nil {
375 | // We had an error
376 | log.Fatal(err)
377 | }
378 |
379 | }
380 | ```
381 |
382 | Now when we run the application with no parameters, it will run the init subcommand:
383 |
384 | ```shell
385 | > subcommand
386 | Initialising
387 | ```
388 |
389 | The help text also indicates that there is a default option:
390 |
391 | ```
392 | > subcommand -help
393 | SubCommand v0.0.1 - A simple example
394 |
395 | Available commands:
396 |
397 | init Initialise a component [default]
398 |
399 | Flags:
400 |
401 | -help
402 | Get help on the 'subcommand' command.
403 | ```
404 |
405 | ### API
406 |
407 | **NewCommand(name string, description string) *Command**
408 |
409 | Creates a new Command in isolation. It may be attached to the application through `AddCommand(cmd *Command)`. The returned Command may be further configured.
410 |
411 | **AddCommand(cmd *Command)**
412 |
413 | Attaches the given Command as a SubCommand. This API is valid for both Cli and Command.
414 |
415 | **Hidden()**
416 |
417 | Hides the command from help message.
418 |
--------------------------------------------------------------------------------
/website/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Home"
3 | ---
4 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | A Simple and Clear CLI library. Dependency free.
18 |
19 |
20 |
21 |

22 |

23 |

24 |

25 |

26 |

27 |

28 |

29 |

30 |
31 |
32 | ## Features
33 |
34 | * Nested Subcommands
35 | * Uses the standard library `flag` package
36 | * Auto-generated help
37 | * Custom banners
38 | * Hidden Subcommands
39 | * Default Subcommand
40 | * Dependency free
41 |
42 | ## Example
43 |
44 | ```go
45 | package main
46 |
47 | import (
48 | "fmt"
49 | "log"
50 |
51 | "github.com/leaanthony/clir"
52 | )
53 |
54 | func main() {
55 |
56 | // Create new cli
57 | cli := clir.NewCli("Flags", "A simple example", "v0.0.1")
58 |
59 | // Name
60 | name := "Anonymous"
61 | cli.StringFlag("name", "Your name", &name)
62 |
63 | // Define action for the command
64 | cli.Action(func() error {
65 | fmt.Printf("Hello %s!\n", name)
66 | return nil
67 | })
68 |
69 | // Run the application
70 | err := cli.Run()
71 | if err != nil {
72 | // We had an error
73 | log.Fatal(err)
74 | }
75 |
76 | }
77 | ```
78 |
79 | ## License Status
80 |
81 | [](https://app.fossa.com/projects/git%2Bgithub.com%2Fleaanthony%2Fclir?ref=badge_large)
82 |
--------------------------------------------------------------------------------
/website/docs/static/clir_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leaanthony/clir/a8d9462bce754819cbd5a5596f22d68b3f318fb6/website/docs/static/clir_logo.png
--------------------------------------------------------------------------------
/website/docs/static/clir_logo_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leaanthony/clir/a8d9462bce754819cbd5a5596f22d68b3f318fb6/website/docs/static/clir_logo_white.png
--------------------------------------------------------------------------------
/website/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: Clîr
2 |
3 | theme:
4 | name: material
5 |
6 | palette:
7 | # Palette toggle for light mode
8 | - media: "(prefers-color-scheme: light)"
9 | scheme: default
10 | toggle:
11 | icon: material/brightness-4
12 | name: Switch to dark mode
13 |
14 | # Palette toggle for dark mode
15 | - media: "(prefers-color-scheme: dark)"
16 | scheme: slate
17 | toggle:
18 | icon: material/brightness-7
19 | name: Switch to light mode
20 |
21 | features:
22 | - navigation.footer
23 | - content.action.edit
24 | - navigation.sections
25 | - content.code.copy
26 |
27 | icon:
28 | edit: material/pencil
29 | logo: material/console-line
30 |
31 | extra_css:
32 | - static/css/extra.css
33 |
34 | extra:
35 | homepage: https://clir.leaanthony.com
36 | version:
37 | provider: mike
38 |
39 | copyright: Copyright © 2020-Present Lea Anthony
40 | repo_url: https://github.com/leaanthony/clir
41 |
42 | markdown_extensions:
43 | - attr_list
44 | - md_in_html
45 | - pymdownx.highlight:
46 | anchor_linenums: true
47 | - pymdownx.inlinehilite
48 | - pymdownx.snippets
49 | - pymdownx.superfences
50 |
51 | nav:
52 | - index.md
53 | - gettingstarted.md
54 | - "Guide":
55 | - guide/index.md
56 | - guide/cli.md
57 | - guide/flags.md
58 | - guide/otherargs.md
59 | - guide/actions.md
60 | - guide/subcommands.md
61 | - guide/custombanner.md
62 | - Examples:
63 | - examples/basic.md
64 | - examples/chained.md
65 | - examples/custom-banner.md
66 | - examples/custom-flag-error.md
67 | - examples/default.md
68 | - examples/flags.md
69 | - examples/flags-compact.md
70 | - examples/flags-function.md
71 | - examples/flags-positional.md
72 | - examples/flags-slice.md
73 | - examples/flagstruct.md
74 | - examples/hidden.md
75 | - examples/nested-subcommands.md
76 | - examples/otherargs.md
77 | - examples/subcommandinheritflags.md
78 | - examples/subcommands.md
79 | - faq.md
80 |
--------------------------------------------------------------------------------
/website/requirements.txt:
--------------------------------------------------------------------------------
1 | mkdocs-material==9.0.6
2 | mkdocs-material-extensions==1.1.1
3 |
--------------------------------------------------------------------------------