mirror of
https://github.com/octoleo/syncthing.git
synced 2024-12-23 03:18:59 +00:00
213 lines
6.4 KiB
Go
213 lines
6.4 KiB
Go
|
// 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 {
|
||
|
// Embedded, see Command for more information
|
||
|
*Command
|
||
|
|
||
|
// A usage string to be displayed in the help message.
|
||
|
Usage string
|
||
|
|
||
|
// Option flags changing the behavior of the parser.
|
||
|
Options Options
|
||
|
|
||
|
internalError error
|
||
|
}
|
||
|
|
||
|
// Options provides parser options that change the behavior of the option
|
||
|
// parser.
|
||
|
type Options uint
|
||
|
|
||
|
const (
|
||
|
// None indicates no options.
|
||
|
None Options = 0
|
||
|
|
||
|
// HelpFlag adds a default Help Options group to the parser containing
|
||
|
// -h and --help options. When either -h or --help is specified on the
|
||
|
// command line, the parser will return the special error of type
|
||
|
// ErrHelp. When PrintErrors is also specified, then the help message
|
||
|
// will also be automatically printed to os.Stderr.
|
||
|
HelpFlag = 1 << iota
|
||
|
|
||
|
// PassDoubleDash passes all arguments after a double dash, --, as
|
||
|
// remaining command line arguments (i.e. they will not be parsed for
|
||
|
// flags).
|
||
|
PassDoubleDash
|
||
|
|
||
|
// IgnoreUnknown ignores any unknown options and passes them as
|
||
|
// remaining command line arguments instead of generating an error.
|
||
|
IgnoreUnknown
|
||
|
|
||
|
// PrintErrors prints any errors which occurred during parsing to
|
||
|
// os.Stderr.
|
||
|
PrintErrors
|
||
|
|
||
|
// PassAfterNonOption passes all arguments after the first non option
|
||
|
// as remaining command line arguments. This is equivalent to strict
|
||
|
// POSIX processing.
|
||
|
PassAfterNonOption
|
||
|
|
||
|
// Default is a convenient default set of options which should cover
|
||
|
// most of the uses of the flags package.
|
||
|
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
|
||
|
}
|