diff --git a/.golangci.yml b/.golangci.yml index c081231..7e6ebfb 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -39,13 +39,11 @@ linters: - unparam # gopls is better and more subtle - varnamelen # Lots of false positives of things that are fine - wrapcheck # Not every error must be wrapped - - wsl # Very aggressive, some of this I like but tend to do anyway - - wsl_v5 # Very aggressive, some of this I like but tend to do anyway + - wsl # Deprecated exclusions: presets: # See https://golangci-lint.run/usage/false-positives/#exclusion-presets - - comments # Revive in particular has lots of false positives - std-error-handling - common-false-positives rules: @@ -155,10 +153,7 @@ linters: disabled: true # predeclared does this - name: unhandled-error - arguments: - - fmt\.(Fp|P)rint(ln|f)? - - strings.Builder.Write(String|Byte)? - - bytes.Buffer.Write(String|Byte)? + disabled: true # errcheck handles this - name: flag-parameter disabled: true # As far as I can work out this just doesn't like bools diff --git a/command.go b/command.go index 8728bbc..bb2126a 100644 --- a/command.go +++ b/command.go @@ -67,8 +67,8 @@ func New(name string, options ...Option) (*Command, error) { errs = errors.Join(errs, err) // nil errors are discarded in join err = Flag(&cfg.versionCalled, "version", 'V', false, "Show version info for "+name).apply(&cfg) - errs = errors.Join(errs, err) + errs = errors.Join(errs, err) if errs != nil { return nil, errs } @@ -472,7 +472,9 @@ func stripFlags(cmd *Command, args []string) []string { if len(args) <= 1 { return argsWithoutFlags } + args = args[1:] + continue case arg != "" && !strings.HasPrefix(arg, "-"): @@ -669,6 +671,7 @@ func writeSubcommands(cmd *Command, s *strings.Builder) error { } else { s.WriteString("\n\n") } + s.WriteString(colour.Title("Commands")) s.WriteByte(':') s.WriteByte('\n') diff --git a/command_test.go b/command_test.go index ff6beee..3ab6fef 100644 --- a/command_test.go +++ b/command_test.go @@ -899,6 +899,7 @@ func TestCommandNoRunNoSub(t *testing.T) { func TestExecuteNilCommand(t *testing.T) { var cmd *cli.Command + err := cmd.Execute() test.Err(t, err) diff --git a/internal/flag/flag.go b/internal/flag/flag.go index 57500b2..c1c0df5 100644 --- a/internal/flag/flag.go +++ b/internal/flag/flag.go @@ -60,8 +60,7 @@ const ( ) const ( - boolTrue = "true" - boolFalse = "false" + boolTrue = "true" ) // NoShortHand should be passed as the "short" argument to [New] if the desired flag @@ -891,6 +890,7 @@ func formatStringSlice(slice []string) string { length := len(slice) s := &strings.Builder{} s.WriteByte('[') + for index, elem := range slice { s.WriteString(strconv.Quote(elem)) // Write commas and a space on every element other than the last one @@ -899,6 +899,7 @@ func formatStringSlice(slice []string) string { s.WriteByte(' ') } } + s.WriteByte(']') return s.String() diff --git a/internal/flag/flag_test.go b/internal/flag/flag_test.go index ccc7336..f4fa79b 100644 --- a/internal/flag/flag_test.go +++ b/internal/flag/flag_test.go @@ -17,6 +17,7 @@ func TestFlaggableTypes(t *testing.T) { // so strap in for a bunch of copy pasta t.Run("int valid", func(t *testing.T) { var i int + intFlag, err := flag.New(&i, "int", 'i', 0, "Set an int value") test.Ok(t, err) @@ -29,6 +30,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int invalid", func(t *testing.T) { var i int + intFlag, err := flag.New(&i, "int", 'i', 0, "Set an int value") test.Ok(t, err) @@ -43,6 +45,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int8 valid", func(t *testing.T) { var i int8 + intFlag, err := flag.New(&i, "int", 'i', 0, "Set an int8 value") test.Ok(t, err) @@ -55,6 +58,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int8 invalid", func(t *testing.T) { var i int8 + intFlag, err := flag.New(&i, "int", 'i', 0, "Set an int8 value") test.Ok(t, err) @@ -69,6 +73,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int16 valid", func(t *testing.T) { var i int16 + intFlag, err := flag.New(&i, "int", 'i', 0, "Set an int16 value") test.Ok(t, err) @@ -81,6 +86,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int16 invalid", func(t *testing.T) { var i int16 + intFlag, err := flag.New(&i, "int", 'i', 0, "Set an int16 value") test.Ok(t, err) @@ -95,6 +101,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int32 valid", func(t *testing.T) { var i int32 + intFlag, err := flag.New(&i, "int", 'i', 0, "Set an int32 value") test.Ok(t, err) @@ -107,6 +114,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int32 invalid", func(t *testing.T) { var i int32 + intFlag, err := flag.New(&i, "int", 'i', 0, "Set an int32 value") test.Ok(t, err) @@ -121,6 +129,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int64 valid", func(t *testing.T) { var i int64 + intFlag, err := flag.New(&i, "int", 'i', 0, "Set an int64 value") test.Ok(t, err) @@ -133,6 +142,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int64 invalid", func(t *testing.T) { var i int64 + intFlag, err := flag.New(&i, "int", 'i', 0, "Set an int64 value") test.Ok(t, err) @@ -147,6 +157,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("count valid", func(t *testing.T) { var c flag.Count + countFlag, err := flag.New(&c, "count", 'c', 0, "Count something") test.Ok(t, err) @@ -174,6 +185,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("count invalid", func(t *testing.T) { var c flag.Count + countFlag, err := flag.New(&c, "count", 'c', 0, "Count something") test.Ok(t, err) @@ -188,6 +200,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint valid", func(t *testing.T) { var i uint + intFlag, err := flag.New(&i, "uint", 'i', 0, "Set a uint value") test.Ok(t, err) @@ -200,6 +213,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint invalid", func(t *testing.T) { var i uint + intFlag, err := flag.New(&i, "uint", 'i', 0, "Set a uint value") test.Ok(t, err) @@ -214,6 +228,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint8 valid", func(t *testing.T) { var i uint8 + intFlag, err := flag.New(&i, "uint", 'i', 0, "Set a uint8 value") test.Ok(t, err) @@ -226,6 +241,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint8 invalid", func(t *testing.T) { var i uint8 + intFlag, err := flag.New(&i, "uint", 'i', 0, "Set a uint8 value") test.Ok(t, err) @@ -240,6 +256,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint16 valid", func(t *testing.T) { var i uint16 + intFlag, err := flag.New(&i, "uint", 'i', 0, "Set a uint16 value") test.Ok(t, err) @@ -252,6 +269,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint16 invalid", func(t *testing.T) { var i uint16 + intFlag, err := flag.New(&i, "uint", 'i', 0, "Set a uint16 value") test.Ok(t, err) @@ -266,6 +284,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint32 valid", func(t *testing.T) { var i uint32 + intFlag, err := flag.New(&i, "uint", 'i', 0, "Set a uint32 value") test.Ok(t, err) @@ -278,6 +297,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint32 invalid", func(t *testing.T) { var i uint32 + intFlag, err := flag.New(&i, "uint", 'i', 0, "Set a uint32 value") test.Ok(t, err) @@ -292,6 +312,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint64 valid", func(t *testing.T) { var i uint64 + intFlag, err := flag.New(&i, "uint", 'i', 0, "Set a uint64 value") test.Ok(t, err) @@ -304,6 +325,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint64 invalid", func(t *testing.T) { var i uint64 + intFlag, err := flag.New(&i, "uint", 'i', 0, "Set a uint64 value") test.Ok(t, err) @@ -318,6 +340,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uintptr valid", func(t *testing.T) { var i uintptr + intFlag, err := flag.New(&i, "uintptr", 'i', 0, "Set a uintptr value") test.Ok(t, err) @@ -330,6 +353,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uintptr invalid", func(t *testing.T) { var i uintptr + intFlag, err := flag.New(&i, "uintptr", 'i', 0, "Set a uintptr value") test.Ok(t, err) @@ -344,6 +368,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("float32 valid", func(t *testing.T) { var f float32 + floatFlag, err := flag.New(&f, "float", 'f', 0, "Set a float32 value") test.Ok(t, err) @@ -356,6 +381,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("float32 invalid", func(t *testing.T) { var f float32 + floatFlag, err := flag.New(&f, "float", 'f', 0, "Set a float32 value") test.Ok(t, err) @@ -370,6 +396,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("float64 valid", func(t *testing.T) { var f float64 + floatFlag, err := flag.New(&f, "float", 'f', 0, "Set a float64 value") test.Ok(t, err) @@ -382,6 +409,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("float64 invalid", func(t *testing.T) { var f float64 + floatFlag, err := flag.New(&f, "float", 'f', 0, "Set a float64 value") test.Ok(t, err) @@ -396,6 +424,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("bool valid", func(t *testing.T) { var b bool + boolFlag, err := flag.New(&b, "bool", 'b', false, "Set a bool value") test.Ok(t, err) @@ -408,6 +437,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("bool invalid", func(t *testing.T) { var b bool + boolFlag, err := flag.New(&b, "bool", 'b', false, "Set a bool value") test.Ok(t, err) @@ -424,6 +454,7 @@ func TestFlaggableTypes(t *testing.T) { // getting an error here t.Run("string", func(t *testing.T) { var str string + strFlag, err := flag.New(&str, "string", 's', "", "Set a string value") test.Ok(t, err) @@ -436,6 +467,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("byte slice valid", func(t *testing.T) { var byt []byte + byteFlag, err := flag.New(&byt, "byte", 'b', []byte(""), "Set a byte slice value") test.Ok(t, err) @@ -448,6 +480,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("byte slice invalid", func(t *testing.T) { var byt []byte + byteFlag, err := flag.New(&byt, "byte", 'b', []byte(""), "Set a byte slice value") test.Ok(t, err) @@ -462,6 +495,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("time.Time valid", func(t *testing.T) { var tyme time.Time + timeFlag, err := flag.New(&tyme, "time", 't', time.Now(), "Set a time value") test.Ok(t, err) @@ -477,6 +511,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("time.Time invalid", func(t *testing.T) { var tyme time.Time + timeFlag, err := flag.New(&tyme, "time", 't', time.Now(), "Set a time value") test.Ok(t, err) @@ -491,6 +526,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("time.Duration valid", func(t *testing.T) { var duration time.Duration + durationFlag, err := flag.New( &duration, "duration", @@ -512,6 +548,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("time.Duration invalid", func(t *testing.T) { var duration time.Duration + durationFlag, err := flag.New( &duration, "duration", @@ -532,6 +569,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("ip valid", func(t *testing.T) { var ip net.IP + ipFlag, err := flag.New(&ip, "ip", 'i', nil, "Set an IP address") test.Ok(t, err) @@ -544,6 +582,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("ip invalid", func(t *testing.T) { var ip net.IP + ipFlag, err := flag.New(&ip, "ip", 'i', nil, "Set an IP address") test.Ok(t, err) @@ -558,6 +597,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int slice valid", func(t *testing.T) { var slice []int + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Append to a slice of ints") test.Ok(t, err) @@ -578,6 +618,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int slice invalid", func(t *testing.T) { var slice []int + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Slice of integers") test.Ok(t, err) @@ -592,6 +633,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int8 slice valid", func(t *testing.T) { var slice []int8 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Append to a slice of ints") test.Ok(t, err) @@ -612,6 +654,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int8 slice invalid", func(t *testing.T) { var slice []int8 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Slice of integers") test.Ok(t, err) @@ -626,6 +669,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int16 slice valid", func(t *testing.T) { var slice []int16 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Append to a slice of ints") test.Ok(t, err) @@ -646,6 +690,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int16 slice invalid", func(t *testing.T) { var slice []int16 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Slice of integers") test.Ok(t, err) @@ -660,6 +705,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int32 slice valid", func(t *testing.T) { var slice []int32 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Append to a slice of ints") test.Ok(t, err) @@ -680,6 +726,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int32 slice invalid", func(t *testing.T) { var slice []int32 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Slice of integers") test.Ok(t, err) @@ -694,6 +741,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int64 slice valid", func(t *testing.T) { var slice []int64 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Append to a slice of ints") test.Ok(t, err) @@ -714,6 +762,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("int64 slice invalid", func(t *testing.T) { var slice []int64 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Slice of integers") test.Ok(t, err) @@ -728,6 +777,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint slice valid", func(t *testing.T) { var slice []uint + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Append to a slice of uints") test.Ok(t, err) @@ -748,6 +798,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint slice invalid", func(t *testing.T) { var slice []uint + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Slice of unsigned integers") test.Ok(t, err) @@ -762,6 +813,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint16 slice valid", func(t *testing.T) { var slice []uint16 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Append to a slice of ints") test.Ok(t, err) @@ -782,6 +834,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint16 slice invalid", func(t *testing.T) { var slice []uint16 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Slice of integers") test.Ok(t, err) @@ -796,6 +849,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint32 slice valid", func(t *testing.T) { var slice []uint32 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Append to a slice of ints") test.Ok(t, err) @@ -816,6 +870,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint32 slice invalid", func(t *testing.T) { var slice []uint32 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Slice of integers") test.Ok(t, err) @@ -830,6 +885,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint64 slice valid", func(t *testing.T) { var slice []uint64 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Append to a slice of ints") test.Ok(t, err) @@ -850,6 +906,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("uint64 slice invalid", func(t *testing.T) { var slice []uint64 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Slice of integers") test.Ok(t, err) @@ -864,6 +921,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("float32 slice valid", func(t *testing.T) { var slice []float32 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Append to a slice of floats") test.Ok(t, err) @@ -884,6 +942,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("float32 slice invalid", func(t *testing.T) { var slice []float32 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Slice of floats") test.Ok(t, err) @@ -898,6 +957,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("float64 slice valid", func(t *testing.T) { var slice []float64 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Append to a slice of floats") test.Ok(t, err) @@ -918,6 +978,7 @@ func TestFlaggableTypes(t *testing.T) { t.Run("float64 slice invalid", func(t *testing.T) { var slice []float64 + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Slice of floats") test.Ok(t, err) @@ -934,6 +995,7 @@ func TestFlaggableTypes(t *testing.T) { // Note: no invalid case for []string because *every* flag value is a string // it's impossible to make a bad one var slice []string + sliceFlag, err := flag.New(&slice, "slice", 's', nil, "Append to a slice of strings") test.Ok(t, err) @@ -1093,6 +1155,7 @@ func TestFlagNilSafety(t *testing.T) { func BenchmarkFlagSet(b *testing.B) { var count int + flag, err := flag.New(&count, "count", 'c', 0, "Count things") test.Ok(b, err) diff --git a/internal/flag/value.go b/internal/flag/value.go index 5dfca58..bb0135b 100644 --- a/internal/flag/value.go +++ b/internal/flag/value.go @@ -2,24 +2,25 @@ package flag // Value is an interface representing a Flag value that can be set from the command line. type Value interface { - // Return the name of the flag + // Name returns the name of the flag. Name() string - // Return the shorthand of the flag (or NoShortHand) + // Short returns the shorthand of the flag (or NoShortHand). Short() rune - // Return the usage line for the flag + // Usage returns the usage line for the flag. Usage() string - // Print the stored value of a flag + // String returns the stored value of a flag as a string. String() string - // String representation of the value of the flag when no args are passed (e.g --bool implies --bool true) + // NoArgValue returns astring representation of the value of the flag when no + // args are passed (e.g --bool implies --bool true). NoArgValue() string - // Return the string representation of the flag type e.g. "bool" + // Type returns the string representation of the flag type e.g. "bool". Type() string - // Set the stored value of a flag by parsing the string "str" + // Set sets the stored value of a flag by parsing the string "str". Set(str string) error }