pax_global_header00006660000000000000000000000064122457035740014523gustar00rootroot0000000000000052 comment=062143ceda90a2df0778a9dfc6126812f15b1cba golang-go-flags-0.0~git20131216/000077500000000000000000000000001224570357400160505ustar00rootroot00000000000000golang-go-flags-0.0~git20131216/LICENSE000066400000000000000000000027531224570357400170640ustar00rootroot00000000000000Copyright (c) 2012 Jesse van den Kieboom. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. golang-go-flags-0.0~git20131216/README.md000066400000000000000000000107231224570357400173320ustar00rootroot00000000000000go-flags: a go library for parsing command line arguments ========================================================= This library provides similar functionality to the builtin flag library of go, but provides much more functionality and nicer formatting. From the documentation: Package flags provides an extensive command line option parser. The flags package is similar in functionality to the go builtin flag package but provides more options and uses reflection to provide a convenient and succinct way of specifying command line options. Supported features: * Options with short names (-v) * Options with long names (--verbose) * Options with and without arguments (bool v.s. other type) * Options with optional arguments and default values * Multiple option groups each containing a set of options * Generate and print well-formatted help message * Passing remaining command line arguments after -- (optional) * Ignoring unknown command line options (optional) * Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification * Supports multiple short options -aux * Supports all primitive go types (string, int{8..64}, uint{8..64}, float) * Supports same option multiple times (can store in slice or last option counts) * Supports maps * Supports function callbacks The flags package uses structs, reflection and struct field tags to allow users to specify command line options. This results in very simple and consise specification of your application options. For example: type Options struct { Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` } This specifies one option with a short name -v and a long name --verbose. When either -v or --verbose is found on the command line, a 'true' value will be appended to the Verbose field. e.g. when specifying -vvv, the resulting value of Verbose will be {[true, true, true]}. Example: -------- var opts struct { // Slice of bool will append 'true' each time the option // is encountered (can be set multiple times, like -vvv) Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` // Example of automatic marshalling to desired type (uint) Offset uint `long:"offset" description:"Offset"` // Example of a callback, called each time the option is found. Call func(string) `short:"c" description:"Call phone number"` // Example of a required flag Name string `short:"n" long:"name" description:"A name" required:"true"` // Example of a value name File string `short:"f" long:"file" description:"A file" value-name:"FILE"` // Example of a pointer Ptr *int `short:"p" description:"A pointer to an integer"` // Example of a slice of strings StringSlice []string `short:"s" description:"A slice of strings"` // Example of a slice of pointers PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"` // Example of a map IntMap map[string]int `long:"intmap" description:"A map from string to int"` } // Callback which will invoke callto: to call a number. // Note that this works just on OS X (and probably only with // Skype) but it shows the idea. opts.Call = func(num string) { cmd := exec.Command("open", "callto:"+num) cmd.Start() cmd.Process.Release() } // Make some fake arguments to parse. args := []string{ "-vv", "--offset=5", "-n", "Me", "-p", "3", "-s", "hello", "-s", "world", "--ptrslice", "hello", "--ptrslice", "world", "--intmap", "a:1", "--intmap", "b:5", "arg1", "arg2", "arg3", } // Parse flags from `args'. Note that here we use flags.ParseArgs for // the sake of making a working example. Normally, you would simply use // flags.Parse(&opts) which uses os.Args args, err := flags.ParseArgs(&opts, args) if err != nil { panic(err) os.Exit(1) } fmt.Printf("Verbosity: %v\n", opts.Verbose) fmt.Printf("Offset: %d\n", opts.Offset) fmt.Printf("Name: %s\n", opts.Name) fmt.Printf("Ptr: %d\n", *opts.Ptr) fmt.Printf("StringSlice: %v\n", opts.StringSlice) fmt.Printf("PtrSlice: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1]) fmt.Printf("IntMap: [a:%v b:%v]\n", opts.IntMap["a"], opts.IntMap["b"]) fmt.Printf("Remaining args: %s\n", strings.Join(args, " ")) // Output: Verbosity: [true true] // Offset: 5 // Name: Me // Ptr: 3 // StringSlice: [hello world] // PtrSlice: [hello world] // IntMap: [a:1 b:5] // Remaining args: arg1 arg2 arg3 More information can be found in the godocs: golang-go-flags-0.0~git20131216/assert_test.go000066400000000000000000000034631224570357400207450ustar00rootroot00000000000000package flags_test import ( "github.com/jessevdk/go-flags" "testing" ) func assertString(t *testing.T, a string, b string) { if a != b { t.Errorf("Expected %#v, but got %#v", b, a) } } func assertStringArray(t *testing.T, a []string, b []string) { if len(a) != len(b) { t.Errorf("Expected %#v, but got %#v", b, a) return } for i, v := range a { if b[i] != v { t.Errorf("Expected %#v, but got %#v", b, a) return } } } func assertBoolArray(t *testing.T, a []bool, b []bool) { if len(a) != len(b) { t.Errorf("Expected %#v, but got %#v", b, a) return } for i, v := range a { if b[i] != v { t.Errorf("Expected %#v, but got %#v", b, a) return } } } func assertParserSuccess(t *testing.T, data interface{}, args ...string) (*flags.Parser, []string) { parser := flags.NewParser(data, flags.Default&^flags.PrintErrors) ret, err := parser.ParseArgs(args) if err != nil { t.Fatalf("Unexpected parse error: %s", err) return nil, nil } return parser, ret } func assertParseSuccess(t *testing.T, data interface{}, args ...string) []string { _, ret := assertParserSuccess(t, data, args...) return ret } func assertError(t *testing.T, err error, typ flags.ErrorType, msg string) { if err == nil { t.Fatalf("Expected error: %s", msg) return } if e, ok := err.(*flags.Error); !ok { t.Fatalf("Expected Error type, but got %#v", err) return } else { if e.Type != typ { t.Errorf("Expected error type {%s}, but got {%s}", typ, e.Type) } if e.Message != msg { t.Errorf("Expected error message %#v, but got %#v", msg, e.Message) } } } func assertParseFail(t *testing.T, typ flags.ErrorType, msg string, data interface{}, args ...string) { parser := flags.NewParser(data, flags.Default&^flags.PrintErrors) _, err := parser.ParseArgs(args) assertError(t, err, typ, msg) } golang-go-flags-0.0~git20131216/check_crosscompile.sh000077500000000000000000000005411224570357400222460ustar00rootroot00000000000000#!/bin/bash set -e echo '# linux arm7' GOARM=7 GOARCH=arm GOOS=linux go build echo '# linux arm5' GOARM=5 GOARCH=arm GOOS=linux go build echo '# windows 386' GOARCH=386 GOOS=windows go build echo '# windows amd64' GOARCH=amd64 GOOS=windows go build echo '# darwin' GOARCH=amd64 GOOS=darwin go build echo '# freebsd' GOARCH=amd64 GOOS=freebsd go build golang-go-flags-0.0~git20131216/closest.go000066400000000000000000000014231224570357400200530ustar00rootroot00000000000000package flags func levenshtein(s string, t string) int { if len(s) == 0 { return len(t) } if len(t) == 0 { return len(s) } var l1, l2, l3 int if len(s) == 1 { l1 = len(t) + 1 } else { l1 = levenshtein(s[1:len(s)-1], t) + 1 } if len(t) == 1 { l2 = len(s) + 1 } else { l2 = levenshtein(t[1:len(t)-1], s) + 1 } l3 = levenshtein(s[1:len(s)], t[1:len(t)]) if s[0] != t[0] { l3 += 1 } if l2 < l1 { l1 = l2 } if l1 < l3 { return l1 } return l3 } func closestChoice(cmd string, choices []string) (string, int) { if len(choices) == 0 { return "", 0 } mincmd := -1 mindist := -1 for i, c := range choices { l := levenshtein(cmd, c) if mincmd < 0 || l < mindist { mindist = l mincmd = i } } return choices[mincmd], mindist } golang-go-flags-0.0~git20131216/command.go000066400000000000000000000047511224570357400200240ustar00rootroot00000000000000package flags type Command struct { // Embedded, see Group for more information *Group // The name by which the command can be invoked Name string // The active sub command (set by parsing) or nil Active *Command commands []*Command hasBuiltinHelpGroup bool } // The command interface should be implemented by any command added in the // options. When implemented, the Execute method will be called for the last // specified (sub)command providing the remaining command line arguments. type Commander interface { // Execute will be called for the last active (sub)command. The // args argument contains the remaining command line arguments. The // error that Execute returns will be eventually passed out of the // Parse method of the Parser. Execute(args []string) error } // The usage interface can be implemented to show a custom usage string in // the help message shown for a command. type Usage interface { // Usage is called for commands to allow customized printing of command // usage in the generated help message. Usage() string } // AddCommand adds a new command to the parser with the given name and data. The // data needs to be a pointer to a struct from which the fields indicate which // options are in the command. The provided data can implement the Command and // Usage interfaces. func (c *Command) AddCommand(command string, shortDescription string, longDescription string, data interface{}) (*Command, error) { cmd := newCommand(command, shortDescription, longDescription, data) if err := cmd.scan(); err != nil { return nil, err } c.commands = append(c.commands, cmd) return cmd, nil } // AddGroup adds a new group to the command with the given name and data. The // data needs to be a pointer to a struct from which the fields indicate which // options are in the group. func (c *Command) AddGroup(shortDescription string, longDescription string, data interface{}) (*Group, error) { group := newGroup(shortDescription, longDescription, data) if err := group.scanType(c.scanSubCommandHandler(group)); err != nil { return nil, err } c.groups = append(c.groups, group) return group, nil } // Get a list of subcommands of this command. func (c *Command) Commands() []*Command { return c.commands } // Find locates the subcommand with the given name and returns it. If no such // command can be found Find will return nil. func (c *Command) Find(name string) *Command { for _, cc := range c.commands { if cc.Name == name { return cc } } return nil } golang-go-flags-0.0~git20131216/command_private.go000066400000000000000000000060461224570357400215550ustar00rootroot00000000000000package flags import ( "reflect" "sort" "strings" "unsafe" ) type lookup struct { shortNames map[string]*Option longNames map[string]*Option required map[*Option]bool commands map[string]*Command } func newCommand(name string, shortDescription string, longDescription string, data interface{}) *Command { return &Command{ Group: newGroup(shortDescription, longDescription, data), Name: name, } } func (c *Command) scanSubCommandHandler(parentg *Group) scanHandler { f := func(realval reflect.Value, sfield *reflect.StructField) (bool, error) { mtag := newMultiTag(string(sfield.Tag)) subcommand := mtag.Get("command") if len(subcommand) != 0 { ptrval := reflect.NewAt(realval.Type(), unsafe.Pointer(realval.UnsafeAddr())) shortDescription := mtag.Get("description") longDescription := mtag.Get("long-description") if _, err := c.AddCommand(subcommand, shortDescription, longDescription, ptrval.Interface()); err != nil { return true, err } return true, nil } return parentg.scanSubGroupHandler(realval, sfield) } return f } func (c *Command) scan() error { return c.scanType(c.scanSubCommandHandler(c.Group)) } func (c *Command) eachCommand(f func(*Command), recurse bool) { f(c) for _, cc := range c.commands { if recurse { cc.eachCommand(f, true) } else { f(cc) } } } func (c *Command) eachActiveGroup(f func(g *Group)) { c.eachGroup(f) if c.Active != nil { c.Active.eachActiveGroup(f) } } func (c *Command) addHelpGroups(showHelp func() error) { if !c.hasBuiltinHelpGroup { c.addHelpGroup(showHelp) c.hasBuiltinHelpGroup = true } for _, cc := range c.commands { cc.addHelpGroups(showHelp) } } func (c *Command) makeLookup() lookup { ret := lookup{ shortNames: make(map[string]*Option), longNames: make(map[string]*Option), required: make(map[*Option]bool), commands: make(map[string]*Command), } c.eachGroup(func(g *Group) { for _, option := range g.options { if option.Required && option.canCli() { ret.required[option] = true } if option.ShortName != 0 { ret.shortNames[string(option.ShortName)] = option } if len(option.LongName) > 0 { ret.longNames[option.LongName] = option } } }) for _, subcommand := range c.commands { ret.commands[subcommand.Name] = subcommand } return ret } func (c *Command) groupByName(name string) *Group { if grp := c.Group.groupByName(name); grp != nil { return grp } for _, subc := range c.commands { prefix := subc.Name + "." if strings.HasPrefix(name, prefix) { if grp := subc.groupByName(name[len(prefix):]); grp != nil { return grp } } else if name == subc.Name { return subc.Group } } return nil } type commandList []*Command func (c commandList) Less(i, j int) bool { return c[i].Name < c[j].Name } func (c commandList) Len() int { return len(c) } func (c commandList) Swap(i, j int) { c[i], c[j] = c[j], c[i] } func (c *Command) sortedCommands() []*Command { ret := make(commandList, len(c.commands)) copy(ret, c.commands) sort.Sort(ret) return []*Command(ret) } golang-go-flags-0.0~git20131216/command_test.go000066400000000000000000000115371224570357400210630ustar00rootroot00000000000000package flags_test import ( "github.com/jessevdk/go-flags" "testing" ) func TestCommandInline(t *testing.T) { var opts = struct { Value bool `short:"v"` Command struct { G bool `short:"g"` } `command:"cmd"` }{} p, ret := assertParserSuccess(t, &opts, "-v", "cmd", "-g") assertStringArray(t, ret, []string{}) if p.Active == nil { t.Errorf("Expected active command") } if !opts.Value { t.Errorf("Expected Value to be true") } if !opts.Command.G { t.Errorf("Expected Command.G to be true") } if p.Command.Find("cmd") != p.Active { t.Errorf("Expected to find command `cmd' to be active") } } func TestCommandInlineMulti(t *testing.T) { var opts = struct { Value bool `short:"v"` C1 struct { } `command:"c1"` C2 struct { G bool `short:"g"` } `command:"c2"` }{} p, ret := assertParserSuccess(t, &opts, "-v", "c2", "-g") assertStringArray(t, ret, []string{}) if p.Active == nil { t.Errorf("Expected active command") } if !opts.Value { t.Errorf("Expected Value to be true") } if !opts.C2.G { t.Errorf("Expected C2.G to be true") } if p.Command.Find("c1") == nil { t.Errorf("Expected to find command `c1'") } if c2 := p.Command.Find("c2"); c2 == nil { t.Errorf("Expected to find command `c2'") } else if c2 != p.Active { t.Errorf("Expected to find command `c2' to be active") } } func TestCommandFlagOrder1(t *testing.T) { var opts = struct { Value bool `short:"v"` Command struct { G bool `short:"g"` } `command:"cmd"` }{} assertParseFail(t, flags.ErrUnknownFlag, "unknown flag `g'", &opts, "-v", "-g", "cmd") } func TestCommandFlagOrder2(t *testing.T) { var opts = struct { Value bool `short:"v"` Command struct { G bool `short:"g"` } `command:"cmd"` }{} assertParseFail(t, flags.ErrUnknownFlag, "unknown flag `v'", &opts, "cmd", "-v", "-g") } func TestCommandEstimate(t *testing.T) { var opts = struct { Value bool `short:"v"` Cmd1 struct { } `command:"remove"` Cmd2 struct { } `command:"add"` }{} p := flags.NewParser(&opts, flags.None) _, err := p.ParseArgs([]string{}) assertError(t, err, flags.ErrRequired, "Please specify one command of: add or remove") } type Command struct { G bool `short:"g"` Executed bool EArgs []string } func (c *Command) Execute(args []string) error { c.Executed = true c.EArgs = args return nil } func TestCommandExecute(t *testing.T) { var opts = struct { Value bool `short:"v"` Command Command `command:"cmd"` }{} assertParseSuccess(t, &opts, "-v", "cmd", "-g", "a", "b") if !opts.Value { t.Errorf("Expected Value to be true") } if !opts.Command.Executed { t.Errorf("Did not execute command") } if !opts.Command.G { t.Errorf("Expected Command.C to be true") } assertStringArray(t, opts.Command.EArgs, []string{"a", "b"}) } func TestCommandClosest(t *testing.T) { var opts = struct { Value bool `short:"v"` Cmd1 struct { } `command:"remove"` Cmd2 struct { } `command:"add"` }{} assertParseFail(t, flags.ErrRequired, "Unknown command `addd', did you mean `add'?", &opts, "-v", "addd") } func TestCommandAdd(t *testing.T) { var opts = struct { Value bool `short:"v"` }{} var cmd = struct { G bool `short:"g"` }{} p := flags.NewParser(&opts, flags.Default) c, err := p.AddCommand("cmd", "", "", &cmd) if err != nil { t.Fatalf("Unexpected error: %v", err) return } ret, err := p.ParseArgs([]string{"-v", "cmd", "-g", "rest"}) if err != nil { t.Fatalf("Unexpected error: %v", err) return } assertStringArray(t, ret, []string{"rest"}) if !opts.Value { t.Errorf("Expected Value to be true") } if !cmd.G { t.Errorf("Expected Command.G to be true") } if p.Command.Find("cmd") != c { t.Errorf("Expected to find command `cmd'") } if p.Commands()[0] != c { t.Errorf("Espected command #v, but got #v", c, p.Commands()[0]) } if c.Options()[0].ShortName != 'g' { t.Errorf("Expected short name `g' but got %v", c.Options()[0].ShortName) } } func TestCommandNestedInline(t *testing.T) { var opts = struct { Value bool `short:"v"` Command struct { G bool `short:"g"` Nested struct { N string `long:"n"` } `command:"nested"` } `command:"cmd"` }{} p, ret := assertParserSuccess(t, &opts, "-v", "cmd", "-g", "nested", "--n", "n", "rest") assertStringArray(t, ret, []string{"rest"}) if !opts.Value { t.Errorf("Expected Value to be true") } if !opts.Command.G { t.Errorf("Expected Command.G to be true") } assertString(t, opts.Command.Nested.N, "n") if c := p.Command.Find("cmd"); c == nil { t.Errorf("Expected to find command `cmd'") } else { if c != p.Active { t.Errorf("Expected `cmd' to be the active parser command") } if nested := c.Find("nested"); nested == nil { t.Errorf("Expected to find command `nested'") } else if nested != c.Active { t.Errorf("Expected to find command `nested' to be the active `cmd' command") } } } golang-go-flags-0.0~git20131216/convert.go000066400000000000000000000142531224570357400200640ustar00rootroot00000000000000// Copyright 2012 Jesse van den Kieboom. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package flags import ( "fmt" "reflect" "strconv" "strings" "time" ) // Marshaler is the interface implemented by types that can marshal themselves // to a string representation of the flag. type Marshaler interface { MarshalFlag() (string, error) } // Unmarshaler is the interface implemented by types that can unmarshal a flag // argument to themselves. The provided value is directly passed from the // command line. type Unmarshaler interface { UnmarshalFlag(value string) error } func getBase(options multiTag, base int) (int, error) { sbase := options.Get("base") var err error var ivbase int64 if sbase != "" { ivbase, err = strconv.ParseInt(sbase, 10, 32) base = int(ivbase) } return base, err } func convertMarshal(val reflect.Value) (bool, string, error) { // Check first for the Marshaler interface if val.Type().NumMethod() > 0 && val.CanInterface() { if marshaler, ok := val.Interface().(Marshaler); ok { ret, err := marshaler.MarshalFlag() return true, ret, err } } return false, "", nil } func convertToString(val reflect.Value, options multiTag) (string, error) { if ok, ret, err := convertMarshal(val); ok { return ret, err } tp := val.Type() // Support for time.Duration if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() { stringer := val.Interface().(fmt.Stringer) return stringer.String(), nil } switch tp.Kind() { case reflect.String: return val.String(), nil case reflect.Bool: if val.Bool() { return "true", nil } else { return "false", nil } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: base, _ := getBase(options, 10) return strconv.FormatInt(val.Int(), base), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: base, _ := getBase(options, 10) return strconv.FormatUint(val.Uint(), base), nil case reflect.Float32, reflect.Float64: return strconv.FormatFloat(val.Float(), 'g', -1, tp.Bits()), nil case reflect.Slice: if val.Len() == 0 { return "", nil } ret := "[" for i := 0; i < val.Len(); i++ { if i != 0 { ret += ", " } item, err := convertToString(val.Index(i), options) if err != nil { return "", err } ret += item } return ret + "]", nil case reflect.Map: ret := "{" for i, key := range val.MapKeys() { if i != 0 { ret += ", " } item, err := convertToString(val.MapIndex(key), options) if err != nil { return "", err } ret += item } return ret + "}", nil case reflect.Ptr: return convertToString(reflect.Indirect(val), options) case reflect.Interface: if !val.IsNil() { return convertToString(val.Elem(), options) } } return "", nil } func convertUnmarshal(val string, retval reflect.Value) (bool, error) { if retval.Type().NumMethod() > 0 && retval.CanInterface() { if unmarshaler, ok := retval.Interface().(Unmarshaler); ok { return true, unmarshaler.UnmarshalFlag(val) } } if retval.Type().Kind() != reflect.Ptr && retval.CanAddr() { return convertUnmarshal(val, retval.Addr()) } if retval.Type().Kind() == reflect.Interface && !retval.IsNil() { return convertUnmarshal(val, retval.Elem()) } return false, nil } func convert(val string, retval reflect.Value, options multiTag) error { if ok, err := convertUnmarshal(val, retval); ok { return err } tp := retval.Type() // Support for time.Duration if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() { parsed, err := time.ParseDuration(val) if err != nil { return err } retval.SetInt(int64(parsed)) return nil } switch tp.Kind() { case reflect.String: retval.SetString(val) case reflect.Bool: if val == "" { retval.SetBool(true) } else { b, err := strconv.ParseBool(val) if err != nil { return err } retval.SetBool(b) } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: base, err := getBase(options, 10) if err != nil { return err } parsed, err := strconv.ParseInt(val, base, tp.Bits()) if err != nil { return err } retval.SetInt(parsed) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: base, err := getBase(options, 10) if err != nil { return err } parsed, err := strconv.ParseUint(val, base, tp.Bits()) if err != nil { return err } retval.SetUint(parsed) case reflect.Float32, reflect.Float64: parsed, err := strconv.ParseFloat(val, tp.Bits()) if err != nil { return err } retval.SetFloat(parsed) case reflect.Slice: elemtp := tp.Elem() elemvalptr := reflect.New(elemtp) elemval := reflect.Indirect(elemvalptr) if err := convert(val, elemval, options); err != nil { return err } retval.Set(reflect.Append(retval, elemval)) case reflect.Map: parts := strings.SplitN(val, ":", 2) key := parts[0] var value string if len(parts) == 2 { value = parts[1] } keytp := tp.Key() keyval := reflect.New(keytp) if err := convert(key, keyval, options); err != nil { return err } valuetp := tp.Elem() valueval := reflect.New(valuetp) if err := convert(value, valueval, options); err != nil { return err } if retval.IsNil() { retval.Set(reflect.MakeMap(tp)) } retval.SetMapIndex(reflect.Indirect(keyval), reflect.Indirect(valueval)) case reflect.Ptr: if retval.IsNil() { retval.Set(reflect.New(retval.Type().Elem())) } return convert(val, reflect.Indirect(retval), options) case reflect.Interface: if !retval.IsNil() { return convert(val, retval.Elem(), options) } } return nil } func wrapText(s string, l int, prefix string) string { // Basic text wrapping of s at spaces to fit in l var ret string s = strings.TrimSpace(s) for len(s) > l { // Try to split on space suffix := "" pos := strings.LastIndex(s[:l], " ") if pos < 0 { pos = l - 1 suffix = "-\n" } if len(ret) != 0 { ret += "\n" + prefix } ret += strings.TrimSpace(s[:pos]) + suffix s = strings.TrimSpace(s[pos:]) } if len(s) > 0 { if len(ret) != 0 { ret += "\n" + prefix } return ret + s } return ret } golang-go-flags-0.0~git20131216/error.go000066400000000000000000000032551224570357400175350ustar00rootroot00000000000000package flags import ( "fmt" ) // ErrorType represents the type of error. type ErrorType uint const ( // Unknown or generic error ErrUnknown ErrorType = iota // Expected an argument but got none ErrExpectedArgument // Unknown flag ErrUnknownFlag // Unknown group ErrUnknownGroup // Failed to marshal value ErrMarshal // The error contains the builtin help message ErrHelp // An argument for a boolean value was specified ErrNoArgumentForBool // A required flag was not specified ErrRequired // A short flag name is longer than one character ErrShortNameTooLong ) func (e ErrorType) String() string { switch e { case ErrUnknown: return "unknown" case ErrExpectedArgument: return "expected argument" case ErrUnknownFlag: return "unknown flag" case ErrUnknownGroup: return "unknown group" case ErrMarshal: return "marshal" case ErrHelp: return "help" case ErrNoArgumentForBool: return "no argument for bool" case ErrRequired: return "required" } return "unknown" } // Error represents a parser error. The error returned from Parse is of this // type. The error contains both a Type and Message. type Error struct { // The type of error Type ErrorType // The error message Message string } // Get the errors error message. func (e *Error) Error() string { return e.Message } func newError(tp ErrorType, message string) *Error { return &Error{ Type: tp, Message: message, } } func newErrorf(tp ErrorType, format string, args ...interface{}) *Error { return newError(tp, fmt.Sprintf(format, args...)) } func wrapError(err error) *Error { ret, ok := err.(*Error) if !ok { return newError(ErrUnknown, err.Error()) } return ret } golang-go-flags-0.0~git20131216/example_test.go000066400000000000000000000052111224570357400210700ustar00rootroot00000000000000// Example of use of the flags package. package flags_test import ( "fmt" "github.com/jessevdk/go-flags" "os" "os/exec" "strings" ) func Example() { var opts struct { // Slice of bool will append 'true' each time the option // is encountered (can be set multiple times, like -vvv) Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` // Example of automatic marshalling to desired type (uint) Offset uint `long:"offset" description:"Offset"` // Example of a callback, called each time the option is found. Call func(string) `short:"c" description:"Call phone number"` // Example of a required flag Name string `short:"n" long:"name" description:"A name" required:"true"` // Example of a value name File string `short:"f" long:"file" description:"A file" value-name:"FILE"` // Example of a pointer Ptr *int `short:"p" description:"A pointer to an integer"` // Example of a slice of strings StringSlice []string `short:"s" description:"A slice of strings"` // Example of a slice of pointers PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"` // Example of a map IntMap map[string]int `long:"intmap" description:"A map from string to int"` } // Callback which will invoke callto: to call a number. // Note that this works just on OS X (and probably only with // Skype) but it shows the idea. opts.Call = func(num string) { cmd := exec.Command("open", "callto:"+num) cmd.Start() cmd.Process.Release() } // Make some fake arguments to parse. args := []string{ "-vv", "--offset=5", "-n", "Me", "-p", "3", "-s", "hello", "-s", "world", "--ptrslice", "hello", "--ptrslice", "world", "--intmap", "a:1", "--intmap", "b:5", "arg1", "arg2", "arg3", } // Parse flags from `args'. Note that here we use flags.ParseArgs for // the sake of making a working example. Normally, you would simply use // flags.Parse(&opts) which uses os.Args args, err := flags.ParseArgs(&opts, args) if err != nil { panic(err) os.Exit(1) } fmt.Printf("Verbosity: %v\n", opts.Verbose) fmt.Printf("Offset: %d\n", opts.Offset) fmt.Printf("Name: %s\n", opts.Name) fmt.Printf("Ptr: %d\n", *opts.Ptr) fmt.Printf("StringSlice: %v\n", opts.StringSlice) fmt.Printf("PtrSlice: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1]) fmt.Printf("IntMap: [a:%v b:%v]\n", opts.IntMap["a"], opts.IntMap["b"]) fmt.Printf("Remaining args: %s\n", strings.Join(args, " ")) // Output: Verbosity: [true true] // Offset: 5 // Name: Me // Ptr: 3 // StringSlice: [hello world] // PtrSlice: [hello world] // IntMap: [a:1 b:5] // Remaining args: arg1 arg2 arg3 } golang-go-flags-0.0~git20131216/examples/000077500000000000000000000000001224570357400176665ustar00rootroot00000000000000golang-go-flags-0.0~git20131216/examples/add.go000066400000000000000000000006411224570357400207460ustar00rootroot00000000000000package main import ( "fmt" ) type AddCommand struct { All bool `short:"a" long:"all" description:"Add all files"` } var addCommand AddCommand func (x *AddCommand) Execute(args []string) error { fmt.Printf("Adding (all=%v): %#v\n", x.All, args) return nil } func init() { parser.AddCommand("add", "Add a file", "The add command adds a file to the repository. Use -a to add all files.", &addCommand) } golang-go-flags-0.0~git20131216/examples/main.go000066400000000000000000000030721224570357400211430ustar00rootroot00000000000000package main import ( "errors" "fmt" "github.com/jessevdk/go-flags" "os" "strconv" "strings" ) type EditorOptions struct { Input string `short:"i" long:"input" description:"Input file" default:"-"` Output string `short:"o" long:"output" description:"Output file" default:"-"` } type Point struct { X, Y int } func (p *Point) UnmarshalFlag(value string) error { parts := strings.Split(value, ",") if len(parts) != 2 { return errors.New("Expected two numbers separated by a ,") } x, err := strconv.ParseInt(parts[0], 10, 32) if err != nil { return err } y, err := strconv.ParseInt(parts[1], 10, 32) if err != nil { return err } p.X = int(x) p.Y = int(y) return nil } func (p Point) MarshalFlag() (string, error) { return fmt.Sprintf("%d,%d", p.X, p.Y), nil } type Options struct { // Example of verbosity with level Verbose []bool `short:"v" long:"verbose" description:"Verbose output"` // Example of optional value User string `short:"u" long:"user" description:"User name" optional:"yes" optional-value:"pancake"` // Example of map with multiple default values Users map[string]string `long:"users" description:"User e-mail map" default:"system:system@example.org" default:"admin:admin@example.org"` // Example of option group Editor EditorOptions `group:"Editor Options"` // Example of custom type Marshal/Unmarshal Point Point `long:"point" description:"A x,y point" default:"1,2"` } var options Options var parser = flags.NewParser(&options, flags.Default) func main() { if _, err := parser.Parse(); err != nil { os.Exit(1) } } golang-go-flags-0.0~git20131216/examples/rm.go000066400000000000000000000006741224570357400206420ustar00rootroot00000000000000package main import ( "fmt" ) type RmCommand struct { Force bool `short:"f" long:"force" description:"Force removal of files"` } var rmCommand RmCommand func (x *RmCommand) Execute(args []string) error { fmt.Printf("Removing (force=%v): %#v\n", x.Force, args) return nil } func init() { parser.AddCommand("rm", "Remove a file", "The rm command removes a file to the repository. Use -f to force removal of files.", &rmCommand) } golang-go-flags-0.0~git20131216/flags.go000066400000000000000000000153101224570357400174730ustar00rootroot00000000000000// Copyright 2012 Jesse van den Kieboom. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package flags provides an extensive command line option parser. // The flags package is similar in functionality to the go builtin flag package // but provides more options and uses reflection to provide a convenient and // succinct way of specifying command line options. // // Supported features: // Options with short names (-v) // Options with long names (--verbose) // Options with and without arguments (bool v.s. other type) // Options with optional arguments and default values // Multiple option groups each containing a set of options // Generate and print well-formatted help message // Passing remaining command line arguments after -- (optional) // Ignoring unknown command line options (optional) // Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification // Supports multiple short options -aux // Supports all primitive go types (string, int{8..64}, uint{8..64}, float) // Supports same option multiple times (can store in slice or last option counts) // Supports maps // Supports function callbacks // // Additional features specific to Windows: // Options with short names (/v) // Options with long names (/verbose) // Windows-style options with arguments use a colon as the delimiter // Modify generated help message with Windows-style / options // // The flags package uses structs, reflection and struct field tags // to allow users to specify command line options. This results in very simple // and consise specification of your application options. For example: // // type Options struct { // Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` // } // // This specifies one option with a short name -v and a long name --verbose. // When either -v or --verbose is found on the command line, a 'true' value // will be appended to the Verbose field. e.g. when specifying -vvv, the // resulting value of Verbose will be {[true, true, true]}. // // Slice options work exactly the same as primitive type options, except that // whenever the option is encountered, a value is appended to the slice. // // Map options from string to primitive type are also supported. On the command // line, you specify the value for such an option as key:value. For example // // type Options struct { // AuthorInfo string[string] `short:"a"` // } // // Then, the AuthorInfo map can be filled with something like // -a name:Jesse -a "surname:van den Kieboom". // // Finally, for full control over the conversion between command line argument // values and options, user defined types can choose to implement the Marshaler // and Unmarshaler interfaces. // // Available field tags: // short: the short name of the option (single character) // long: the long name of the option // description: the description of the option (optional) // optional: whether an argument of the option is optional (optional) // optional-value: the value of an optional option when the option occurs // without an argument. This tag can be specified multiple // times in the case of maps or slices (optional) // default: the default value of an option. This tag can be specified // multiple times in the case of slices or maps (optional). // default-mask: when specified, this value will be displayed in the help // instead of the actual default value. This is useful // mostly for hiding otherwise sensitive information from // showing up in the help. If default-mask takes the special // value "-", then no default value will be shown at all // (optional) // required: whether an option is required to appear on the command // line. If a required option is not present, the parser // will return ErrRequired. // base: a base (radix) used to convert strings to integer values, // the default base is 10 (i.e. decimal) (optional) // value-name: the name of the argument value (to be shown in the help, // (optional) // group: when specified on a struct field, makes the struct field // a separate group with the given name (optional). // command: when specified on a struct field, makes the struct field // a (sub)command with the given name (optional). // // Either short: or long: must be specified to make the field eligible as an // option. // // // Option groups: // // Option groups are a simple way to semantically separate your options. The // only real difference is in how your options will appear in the builtin // generated help. All options in a particular group are shown together in the // help under the name of the group. // // There are currently three ways to specify option groups. // // 1. Use NewNamedParser specifying the various option groups. // 2. Use AddGroup to add a group to an existing parser. // 3. Add a struct field to the toplevel options annotated with the // group:"group-name" tag. // // // // Commands: // // The flags package also has basic support for commands. Commands are often // used in monolithic applications that support various commands or actions. // Take git for example, all of the add, commit, checkout, etc. are called // commands. Using commands you can easily separate multiple functions of your // application. // // There are currently two ways to specifiy a command. // // 1. Use AddCommand on an existing parser. // 2. Add a struct field to your options struct annotated with the // command:"command-name" tag. // // The most common, idiomatic way to implement commands is to define a global // parser instance and implement each command in a separate file. These // command files should define a go init function which calls AddCommand on // the global parser. // // When parsing ends and there is an active command and that command implements // the Commander interface, then its Execute method will be run with the // remaining command line arguments. // // Command structs can have options which become valid to parse after the // command has been specified on the command line. It is currently not valid // to specify options from the parent level of the command after the command // name has occurred. Thus, given a toplevel option "-v" and a command "add": // // Valid: ./app -v add // Invalid: ./app add -v // package flags golang-go-flags-0.0~git20131216/group.go000066400000000000000000000034311224570357400175340ustar00rootroot00000000000000// Copyright 2012 Jesse van den Kieboom. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package flags import ( "errors" "strings" ) // The provided container is not a pointer to a struct var ErrNotPointerToStruct = errors.New("provided data is not a pointer to struct") // An option group. The option group has a name and a set of options. type Group struct { // A short description of the group ShortDescription string // A long description of the group LongDescription string // All the options in the group options []*Option // All the subgroups groups []*Group data interface{} } // AddGroup adds a new group to the command with the given name and data. The // data needs to be a pointer to a struct from which the fields indicate which // options are in the group. func (g *Group) AddGroup(shortDescription string, longDescription string, data interface{}) (*Group, error) { group := newGroup(shortDescription, longDescription, data) if err := group.scan(); err != nil { return nil, err } g.groups = append(g.groups, group) return group, nil } // Get a list of subgroups in the group. func (g *Group) Groups() []*Group { return g.groups } // Get a list of options in the group. func (g *Group) Options() []*Option { return g.options } // Group locates the subgroup with the given short description and returns it. // If no such group can be found Find will return nil. Note that the description // is matched case insensitively. func (g *Group) Find(shortDescription string) *Group { lshortDescription := strings.ToLower(shortDescription) var ret *Group g.eachGroup(func(gg *Group) { if gg != g && strings.ToLower(gg.ShortDescription) == lshortDescription { ret = gg } }) return ret } golang-go-flags-0.0~git20131216/group_private.go000066400000000000000000000107721224570357400212740ustar00rootroot00000000000000package flags import ( "reflect" "unicode/utf8" "unsafe" ) type scanHandler func(reflect.Value, *reflect.StructField) (bool, error) func newGroup(shortDescription string, longDescription string, data interface{}) *Group { return &Group{ ShortDescription: shortDescription, LongDescription: longDescription, data: data, } } func (g *Group) optionByName(name string, namematch func(*Option, string) bool) *Option { prio := 0 var retopt *Option for _, opt := range g.options { if namematch != nil && namematch(opt, name) && prio < 4 { retopt = opt prio = 4 } if name == opt.field.Name && prio < 3 { retopt = opt prio = 3 } if name == opt.LongName && prio < 2 { retopt = opt prio = 2 } if opt.ShortName != 0 && name == string(opt.ShortName) && prio < 1 { retopt = opt prio = 1 } } return retopt } func (g *Group) storeDefaults() { for _, option := range g.options { // First. empty out the value if len(option.Default) > 0 { option.clear() } for _, d := range option.Default { option.set(&d) } if !option.value.CanSet() { continue } option.defaultValue = reflect.ValueOf(option.value.Interface()) } } func (g *Group) eachGroup(f func(*Group)) { f(g) for _, gg := range g.groups { gg.eachGroup(f) } } func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, handler scanHandler) error { stype := realval.Type() if sfield != nil { if ok, err := handler(realval, sfield); err != nil { return err } else if ok { return nil } } for i := 0; i < stype.NumField(); i++ { field := stype.Field(i) // PkgName is set only for non-exported fields, which we ignore if field.PkgPath != "" { continue } mtag := newMultiTag(string(field.Tag)) // Skip fields with the no-flag tag if mtag.Get("no-flag") != "" { continue } // Dive deep into structs or pointers to structs kind := field.Type.Kind() fld := realval.Field(i) if kind == reflect.Struct { if err := g.scanStruct(fld, &field, handler); err != nil { return err } } else if kind == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct { if fld.IsNil() { fld.Set(reflect.New(fld.Type().Elem())) } if err := g.scanStruct(reflect.Indirect(fld), &field, handler); err != nil { return err } } longname := mtag.Get("long") shortname := mtag.Get("short") // Need at least either a short or long name if longname == "" && shortname == "" && mtag.Get("ini-name") == "" { continue } short := rune(0) rc := utf8.RuneCountInString(shortname) if rc > 1 { return newErrorf(ErrShortNameTooLong, "short names can only be 1 character long, not `%s'", shortname) } else if rc == 1 { short, _ = utf8.DecodeRuneInString(shortname) } description := mtag.Get("description") def := mtag.GetMany("default") optionalValue := mtag.GetMany("optional-value") valueName := mtag.Get("value-name") defaultMask := mtag.Get("default-mask") optional := (mtag.Get("optional") != "") required := (mtag.Get("required") != "") option := &Option{ Description: description, ShortName: short, LongName: longname, Default: def, OptionalArgument: optional, OptionalValue: optionalValue, Required: required, ValueName: valueName, DefaultMask: defaultMask, field: field, value: realval.Field(i), tag: mtag, } g.options = append(g.options, option) } return nil } func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.StructField) (bool, error) { mtag := newMultiTag(string(sfield.Tag)) subgroup := mtag.Get("group") if len(subgroup) != 0 { ptrval := reflect.NewAt(realval.Type(), unsafe.Pointer(realval.UnsafeAddr())) description := mtag.Get("description") if _, err := g.AddGroup(subgroup, description, ptrval.Interface()); err != nil { return true, err } return true, nil } return false, nil } func (g *Group) scanType(handler scanHandler) error { // Get all the public fields in the data struct ptrval := reflect.ValueOf(g.data) if ptrval.Type().Kind() != reflect.Ptr { panic(ErrNotPointerToStruct) } stype := ptrval.Type().Elem() if stype.Kind() != reflect.Struct { panic(ErrNotPointerToStruct) } realval := reflect.Indirect(ptrval) return g.scanStruct(realval, nil, handler) } func (g *Group) scan() error { return g.scanType(g.scanSubGroupHandler) } func (g *Group) groupByName(name string) *Group { if len(name) == 0 { return g } return g.Find(name) } golang-go-flags-0.0~git20131216/group_test.go000066400000000000000000000042751224570357400206020ustar00rootroot00000000000000package flags_test import ( "github.com/jessevdk/go-flags" "testing" ) func TestGroupInline(t *testing.T) { var opts = struct { Value bool `short:"v"` Group struct { G bool `short:"g"` } `group:"Grouped Options"` }{} p, ret := assertParserSuccess(t, &opts, "-v", "-g") assertStringArray(t, ret, []string{}) if !opts.Value { t.Errorf("Expected Value to be true") } if !opts.Group.G { t.Errorf("Expected Group.G to be true") } if p.Command.Group.Find("Grouped Options") == nil { t.Errorf("Expected to find group `Grouped Options'") } } func TestGroupAdd(t *testing.T) { var opts = struct { Value bool `short:"v"` }{} var grp = struct { G bool `short:"g"` }{} p := flags.NewParser(&opts, flags.Default) g, err := p.AddGroup("Grouped Options", "", &grp) if err != nil { t.Fatalf("Unexpected error: %v", err) return } ret, err := p.ParseArgs([]string{"-v", "-g", "rest"}) if err != nil { t.Fatalf("Unexpected error: %v", err) return } assertStringArray(t, ret, []string{"rest"}) if !opts.Value { t.Errorf("Expected Value to be true") } if !grp.G { t.Errorf("Expected Group.G to be true") } if p.Command.Group.Find("Grouped Options") != g { t.Errorf("Expected to find group `Grouped Options'") } if p.Groups()[1] != g { t.Errorf("Espected group #v, but got #v", g, p.Groups()[0]) } if g.Options()[0].ShortName != 'g' { t.Errorf("Expected short name `g' but got %v", g.Options()[0].ShortName) } } func TestGroupNestedInline(t *testing.T) { var opts = struct { Value bool `short:"v"` Group struct { G bool `short:"g"` Nested struct { N string `long:"n"` } `group:"Nested Options"` } `group:"Grouped Options"` }{} p, ret := assertParserSuccess(t, &opts, "-v", "-g", "--n", "n", "rest") assertStringArray(t, ret, []string{"rest"}) if !opts.Value { t.Errorf("Expected Value to be true") } if !opts.Group.G { t.Errorf("Expected Group.G to be true") } assertString(t, opts.Group.Nested.N, "n") if p.Command.Group.Find("Grouped Options") == nil { t.Errorf("Expected to find group `Grouped Options'") } if p.Command.Group.Find("Nested Options") == nil { t.Errorf("Expected to find group `Nested Options'") } } golang-go-flags-0.0~git20131216/help.go000066400000000000000000000124341224570357400173330ustar00rootroot00000000000000// Copyright 2012 Jesse van den Kieboom. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package flags import ( "bufio" "bytes" "fmt" "io" "reflect" "strings" "unicode/utf8" ) type alignmentInfo struct { maxLongLen int hasShort bool hasValueName bool terminalColumns int } func (p *Parser) getAlignmentInfo() alignmentInfo { ret := alignmentInfo{ maxLongLen: 0, hasShort: false, hasValueName: false, terminalColumns: getTerminalColumns(), } if ret.terminalColumns <= 0 { ret.terminalColumns = 80 } p.eachActiveGroup(func(grp *Group) { for _, info := range grp.options { if info.ShortName != 0 { ret.hasShort = true } lv := utf8.RuneCountInString(info.ValueName) if lv != 0 { ret.hasValueName = true } l := utf8.RuneCountInString(info.LongName) + lv if l > ret.maxLongLen { ret.maxLongLen = l } } }) return ret } func (p *Parser) writeHelpOption(writer *bufio.Writer, option *Option, info alignmentInfo) { line := &bytes.Buffer{} distanceBetweenOptionAndDescription := 2 paddingBeforeOption := 2 line.WriteString(strings.Repeat(" ", paddingBeforeOption)) if option.ShortName != 0 { line.WriteRune(defaultShortOptDelimiter) line.WriteRune(option.ShortName) } else if info.hasShort { line.WriteString(" ") } descstart := info.maxLongLen + paddingBeforeOption + distanceBetweenOptionAndDescription if info.hasShort { descstart += 2 } if info.maxLongLen > 0 { descstart += 4 } if info.hasValueName { descstart += 3 } if len(option.LongName) > 0 { if option.ShortName != 0 { line.WriteString(", ") } else if info.hasShort { line.WriteString(" ") } line.WriteString(defaultLongOptDelimiter) line.WriteString(option.LongName) } if option.canArgument() { line.WriteRune(defaultNameArgDelimiter) if len(option.ValueName) > 0 { line.WriteString(option.ValueName) } } written := line.Len() line.WriteTo(writer) if option.Description != "" { dw := descstart - written writer.WriteString(strings.Repeat(" ", dw)) def := "" defs := option.Default if len(option.DefaultMask) != 0 { if option.DefaultMask != "-" { def = option.DefaultMask } } else if len(defs) == 0 && option.canArgument() { var showdef bool switch option.field.Type.Kind() { case reflect.Func, reflect.Ptr: showdef = !option.value.IsNil() case reflect.Slice, reflect.String, reflect.Array: showdef = option.value.Len() > 0 case reflect.Map: showdef = !option.value.IsNil() && option.value.Len() > 0 default: zeroval := reflect.Zero(option.field.Type) showdef = !reflect.DeepEqual(zeroval.Interface(), option.value.Interface()) } if showdef { def, _ = convertToString(option.value, option.tag) } } else if len(defs) != 0 { def = strings.Join(defs, ", ") } var desc string if def != "" { desc = fmt.Sprintf("%s (%v)", option.Description, def) } else { desc = option.Description } writer.WriteString(wrapText(desc, info.terminalColumns-descstart, strings.Repeat(" ", descstart))) } writer.WriteString("\n") } func maxCommandLength(s []*Command) int { if len(s) == 0 { return 0 } ret := len(s[0].Name) for _, v := range s[1:] { l := len(v.Name) if l > ret { ret = l } } return ret } // WriteHelp writes a help message containing all the possible options and // their descriptions to the provided writer. Note that the HelpFlag parser // option provides a convenient way to add a -h/--help option group to the // command line parser which will automatically show the help messages using // this method. func (p *Parser) WriteHelp(writer io.Writer) { if writer == nil { return } wr := bufio.NewWriter(writer) aligninfo := p.getAlignmentInfo() cmd := p.Command for cmd.Active != nil { cmd = cmd.Active } if p.Name != "" { wr.WriteString("Usage:\n") wr.WriteString(" ") allcmd := p.Command for allcmd != nil { var usage string if allcmd == p.Command { if len(p.Usage) != 0 { usage = p.Usage } else { usage = "[OPTIONS]" } } else if us, ok := allcmd.data.(Usage); ok { usage = us.Usage() } else { usage = fmt.Sprintf("[%s-OPTIONS]", allcmd.Name) } if len(usage) != 0 { fmt.Fprintf(wr, " %s %s", allcmd.Name, usage) } else { fmt.Fprintf(wr, " %s", allcmd.Name) } allcmd = allcmd.Active } fmt.Fprintln(wr) if len(cmd.LongDescription) != 0 { fmt.Fprintln(wr) t := wrapText(cmd.LongDescription, aligninfo.terminalColumns, "") fmt.Fprintln(wr, t) } } p.eachActiveGroup(func(grp *Group) { first := true for _, info := range grp.options { if info.canCli() { if first { fmt.Fprintf(wr, "\n%s:\n", grp.ShortDescription) first = false } p.writeHelpOption(wr, info, aligninfo) } } }) scommands := cmd.sortedCommands() if len(scommands) > 0 { maxnamelen := maxCommandLength(scommands) fmt.Fprintln(wr) fmt.Fprintln(wr, "Available commands:") for _, c := range scommands { fmt.Fprintf(wr, " %s", c.Name) if len(c.ShortDescription) > 0 { pad := strings.Repeat(" ", maxnamelen-len(c.Name)) fmt.Fprintf(wr, "%s %s", pad, c.ShortDescription) } fmt.Fprintln(wr) } } wr.Flush() } golang-go-flags-0.0~git20131216/help_test.go000066400000000000000000000067151224570357400203770ustar00rootroot00000000000000package flags_test import ( "bytes" "fmt" "github.com/jessevdk/go-flags" "io" "io/ioutil" "os" "os/exec" "testing" "time" ) func helpDiff(a, b string) (string, error) { atmp, err := ioutil.TempFile("", "help-diff") if err != nil { return "", err } btmp, err := ioutil.TempFile("", "help-diff") if err != nil { return "", err } if _, err := io.WriteString(atmp, a); err != nil { return "", err } if _, err := io.WriteString(btmp, b); err != nil { return "", err } ret, err := exec.Command("diff", "-u", "-d", "--label", "got", atmp.Name(), "--label", "expected", btmp.Name()).Output() os.Remove(atmp.Name()) os.Remove(btmp.Name()) return string(ret), nil } type helpOptions struct { Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information" ini-name:"verbose"` Call func(string) `short:"c" description:"Call phone number" ini-name:"call"` PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"` OnlyIni string `ini-name:"only-ini" description:"Option only available in ini"` Other struct { StringSlice []string `short:"s" description:"A slice of strings"` IntMap map[string]int `long:"intmap" description:"A map from string to int" ini-name:"int-map"` } `group:"Other Options"` } func TestHelp(t *testing.T) { var opts helpOptions p := flags.NewNamedParser("TestHelp", flags.HelpFlag) p.AddGroup("Application Options", "The application options", &opts) _, err := p.ParseArgs([]string{"--help"}) if err == nil { t.Fatalf("Expected help error") } if e, ok := err.(*flags.Error); !ok { t.Fatalf("Expected flags.Error, but got %#T", err) } else { if e.Type != flags.ErrHelp { t.Errorf("Expected flags.ErrHelp type, but got %s", e.Type) } expected := `Usage: TestHelp [OPTIONS] Application Options: -v, --verbose Show verbose debug information -c= Call phone number --ptrslice= A slice of pointers to string Other Options: -s= A slice of strings --intmap= A map from string to int Help Options: -h, --help Show this help message ` if e.Message != expected { ret, err := helpDiff(e.Message, expected) if err != nil { t.Errorf("Unexpected diff error: %s", err) t.Errorf("Unexpected help message, expected:\n\n%s\n\nbut got\n\n%s", expected, e.Message) } else { t.Errorf("Unexpected help message:\n\n%s", ret) } } } } func TestMan(t *testing.T) { var opts helpOptions p := flags.NewNamedParser("TestMan", flags.HelpFlag) p.ShortDescription = "Test manpage generation" p.LongDescription = "This is a somewhat longer description of what this does" p.AddGroup("Application Options", "The application options", &opts) var buf bytes.Buffer p.WriteManPage(&buf) got := buf.String() tt := time.Now() expected := fmt.Sprintf(`.TH TestMan 1 "%s" .SH NAME TestMan \- Test manpage generation .SH SYNOPSIS \fBTestMan\fP [OPTIONS] .SH DESCRIPTION This is a somewhat longer description of what this does .SH OPTIONS .TP \fB-v, --verbose\fP Show verbose debug information .TP \fB-c\fP Call phone number .TP \fB--ptrslice\fP A slice of pointers to string .TP \fB-s\fP A slice of strings .TP \fB--intmap\fP A map from string to int `, tt.Format("2 January 2006")) if got != expected { ret, err := helpDiff(got, expected) if err != nil { t.Errorf("Unexpected man page, expected:\n\n%s\n\nbut got\n\n%s", expected, got) } else { t.Errorf("Unexpected man page:\n\n%s", ret) } } } golang-go-flags-0.0~git20131216/ini.go000066400000000000000000000072621224570357400171650ustar00rootroot00000000000000package flags import ( "fmt" "io" "os" ) // IniError contains location information on where in the ini file an error // occured. type IniError struct { Message string File string LineNumber uint } // Error provides a "file:line: message" formatted message of the ini error. func (x *IniError) Error() string { return fmt.Sprintf("%s:%d: %s", x.File, x.LineNumber, x.Message) } // Options for writing ini files type IniOptions uint const ( // No options IniNone IniOptions = 0 // Write default values IniIncludeDefaults = 1 << iota // Write comments containing the description of an option IniIncludeComments // Default options IniDefault = IniIncludeComments ) // IniParser is a utility to read and write flags options from and to ini // files. type IniParser struct { parser *Parser } // NewIniParser creates a new ini parser for a given Parser. func NewIniParser(p *Parser) *IniParser { return &IniParser{ parser: p, } } // IniParse is a convenience function to parse command line options with default // settings from an ini file. The provided data is a pointer to a struct // representing the default option group (named "Application Options"). For // more control, use flags.NewParser. func IniParse(filename string, data interface{}) error { p := NewParser(data, Default) return NewIniParser(p).ParseFile(filename) } // ParseFile parses flags from an ini formatted file. See Parse for more // information on the ini file foramt. The returned errors can be of the type // flags.Error or flags.IniError. func (i *IniParser) ParseFile(filename string) error { i.parser.storeDefaults() ini, err := readIniFromFile(filename) if err != nil { return err } return i.parse(ini) } // Parse parses flags from an ini format. You can use ParseFile as a // convenience function to parse from a filename instead of a general // io.Reader. // // The format of the ini file is as follows: // // [Option group name] // option = value // // Each section in the ini file represents an option group or command in the // flags parser. The default flags parser option group (i.e. when using // flags.Parse) is named 'Application Options'. The ini option name is matched // in the following order: // // 1. Compared to the ini-name tag on the option struct field (if present) // 2. Compared to the struct field name // 3. Compared to the option long name (if present) // 4. Compared to the option short name (if present) // // Sections for nested groups and commands can be addressed using a dot `.' // namespacing notation (i.e [subcommand.Options]). Group section names are // matched case insensitive. // // The returned errors can be of the type flags.Error or // flags.IniError. func (i *IniParser) Parse(reader io.Reader) error { i.parser.storeDefaults() ini, err := readIni(reader, "") if err != nil { return err } return i.parse(ini) } // WriteFile writes the flags as ini format into a file. See WriteIni // for more information. The returned error occurs when the specified file // could not be opened for writing. func (i *IniParser) WriteFile(filename string, options IniOptions) error { file, err := os.Create(filename) if err != nil { return err } defer file.Close() i.Write(file, options) return nil } // WriteIni writes the current values of all the flags to an ini format. // See ParseIni for more information on the ini file format. You typically // call this only after settings have been parsed since the default values of each // option are stored just before parsing the flags (this is only relevant when // IniIncludeDefaults is _not_ set in options). func (i *IniParser) Write(writer io.Writer, options IniOptions) { writeIni(i, writer, options) } golang-go-flags-0.0~git20131216/ini_private.go000066400000000000000000000135261224570357400207170ustar00rootroot00000000000000package flags import ( "bufio" "fmt" "io" "os" "reflect" "strings" ) type iniValue struct { Name string Value string } type iniSection []iniValue type ini map[string]iniSection func readFullLine(reader *bufio.Reader) (string, error) { var line []byte for { l, more, err := reader.ReadLine() if err != nil { return "", err } if line == nil && !more { return string(l), nil } line = append(line, l...) if !more { break } } return string(line), nil } func optionIniName(option *Option) string { name := option.tag.Get("_read-ini-name") if len(name) != 0 { return name } name = option.tag.Get("ini-name") if len(name) != 0 { return name } return option.field.Name } func writeGroupIni(group *Group, namespace string, writer io.Writer, options IniOptions) { var sname string if len(namespace) != 0 { sname = namespace + "." + group.ShortDescription } else { sname = group.ShortDescription } sectionwritten := false comments := (options & IniIncludeComments) != IniNone for _, option := range group.options { if option.isFunc() { continue } if len(option.tag.Get("no-ini")) != 0 { continue } val := option.value if (options&IniIncludeDefaults) == IniNone && reflect.DeepEqual(val, option.defaultValue) { continue } if !sectionwritten { fmt.Fprintf(writer, "[%s]\n", sname) sectionwritten = true } if comments { fmt.Fprintf(writer, "; %s\n", option.Description) } oname := optionIniName(option) switch val.Type().Kind() { case reflect.Slice: for idx := 0; idx < val.Len(); idx++ { v, _ := convertToString(val.Index(idx), option.tag) fmt.Fprintf(writer, "%s = %s\n", oname, v) } if val.Len() == 0 { fmt.Fprintf(writer, "; %s =\n", oname) } case reflect.Map: for _, key := range val.MapKeys() { k, _ := convertToString(key, option.tag) v, _ := convertToString(val.MapIndex(key), option.tag) fmt.Fprintf(writer, "%s = %s:%s\n", oname, k, v) } if val.Len() == 0 { fmt.Fprintf(writer, "; %s =\n", oname) } default: v, _ := convertToString(val, option.tag) if len(v) != 0 { fmt.Fprintf(writer, "%s = %s\n", oname, v) } else { fmt.Fprintf(writer, "%s =\n", oname) } } if comments { fmt.Fprintln(writer) } } if sectionwritten && !comments { fmt.Fprintln(writer) } } func writeCommandIni(command *Command, namespace string, writer io.Writer, options IniOptions) { command.eachGroup(func(group *Group) { writeGroupIni(group, namespace, writer, options) }) for _, c := range command.commands { var nns string if len(namespace) != 0 { nns = c.Name + "." + nns } else { nns = c.Name } writeCommandIni(c, nns, writer, options) } } func writeIni(parser *IniParser, writer io.Writer, options IniOptions) { writeCommandIni(parser.parser.Command, "", writer, options) } func readIniFromFile(filename string) (ini, error) { file, err := os.Open(filename) if err != nil { return nil, err } defer file.Close() return readIni(file, filename) } func readIni(contents io.Reader, filename string) (ini, error) { ret := make(ini) reader := bufio.NewReader(contents) // Empty global section section := make(iniSection, 0, 10) sectionname := "" ret[sectionname] = section var lineno uint for { line, err := readFullLine(reader) if err == io.EOF { break } if err != nil { return nil, err } lineno++ line = strings.TrimSpace(line) // Skip empty lines and lines starting with ; (comments) if len(line) == 0 || line[0] == ';' { continue } if line[0] == '[' { if line[0] != '[' || line[len(line)-1] != ']' { return nil, &IniError{ Message: "malformed section header", File: filename, LineNumber: lineno, } } name := strings.TrimSpace(line[1 : len(line)-1]) if len(name) == 0 { return nil, &IniError{ Message: "empty section name", File: filename, LineNumber: lineno, } } sectionname = name section = ret[name] if section == nil { section = make(iniSection, 0, 10) ret[name] = section } continue } // Parse option here keyval := strings.SplitN(line, "=", 2) if len(keyval) != 2 { return nil, &IniError{ Message: fmt.Sprintf("malformed key=value (%s)", line), File: filename, LineNumber: lineno, } } name := strings.TrimSpace(keyval[0]) value := strings.TrimSpace(keyval[1]) section = append(section, iniValue{ Name: name, Value: value, }) ret[sectionname] = section } return ret, nil } func (i *IniParser) matchingGroups(name string) []*Group { if len(name) == 0 { var ret []*Group i.parser.eachGroup(func(g *Group) { ret = append(ret, g) }) return ret } else { g := i.parser.groupByName(name) if g != nil { return []*Group{g} } else { return nil } } } func (i *IniParser) parse(ini ini) error { p := i.parser for name, section := range ini { groups := i.matchingGroups(name) if len(groups) == 0 { return newError(ErrUnknownGroup, fmt.Sprintf("could not find option group `%s'", name)) } for _, inival := range section { var opt *Option for _, group := range groups { opt = group.optionByName(inival.Name, func(o *Option, n string) bool { return strings.ToLower(o.tag.Get("ini-name")) == strings.ToLower(n) }) if opt != nil && len(opt.tag.Get("no-ini")) != 0 { opt = nil } if opt != nil { break } } if opt == nil { if (p.Options & IgnoreUnknown) == None { return newError(ErrUnknownFlag, fmt.Sprintf("unknown option: %s", inival.Name)) } continue } pval := &inival.Value if !opt.canArgument() && len(inival.Value) == 0 { pval = nil } if err := opt.set(pval); err != nil { return wrapError(err) } opt.tag.Set("_read-ini-name", inival.Name) } } return nil } golang-go-flags-0.0~git20131216/ini_test.go000066400000000000000000000064011224570357400202160ustar00rootroot00000000000000package flags_test import ( "bytes" "github.com/jessevdk/go-flags" "strings" "testing" ) func TestWriteIni(t *testing.T) { var opts helpOptions p := flags.NewNamedParser("TestIni", flags.Default) p.AddGroup("Application Options", "The application options", &opts) p.ParseArgs([]string{"-vv", "--intmap=a:2", "--intmap", "b:3"}) inip := flags.NewIniParser(p) var b bytes.Buffer inip.Write(&b, flags.IniDefault|flags.IniIncludeDefaults) got := b.String() expected := `[Application Options] ; Show verbose debug information verbose = true verbose = true ; A slice of pointers to string ; PtrSlice = ; Option only available in ini only-ini = [Other Options] ; A slice of strings ; StringSlice = ; A map from string to int int-map = a:2 int-map = b:3 ` if got != expected { ret, err := helpDiff(got, expected) if err != nil { t.Errorf("Unexpected ini, expected:\n\n%s\n\nbut got\n\n%s", expected, got) } else { t.Errorf("Unexpected ini:\n\n%s", ret) } } } func TestReadIni(t *testing.T) { var opts helpOptions p := flags.NewNamedParser("TestIni", flags.Default) p.AddGroup("Application Options", "The application options", &opts) inip := flags.NewIniParser(p) inic := ` ; Show verbose debug information verbose = true verbose = true [Application Options] ; A slice of pointers to string ; PtrSlice = [Other Options] ; A slice of strings ; StringSlice = ; A map from string to int int-map = a:2 int-map = b:3 ` b := strings.NewReader(inic) err := inip.Parse(b) if err != nil { t.Fatalf("Unexpected error: %s", err) } assertBoolArray(t, opts.Verbose, []bool{true, true}) if v, ok := opts.Other.IntMap["a"]; !ok { t.Errorf("Expected \"a\" in Other.IntMap") } else if v != 2 { t.Errorf("Expected Other.IntMap[\"a\"] = 2, but got %v", v) } if v, ok := opts.Other.IntMap["b"]; !ok { t.Errorf("Expected \"b\" in Other.IntMap") } else if v != 3 { t.Errorf("Expected Other.IntMap[\"b\"] = 3, but got %v", v) } } func TestIniCommands(t *testing.T) { var opts struct { Value string `short:"v" long:"value"` Add struct { Name int `short:"n" long:"name" ini-name:"AliasName"` Other struct { O string `short:"o" long:"other"` } `group:"Other Options"` } `command:"add"` } p := flags.NewNamedParser("TestIni", flags.Default) p.AddGroup("Application Options", "The application options", &opts) inip := flags.NewIniParser(p) inic := `[Application Options] value = some value [add] AliasName = 5 [add.Other Options] other = subgroup ` b := strings.NewReader(inic) err := inip.Parse(b) if err != nil { t.Fatalf("Unexpected error: %s", err) } assertString(t, opts.Value, "some value") if opts.Add.Name != 5 { t.Errorf("Expected opts.Add.Name to be 5, but got %v", opts.Add.Name) } assertString(t, opts.Add.Other.O, "subgroup") } func TestIniNoIni(t *testing.T) { var opts struct { Value string `short:"v" long:"value" no-ini:"yes"` } p := flags.NewNamedParser("TestIni", flags.Default) p.AddGroup("Application Options", "The application options", &opts) inip := flags.NewIniParser(p) inic := `[Application Options] value = some value ` b := strings.NewReader(inic) err := inip.Parse(b) if err == nil { t.Fatalf("Expected error") } assertError(t, err, flags.ErrUnknownFlag, "unknown option: value") } golang-go-flags-0.0~git20131216/long_test.go000066400000000000000000000033751224570357400204050ustar00rootroot00000000000000package flags_test import ( "testing" ) func TestLong(t *testing.T) { var opts = struct { Value bool `long:"value"` }{} ret := assertParseSuccess(t, &opts, "--value") assertStringArray(t, ret, []string{}) if !opts.Value { t.Errorf("Expected Value to be true") } } func TestLongArg(t *testing.T) { var opts = struct { Value string `long:"value"` }{} ret := assertParseSuccess(t, &opts, "--value", "value") assertStringArray(t, ret, []string{}) assertString(t, opts.Value, "value") } func TestLongArgEqual(t *testing.T) { var opts = struct { Value string `long:"value"` }{} ret := assertParseSuccess(t, &opts, "--value=value") assertStringArray(t, ret, []string{}) assertString(t, opts.Value, "value") } func TestLongDefault(t *testing.T) { var opts = struct { Value string `long:"value" default:"value"` }{} ret := assertParseSuccess(t, &opts) assertStringArray(t, ret, []string{}) assertString(t, opts.Value, "value") } func TestLongOptional(t *testing.T) { var opts = struct { Value string `long:"value" optional:"yes" optional-value:"value"` }{} ret := assertParseSuccess(t, &opts, "--value") assertStringArray(t, ret, []string{}) assertString(t, opts.Value, "value") } func TestLongOptionalArg(t *testing.T) { var opts = struct { Value string `long:"value" optional:"yes" optional-value:"value"` }{} ret := assertParseSuccess(t, &opts, "--value", "no") assertStringArray(t, ret, []string{"no"}) assertString(t, opts.Value, "value") } func TestLongOptionalArgEqual(t *testing.T) { var opts = struct { Value string `long:"value" optional:"yes" optional-value:"value"` }{} ret := assertParseSuccess(t, &opts, "--value=value", "no") assertStringArray(t, ret, []string{"no"}) assertString(t, opts.Value, "value") } golang-go-flags-0.0~git20131216/man.go000066400000000000000000000051061224570357400171540ustar00rootroot00000000000000package flags import ( "fmt" "io" "strings" "time" ) func formatForMan(wr io.Writer, s string) { for { idx := strings.IndexRune(s, '`') if idx < 0 { fmt.Fprintf(wr, "%s", s) break } fmt.Fprintf(wr, "%s", s[:idx]) s = s[idx+1:] idx = strings.IndexRune(s, '\'') if idx < 0 { fmt.Fprintf(wr, "%s", s) break } fmt.Fprintf(wr, "\\fB%s\\fP", s[:idx]) s = s[idx+1:] } } func writeManPageOptions(wr io.Writer, grp *Group) { grp.eachGroup(func(group *Group) { for _, opt := range group.options { if !opt.canCli() { continue } fmt.Fprintln(wr, ".TP") fmt.Fprintf(wr, "\\fB") if opt.ShortName != 0 { fmt.Fprintf(wr, "-%c", opt.ShortName) } if len(opt.LongName) != 0 { if opt.ShortName != 0 { fmt.Fprintf(wr, ", ") } fmt.Fprintf(wr, "--%s", opt.LongName) } fmt.Fprintln(wr, "\\fP") formatForMan(wr, opt.Description) fmt.Fprintln(wr, "") } }) } func writeManPageSubCommands(wr io.Writer, name string, root *Command) { commands := root.sortedCommands() for _, c := range commands { var nn string if len(name) != 0 { nn = name + " " + c.Name } else { nn = c.Name } writeManPageCommand(wr, nn, c) } } func writeManPageCommand(wr io.Writer, name string, command *Command) { fmt.Fprintf(wr, ".SS %s\n", name) fmt.Fprintln(wr, command.ShortDescription) if len(command.LongDescription) > 0 { fmt.Fprintln(wr, "") cmdstart := fmt.Sprintf("The %s command", command.Name) if strings.HasPrefix(command.LongDescription, cmdstart) { fmt.Fprintf(wr, "The \\fI%s\\fP command", command.Name) formatForMan(wr, command.LongDescription[len(cmdstart):]) fmt.Fprintln(wr, "") } else { formatForMan(wr, command.LongDescription) fmt.Fprintln(wr, "") } } writeManPageOptions(wr, command.Group) writeManPageSubCommands(wr, name, command) } // WriteManPage writes a basic man page in groff format to the specified // writer. func (p *Parser) WriteManPage(wr io.Writer) { t := time.Now() fmt.Fprintf(wr, ".TH %s 1 \"%s\"\n", p.Name, t.Format("2 January 2006")) fmt.Fprintln(wr, ".SH NAME") fmt.Fprintf(wr, "%s \\- %s\n", p.Name, p.ShortDescription) fmt.Fprintln(wr, ".SH SYNOPSIS") usage := p.Usage if len(usage) == 0 { usage = "[OPTIONS]" } fmt.Fprintf(wr, "\\fB%s\\fP %s\n", p.Name, usage) fmt.Fprintln(wr, ".SH DESCRIPTION") formatForMan(wr, p.LongDescription) fmt.Fprintln(wr, "") fmt.Fprintln(wr, ".SH OPTIONS") writeManPageOptions(wr, p.Command.Group) if len(p.commands) > 0 { fmt.Fprintln(wr, ".SH COMMANDS") writeManPageSubCommands(wr, "", p.Command) } } golang-go-flags-0.0~git20131216/marshal_test.go000066400000000000000000000027341224570357400210730ustar00rootroot00000000000000package flags_test import ( "fmt" "github.com/jessevdk/go-flags" "testing" ) type marshalled bool func (m *marshalled) UnmarshalFlag(value string) error { if value == "yes" { *m = true } else if value == "no" { *m = false } else { return fmt.Errorf("`%s' is not a valid value, please specify `yes' or `no'", value) } return nil } func (m marshalled) MarshalFlag() string { if m { return "yes" } return "no" } func TestMarshal(t *testing.T) { var opts = struct { Value marshalled `short:"v"` }{} ret := assertParseSuccess(t, &opts, "-v=yes") assertStringArray(t, ret, []string{}) if !opts.Value { t.Errorf("Expected Value to be true") } } func TestMarshalDefault(t *testing.T) { var opts = struct { Value marshalled `short:"v" default:"yes"` }{} ret := assertParseSuccess(t, &opts) assertStringArray(t, ret, []string{}) if !opts.Value { t.Errorf("Expected Value to be true") } } func TestMarshalOptional(t *testing.T) { var opts = struct { Value marshalled `short:"v" optional:"yes" optional-value:"yes"` }{} ret := assertParseSuccess(t, &opts, "-v") assertStringArray(t, ret, []string{}) if !opts.Value { t.Errorf("Expected Value to be true") } } func TestMarshalError(t *testing.T) { var opts = struct { Value marshalled `short:"v"` }{} assertParseFail(t, flags.ErrMarshal, "invalid argument for flag `-v' (expected flags_test.marshalled): `invalid' is not a valid value, please specify `yes' or `no'", &opts, "-vinvalid") } golang-go-flags-0.0~git20131216/multitag.go000066400000000000000000000026661224570357400202370ustar00rootroot00000000000000package flags import ( "strconv" ) type multiTag struct { value string cache map[string][]string } func newMultiTag(v string) multiTag { return multiTag{ value: v, } } func (x *multiTag) scan() map[string][]string { v := x.value ret := make(map[string][]string) // This is mostly copied from reflect.StructTAg.Get for v != "" { i := 0 // Skip whitespace for i < len(v) && v[i] == ' ' { i++ } v = v[i:] if v == "" { break } // Scan to colon to find key i = 0 for i < len(v) && v[i] != ' ' && v[i] != ':' && v[i] != '"' { i++ } if i+1 >= len(v) || v[i] != ':' || v[i+1] != '"' { break } name := v[:i] v = v[i+1:] // Scan quoted string to find value i = 1 for i < len(v) && v[i] != '"' { if v[i] == '\\' { i++ } i++ } if i >= len(v) { break } val, _ := strconv.Unquote(v[:i+1]) v = v[i+1:] ret[name] = append(ret[name], val) } return ret } func (x *multiTag) cached() map[string][]string { if x.cache == nil { x.cache = x.scan() } return x.cache } func (x *multiTag) Get(key string) string { c := x.cached() if v, ok := c[key]; ok { return v[len(v)-1] } return "" } func (x *multiTag) GetMany(key string) []string { c := x.cached() return c[key] } func (x *multiTag) Set(key string, value string) { c := x.cached() c[key] = []string{value} } func (x *multiTag) SetMany(key string, value []string) { c := x.cached() c[key] = value } golang-go-flags-0.0~git20131216/option.go000066400000000000000000000055501224570357400177140ustar00rootroot00000000000000package flags import ( "fmt" "reflect" "unicode/utf8" ) // Option flag information. Contains a description of the option, short and // long name as well as a default value and whether an argument for this // flag is optional. type Option struct { // The description of the option flag. This description is shown // automatically in the builtin help. Description string // The short name of the option (a single character). If not 0, the // option flag can be 'activated' using -. Either ShortName // or LongName needs to be non-empty. ShortName rune // The long name of the option. If not "", the option flag can be // activated using --. Either ShortName or LongName needs // to be non-empty. LongName string // The default value of the option. Default []string // If true, specifies that the argument to an option flag is optional. // When no argument to the flag is specified on the command line, the // value of Default will be set in the field this option represents. // This is only valid for non-boolean options. OptionalArgument bool // The optional value of the option. The optional value is used when // the option flag is marked as having an OptionalArgument. This means // that when the flag is specified, but no option argument is given, // the value of the field this option represents will be set to // OptionalValue. This is only valid for non-boolean options. OptionalValue []string // If true, the option _must_ be specified on the command line. If the // option is not specified, the parser will generate an ErrRequired type // error. Required bool // A name for the value of an option shown in the Help as --flag [ValueName] ValueName string // A mask value to show in the help instead of the default value. This // is useful for hiding sensitive information in the help, such as // passwords. DefaultMask string // The struct field which the option represents. field reflect.StructField // The struct field value which the option represents. value reflect.Value defaultValue reflect.Value iniUsedName string tag multiTag } // Convert an option to a human friendly readable string describing the option. func (option *Option) String() string { var s string var short string if option.ShortName != 0 { data := make([]byte, utf8.RuneLen(option.ShortName)) utf8.EncodeRune(data, option.ShortName) short = string(data) if len(option.LongName) != 0 { s = fmt.Sprintf("%s%s, %s%s", string(defaultShortOptDelimiter), short, defaultLongOptDelimiter, option.LongName) } else { s = fmt.Sprintf("%s%s", string(defaultShortOptDelimiter), short) } } else if len(option.LongName) != 0 { s = fmt.Sprintf("%s%s", defaultLongOptDelimiter, option.LongName) } return s } // Get the option value as an interface{} func (option *Option) Value() interface{} { return option.value.Interface() } golang-go-flags-0.0~git20131216/option_private.go000066400000000000000000000042471224570357400214500ustar00rootroot00000000000000package flags import ( "reflect" ) // Set the value of an option to the specified value. An error will be returned // if the specified value could not be converted to the corresponding option // value type. func (option *Option) set(value *string) error { if option.isFunc() { return option.call(value) } else if value != nil { return convert(*value, option.value, option.tag) } else { return convert("", option.value, option.tag) } return nil } func (option *Option) canCli() bool { return option.ShortName != 0 || len(option.LongName) != 0 } func (option *Option) canArgument() bool { if u := option.isUnmarshaler(); u != nil { return true } return !option.isBool() } func (option *Option) clear() { tp := option.value.Type() switch tp.Kind() { case reflect.Func: // Skip case reflect.Map: // Empty the map option.value.Set(reflect.MakeMap(tp)) default: zeroval := reflect.Zero(tp) option.value.Set(zeroval) } } func (option *Option) isUnmarshaler() Unmarshaler { v := option.value for { if !v.CanInterface() { return nil } i := v.Interface() if u, ok := i.(Unmarshaler); ok { return u } if !v.CanAddr() { return nil } v = v.Addr() } return nil } func (option *Option) isBool() bool { tp := option.value.Type() for { switch tp.Kind() { case reflect.Bool: return true case reflect.Slice: return (tp.Elem().Kind() == reflect.Bool) case reflect.Func: return tp.NumIn() == 0 case reflect.Ptr: tp = tp.Elem() default: return false } } return false } func (option *Option) isFunc() bool { return option.value.Type().Kind() == reflect.Func } func (option *Option) call(value *string) error { var retval []reflect.Value if value == nil { retval = option.value.Call(nil) } else { tp := option.value.Type().In(0) val := reflect.New(tp) val = reflect.Indirect(val) if err := convert(*value, val, option.tag); err != nil { return err } retval = option.value.Call([]reflect.Value{val}) } if len(retval) == 1 && retval[0].Type() == reflect.TypeOf((*error)(nil)).Elem() { if retval[0].Interface() == nil { return nil } return retval[0].Interface().(error) } return nil } golang-go-flags-0.0~git20131216/options_test.go000066400000000000000000000015401224570357400211310ustar00rootroot00000000000000package flags_test import ( "github.com/jessevdk/go-flags" "testing" ) func TestPassDoubleDash(t *testing.T) { var opts = struct { Value bool `short:"v"` }{} p := flags.NewParser(&opts, flags.PassDoubleDash) ret, err := p.ParseArgs([]string{"-v", "--", "-v", "-g"}) if err != nil { t.Fatalf("Unexpected error: %v", err) return } if !opts.Value { t.Errorf("Expected Value to be true") } assertStringArray(t, ret, []string{"-v", "-g"}) } func TestPassAfterNonOption(t *testing.T) { var opts = struct { Value bool `short:"v"` }{} p := flags.NewParser(&opts, flags.PassAfterNonOption) ret, err := p.ParseArgs([]string{"-v", "arg", "-v", "-g"}) if err != nil { t.Fatalf("Unexpected error: %v", err) return } if !opts.Value { t.Errorf("Expected Value to be true") } assertStringArray(t, ret, []string{"arg", "-v", "-g"}) } golang-go-flags-0.0~git20131216/optstyle_other.go000066400000000000000000000025231224570357400214650ustar00rootroot00000000000000// +build !windows package flags import ( "strings" ) const ( defaultShortOptDelimiter = '-' defaultLongOptDelimiter = "--" defaultNameArgDelimiter = '=' ) func argumentIsOption(arg string) bool { return len(arg) > 0 && arg[0] == '-' } // stripOptionPrefix returns the option without the prefix and whether or // not the option is a long option or not. func stripOptionPrefix(optname string) (prefix string, name string, islong bool) { if strings.HasPrefix(optname, "--") { return "--", optname[2:], true } else if strings.HasPrefix(optname, "-") { return "-", optname[1:], false } return "", optname, false } // splitOption attempts to split the passed option into a name and an argument. // When there is no argument specified, nil will be returned for it. func splitOption(prefix string, option string, islong bool) (string, *string) { pos := strings.Index(option, "=") if (islong && pos >= 0) || (!islong && pos == 1) { rest := option[pos+1:] return option[:pos], &rest } return option, nil } // addHelpGroup adds a new group that contains default help parameters. func (c *Command) addHelpGroup(showHelp func() error) *Group { var help struct { ShowHelp func() error `short:"h" long:"help" description:"Show this help message"` } help.ShowHelp = showHelp ret, _ := c.AddGroup("Help Options", "", &help) return ret } golang-go-flags-0.0~git20131216/optstyle_windows.go000066400000000000000000000050061224570357400220350ustar00rootroot00000000000000package flags import ( "strings" ) // Windows uses a front slash for both short and long options. Also it uses // a colon for name/argument delimter. const ( defaultShortOptDelimiter = '/' defaultLongOptDelimiter = "/" defaultNameArgDelimiter = ':' ) func argumentIsOption(arg string) bool { // Windows-style options allow front slash for the option // delimiter. return len(arg) > 0 && (arg[0] == '-' || arg[0] == '/') } // stripOptionPrefix returns the option without the prefix and whether or // not the option is a long option or not. func stripOptionPrefix(optname string) (prefix string, name string, islong bool) { // Determine if the argument is a long option or not. Windows // typically supports both long and short options with a single // front slash as the option delimiter, so handle this situation // nicely. possplit := 0 if strings.HasPrefix(optname, "--") { possplit = 2 islong = true } else if strings.HasPrefix(optname, "-") { possplit = 1 islong = false } else if strings.HasPrefix(optname, "/") { possplit = 1 islong = len(optname) > 2 } return optname[:possplit], optname[possplit:], islong } // splitOption attempts to split the passed option into a name and an argument. // When there is no argument specified, nil will be returned for it. func splitOption(prefix string, option string, islong bool) (string, *string) { if len(option) == 0 { return option, nil } // Windows typically uses a colon for the option name and argument // delimiter while POSIX typically uses an equals. Support both styles, // but don't allow the two to be mixed. That is to say /foo:bar and // --foo=bar are acceptable, but /foo=bar and --foo:bar are not. var pos int if prefix == "/" { pos = strings.Index(option, ":") } else if len(prefix) > 0 { pos = strings.Index(option, "=") } if (islong && pos >= 0) || (!islong && pos == 1) { rest := option[pos+1:] return option[:pos], &rest } return option, nil } // addHelpGroup adds a new group that contains default help parameters. func (c *Command) addHelpGroup(showHelp func() error) *Group { // Windows CLI applications typically use /? for help, so make both // that available as well as the POSIX style h and help. var help struct { ShowHelpWindows func() error `short:"?" description:"Show this help message"` ShowHelpPosix func() error `short:"h" long:"help" description:"Show this help message"` } help.ShowHelpWindows = showHelp help.ShowHelpPosix = showHelp ret, _ := c.AddGroup("Help Options", "", &help) return ret } golang-go-flags-0.0~git20131216/parser.go000066400000000000000000000135101224570357400176730ustar00rootroot00000000000000// Copyright 2012 Jesse van den Kieboom. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package flags import ( "os" "path" ) // A Parser provides command line option parsing. It can contain several // option groups each with their own set of options. type Parser struct { *Command Usage string Options Options internalError error } // Parser options type Options uint const ( // No options None Options = 0 // Add a default Help Options group to the parser containing -h and // --help options. When either -h or --help is specified on the command // line, a pretty formatted help message will be printed to os.Stderr. // The parser will return ErrHelp. HelpFlag = 1 << iota // Pass all arguments after a double dash, --, as remaining command line // arguments (i.e. they will not be parsed for flags) PassDoubleDash // Ignore any unknown options and pass them as remaining command line // arguments IgnoreUnknown // Print any errors which occured during parsing to os.Stderr PrintErrors // Pass all arguments after the first non option. This is equivalent // to strict POSIX processing PassAfterNonOption // A convenient default set of options Default = HelpFlag | PrintErrors | PassDoubleDash ) // Parse is a convenience function to parse command line options with default // settings. The provided data is a pointer to a struct representing the // default option group (named "Application Options"). For more control, use // flags.NewParser. func Parse(data interface{}) ([]string, error) { return NewParser(data, Default).Parse() } // ParseArgs is a convenience function to parse command line options with default // settings. The provided data is a pointer to a struct representing the // default option group (named "Application Options"). The args argument is // the list of command line arguments to parse. If you just want to parse the // default program command line arguments (i.e. os.Args), then use flags.Parse // instead. For more control, use flags.NewParser. func ParseArgs(data interface{}, args []string) ([]string, error) { return NewParser(data, Default).ParseArgs(args) } // NewParser creates a new parser. It uses os.Args[0] as the application // name and then calls Parser.NewNamedParser (see Parser.NewNamedParser for // more details). The provided data is a pointer to a struct representing the // default option group (named "Application Options"), or nil if the default // group should not be added. The options parameter specifies a set of options // for the parser. func NewParser(data interface{}, options Options) *Parser { ret := NewNamedParser(path.Base(os.Args[0]), options) if data != nil { _, ret.internalError = ret.AddGroup("Application Options", "", data) } return ret } // NewNamedParser creates a new parser. The appname is used to display the // executable name in the builtin help message. Option groups and commands can // be added to this parser by using AddGroup and AddCommand. func NewNamedParser(appname string, options Options) *Parser { return &Parser{ Command: newCommand(appname, "", "", nil), Options: options, } } // Parse parses the command line arguments from os.Args using Parser.ParseArgs. // For more detailed information see ParseArgs. func (p *Parser) Parse() ([]string, error) { return p.ParseArgs(os.Args[1:]) } // ParseArgs parses the command line arguments according to the option groups that // were added to the parser. On successful parsing of the arguments, the // remaining, non-option, arguments (if any) are returned. The returned error // indicates a parsing error and can be used with PrintError to display // contextual information on where the error occurred exactly. // // When the common help group has been added (AddHelp) and either -h or --help // was specified in the command line arguments, a help message will be // automatically printed. Furthermore, the special error type ErrHelp is returned. // It is up to the caller to exit the program if so desired. func (p *Parser) ParseArgs(args []string) ([]string, error) { if p.internalError != nil { return nil, p.internalError } p.eachCommand(func(c *Command) { p.eachGroup(func(g *Group) { g.storeDefaults() }) }, true) // Add builtin help group to all commands if necessary if (p.Options & HelpFlag) != None { p.addHelpGroups(p.showBuiltinHelp) } s := &parseState{ args: args, retargs: make([]string, 0, len(args)), command: p.Command, lookup: p.makeLookup(), } for !s.eof() { arg := s.pop() // When PassDoubleDash is set and we encounter a --, then // simply append all the rest as arguments and break out if (p.Options&PassDoubleDash) != None && arg == "--" { s.retargs = append(s.retargs, s.args...) break } if !argumentIsOption(arg) { // Note: this also sets s.err, so we can just check for // nil here and use s.err later if p.parseNonOption(s) != nil { break } continue } var err error var option *Option prefix, optname, islong := stripOptionPrefix(arg) optname, argument := splitOption(prefix, optname, islong) if islong { option, err = p.parseLong(s, optname, argument) } else { option, err = p.parseShort(s, optname, argument) } if err != nil { ignoreUnknown := (p.Options & IgnoreUnknown) != None parseErr := wrapError(err) if !(parseErr.Type == ErrUnknownFlag && ignoreUnknown) { s.err = parseErr break } if ignoreUnknown { s.retargs = append(s.retargs, arg) } } else { delete(s.lookup.required, option) } } if s.err == nil { s.checkRequired() } if s.err != nil { return nil, p.printError(s.err) } if len(s.command.commands) != 0 { return nil, p.printError(s.estimateCommand()) } else if cmd, ok := s.command.data.(Commander); ok { return nil, p.printError(cmd.Execute(s.retargs)) } return s.retargs, nil } golang-go-flags-0.0~git20131216/parser_private.go000066400000000000000000000126161224570357400214330ustar00rootroot00000000000000package flags import ( "bytes" "fmt" "os" "strings" "unicode/utf8" ) type parseState struct { arg string args []string retargs []string err error command *Command lookup lookup } func (p *parseState) eof() bool { return len(p.args) == 0 } func (p *parseState) pop() string { if p.eof() { return "" } p.arg = p.args[0] p.args = p.args[1:] return p.arg } func (p *parseState) peek() string { if p.eof() { return "" } return p.args[0] } func (p *parseState) checkRequired() error { required := p.lookup.required if len(required) == 0 { return nil } names := make([]string, 0, len(required)) for k, _ := range required { names = append(names, "`"+k.String()+"'") } var msg string if len(names) == 1 { msg = fmt.Sprintf("the required flag %s was not specified", names[0]) } else { msg = fmt.Sprintf("the required flags %s and %s were not specified", strings.Join(names[:len(names)-1], ", "), names[len(names)-1]) } p.err = newError(ErrRequired, msg) return p.err } func (p *parseState) estimateCommand() error { commands := p.command.sortedCommands() cmdnames := make([]string, len(commands)) for i, v := range commands { cmdnames[i] = v.Name } var msg string if len(p.retargs) != 0 { c, l := closestChoice(p.retargs[0], cmdnames) msg = fmt.Sprintf("Unknown command `%s'", p.retargs[0]) if float32(l)/float32(len(c)) < 0.5 { msg = fmt.Sprintf("%s, did you mean `%s'?", msg, c) } else if len(cmdnames) == 1 { msg = fmt.Sprintf("%s. You should use the %s command", msg, cmdnames[0]) } else { msg = fmt.Sprintf("%s. Please specify one command of: %s or %s", msg, strings.Join(cmdnames[:len(cmdnames)-1], ", "), cmdnames[len(cmdnames)-1]) } } else { if len(cmdnames) == 1 { msg = fmt.Sprintf("Please specify the %s command", cmdnames[0]) } else { msg = fmt.Sprintf("Please specify one command of: %s or %s", strings.Join(cmdnames[:len(cmdnames)-1], ", "), cmdnames[len(cmdnames)-1]) } } return newError(ErrRequired, msg) } func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg bool, argument *string) (retoption *Option, err error) { if !option.canArgument() { if argument != nil { msg := fmt.Sprintf("bool flag `%s' cannot have an argument", option) return option, newError(ErrNoArgumentForBool, msg) } err = option.set(nil) } else if argument != nil { err = option.set(argument) } else if canarg && !s.eof() { arg := s.pop() err = option.set(&arg) } else if option.OptionalArgument { option.clear() for _, v := range option.OptionalValue { err = option.set(&v) if err != nil { break } } } else { msg := fmt.Sprintf("expected argument for flag `%s'", option) err = newError(ErrExpectedArgument, msg) } if err != nil { if _, ok := err.(*Error); !ok { msg := fmt.Sprintf("invalid argument for flag `%s' (expected %s): %s", option, option.value.Type(), err.Error()) err = newError(ErrMarshal, msg) } } return option, err } func (p *Parser) parseLong(s *parseState, name string, argument *string) (option *Option, err error) { if option := s.lookup.longNames[name]; option != nil { // Only long options that are required can consume an argument // from the argument list canarg := !option.OptionalArgument return p.parseOption(s, name, option, canarg, argument) } return nil, newError(ErrUnknownFlag, fmt.Sprintf("unknown flag `%s'", name)) } func (p *Parser) splitShortConcatArg(s *parseState, optname string) (string, *string) { c, n := utf8.DecodeRuneInString(optname) if n == len(optname) { return optname, nil } first := string(c) if option := s.lookup.shortNames[first]; option != nil && option.canArgument() { arg := optname[n:] return first, &arg } return optname, nil } func (p *Parser) parseShort(s *parseState, optname string, argument *string) (option *Option, err error) { if argument == nil { optname, argument = p.splitShortConcatArg(s, optname) } for i, c := range optname { shortname := string(c) if option = s.lookup.shortNames[shortname]; option != nil { // Only the last short argument can consume an argument from // the arguments list, and only if it's non optional canarg := (i+utf8.RuneLen(c) == len(optname)) && !option.OptionalArgument if _, err := p.parseOption(s, shortname, option, canarg, argument); err != nil { return option, err } } else { return nil, newError(ErrUnknownFlag, fmt.Sprintf("unknown flag `%s'", shortname)) } // Only the first option can have a concatted argument, so just // clear argument here argument = nil } return option, nil } func (p *Parser) parseNonOption(s *parseState) error { if cmd := s.lookup.commands[s.arg]; cmd != nil { if err := s.checkRequired(); err != nil { return err } s.command.Active = cmd s.command = cmd s.lookup = cmd.makeLookup() } else if (p.Options & PassAfterNonOption) != None { // If PassAfterNonOption is set then all remaining arguments // are considered positional s.retargs = append(append(s.retargs, s.arg), s.args...) s.args = []string{} } else { s.retargs = append(s.retargs, s.arg) } return nil } func (p *Parser) showBuiltinHelp() error { var b bytes.Buffer p.WriteHelp(&b) return newError(ErrHelp, b.String()) } func (p *Parser) printError(err error) error { if err != nil && (p.Options&PrintErrors) != None { fmt.Fprintln(os.Stderr, err) } return err } golang-go-flags-0.0~git20131216/pointer_test.go000066400000000000000000000031461224570357400211220ustar00rootroot00000000000000package flags_test import ( "testing" ) func TestPointerBool(t *testing.T) { var opts = struct { Value *bool `short:"v"` }{} ret := assertParseSuccess(t, &opts, "-v") assertStringArray(t, ret, []string{}) if !*opts.Value { t.Errorf("Expected Value to be true") } } func TestPointerString(t *testing.T) { var opts = struct { Value *string `short:"v"` }{} ret := assertParseSuccess(t, &opts, "-v", "value") assertStringArray(t, ret, []string{}) assertString(t, *opts.Value, "value") } func TestPointerSlice(t *testing.T) { var opts = struct { Value *[]string `short:"v"` }{} ret := assertParseSuccess(t, &opts, "-v", "value1", "-v", "value2") assertStringArray(t, ret, []string{}) assertStringArray(t, *opts.Value, []string{"value1", "value2"}) } func TestPointerMap(t *testing.T) { var opts = struct { Value *map[string]int `short:"v"` }{} ret := assertParseSuccess(t, &opts, "-v", "k1:2", "-v", "k2:-5") assertStringArray(t, ret, []string{}) if v, ok := (*opts.Value)["k1"]; !ok { t.Errorf("Expected key \"k1\" to exist") } else if v != 2 { t.Errorf("Expected \"k1\" to be 2, but got %#v", v) } if v, ok := (*opts.Value)["k2"]; !ok { t.Errorf("Expected key \"k2\" to exist") } else if v != -5 { t.Errorf("Expected \"k2\" to be -5, but got %#v", v) } } type PointerGroup struct { Value bool `short:"v"` } func TestPointerGroup(t *testing.T) { var opts = struct { Group *PointerGroup `group:"Group Options"` }{} ret := assertParseSuccess(t, &opts, "-v") assertStringArray(t, ret, []string{}) if !opts.Group.Value { t.Errorf("Expected Group.Value to be true") } } golang-go-flags-0.0~git20131216/short_test.go000066400000000000000000000067561224570357400206130ustar00rootroot00000000000000package flags_test import ( "github.com/jessevdk/go-flags" "testing" ) func TestShort(t *testing.T) { var opts = struct { Value bool `short:"v"` }{} ret := assertParseSuccess(t, &opts, "-v") assertStringArray(t, ret, []string{}) if !opts.Value { t.Errorf("Expected Value to be true") } } func TestShortTooLong(t *testing.T) { var opts = struct { Value bool `short:"vv"` }{} assertParseFail(t, flags.ErrShortNameTooLong, "short names can only be 1 character long, not `vv'", &opts) } func TestShortRequired(t *testing.T) { var opts = struct { Value bool `short:"v" required:"true"` }{} assertParseFail(t, flags.ErrRequired, "the required flag `-v' was not specified", &opts) } func TestShortMultiConcat(t *testing.T) { var opts = struct { V bool `short:"v"` O bool `short:"o"` F bool `short:"f"` }{} ret := assertParseSuccess(t, &opts, "-vo", "-f") assertStringArray(t, ret, []string{}) if !opts.V { t.Errorf("Expected V to be true") } if !opts.O { t.Errorf("Expected O to be true") } if !opts.F { t.Errorf("Expected F to be true") } } func TestShortMultiSlice(t *testing.T) { var opts = struct { Values []bool `short:"v"` }{} ret := assertParseSuccess(t, &opts, "-v", "-v") assertStringArray(t, ret, []string{}) assertBoolArray(t, opts.Values, []bool{true, true}) } func TestShortMultiSliceConcat(t *testing.T) { var opts = struct { Values []bool `short:"v"` }{} ret := assertParseSuccess(t, &opts, "-vvv") assertStringArray(t, ret, []string{}) assertBoolArray(t, opts.Values, []bool{true, true, true}) } func TestShortWithEqualArg(t *testing.T) { var opts = struct { Value string `short:"v"` }{} ret := assertParseSuccess(t, &opts, "-v=value") assertStringArray(t, ret, []string{}) assertString(t, opts.Value, "value") } func TestShortWithArg(t *testing.T) { var opts = struct { Value string `short:"v"` }{} ret := assertParseSuccess(t, &opts, "-vvalue") assertStringArray(t, ret, []string{}) assertString(t, opts.Value, "value") } func TestShortArg(t *testing.T) { var opts = struct { Value string `short:"v"` }{} ret := assertParseSuccess(t, &opts, "-v", "value") assertStringArray(t, ret, []string{}) assertString(t, opts.Value, "value") } func TestShortMultiWithEqualArg(t *testing.T) { var opts = struct { F []bool `short:"f"` Value string `short:"v"` }{} assertParseFail(t, flags.ErrExpectedArgument, "expected argument for flag `-v'", &opts, "-ffv=value") } func TestShortMultiArg(t *testing.T) { var opts = struct { F []bool `short:"f"` Value string `short:"v"` }{} ret := assertParseSuccess(t, &opts, "-ffv", "value") assertStringArray(t, ret, []string{}) assertBoolArray(t, opts.F, []bool{true, true}) assertString(t, opts.Value, "value") } func TestShortMultiArgConcatFail(t *testing.T) { var opts = struct { F []bool `short:"f"` Value string `short:"v"` }{} assertParseFail(t, flags.ErrExpectedArgument, "expected argument for flag `-v'", &opts, "-ffvvalue") } func TestShortMultiArgConcat(t *testing.T) { var opts = struct { F []bool `short:"f"` Value string `short:"v"` }{} ret := assertParseSuccess(t, &opts, "-vff") assertStringArray(t, ret, []string{}) assertString(t, opts.Value, "ff") } func TestShortOptional(t *testing.T) { var opts = struct { F []bool `short:"f"` Value string `short:"v" optional:"yes" optional-value:"value"` }{} ret := assertParseSuccess(t, &opts, "-fv", "f") assertStringArray(t, ret, []string{"f"}) assertString(t, opts.Value, "value") } golang-go-flags-0.0~git20131216/termsize.go000066400000000000000000000005661224570357400202500ustar00rootroot00000000000000// +build !windows package flags import ( "syscall" "unsafe" ) type winsize struct { ws_row, ws_col uint16 ws_xpixel, ws_ypixel uint16 } func getTerminalColumns() int { ws := winsize{} if tIOCGWINSZ != 0 { syscall.Syscall(syscall.SYS_IOCTL, uintptr(0), uintptr(tIOCGWINSZ), uintptr(unsafe.Pointer(&ws))) return int(ws.ws_col) } return 80 } golang-go-flags-0.0~git20131216/termsize_linux.go000066400000000000000000000000771224570357400214640ustar00rootroot00000000000000// +build linux package flags const ( tIOCGWINSZ = 0x5413 ) golang-go-flags-0.0~git20131216/termsize_other.go000066400000000000000000000001351224570357400214410ustar00rootroot00000000000000// +build !darwin,!freebsd,!netbsd,!openbsd,!linux package flags const ( tIOCGWINSZ = 0 ) golang-go-flags-0.0~git20131216/termsize_unix.go000066400000000000000000000001331224570357400213010ustar00rootroot00000000000000// +build darwin freebsd netbsd openbsd package flags const ( tIOCGWINSZ = 0x40087468 ) golang-go-flags-0.0~git20131216/termsize_windows.go000066400000000000000000000000741224570357400220140ustar00rootroot00000000000000package flags func getTerminalColumns() int { return 80 } golang-go-flags-0.0~git20131216/unknown_test.go000066400000000000000000000020111224570357400211270ustar00rootroot00000000000000package flags_test import ( "github.com/jessevdk/go-flags" "testing" ) func TestUnknownFlags(t *testing.T) { var opts = struct { Verbose []bool `short:"v" long:"verbose" description:"Verbose output"` }{} args := []string{ "-f", } p := flags.NewParser(&opts, 0) args, err := p.ParseArgs(args) if err == nil { t.Fatal("Expected error for unknown argument") } } func TestIgnoreUnknownFlags(t *testing.T) { var opts = struct { Verbose []bool `short:"v" long:"verbose" description:"Verbose output"` }{} args := []string{ "hello", "world", "-v", "--foo=bar", "--verbose", "-f", } p := flags.NewParser(&opts, flags.IgnoreUnknown) args, err := p.ParseArgs(args) if err != nil { t.Fatal(err) } exargs := []string{ "hello", "world", "--foo=bar", "-f", } issame := (len(args) == len(exargs)) if issame { for i := 0; i < len(args); i++ { if args[i] != exargs[i] { issame = false break } } } if !issame { t.Fatalf("Expected %v but got %v", exargs, args) } }