├── .gitignore ├── vendor ├── gopkg.in │ └── alecthomas │ │ └── kingpin.v2 │ │ ├── .travis.yml │ │ ├── guesswidth.go │ │ ├── guesswidth_unix.go │ │ ├── completions.go │ │ ├── envar.go │ │ ├── COPYING │ │ ├── actions.go │ │ ├── values.json │ │ ├── doc.go │ │ ├── global.go │ │ ├── args.go │ │ ├── model.go │ │ ├── parsers.go │ │ ├── usage.go │ │ ├── cmd.go │ │ ├── templates.go │ │ ├── flags.go │ │ ├── parser.go │ │ ├── values.go │ │ └── app.go └── github.com │ ├── ProtonMail │ └── go-autostart │ │ ├── quote.go │ │ ├── autostart.go │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── autostart_windows.go │ │ ├── README.md │ │ ├── autostart_windows.c │ │ ├── autostart_darwin.go │ │ └── autostart_xdg.go │ └── alecthomas │ ├── units │ ├── README.md │ ├── doc.go │ ├── si.go │ ├── COPYING │ ├── bytes.go │ └── util.go │ └── template │ ├── README.md │ ├── LICENSE │ ├── helper.go │ ├── template.go │ ├── parse │ ├── lex.go │ └── parse.go │ ├── doc.go │ └── funcs.go ├── Godeps ├── Readme └── Godeps.json ├── LICENSE ├── release.sh ├── main.go └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.tar.gz 2 | goautostart 3 | autostart 4 | autostart.exe 5 | goautostart.exe 6 | 7 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: go 3 | install: go get -t -v ./... 4 | go: 1.2 5 | -------------------------------------------------------------------------------- /Godeps/Readme: -------------------------------------------------------------------------------- 1 | This directory tree is generated automatically by godep. 2 | 3 | Please do not edit. 4 | 5 | See https://github.com/tools/godep for more information. 6 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/guesswidth.go: -------------------------------------------------------------------------------- 1 | // +build appengine !linux,!freebsd,!darwin,!dragonfly,!netbsd,!openbsd 2 | 3 | package kingpin 4 | 5 | import "io" 6 | 7 | func guessWidth(w io.Writer) int { 8 | return 80 9 | } 10 | -------------------------------------------------------------------------------- /vendor/github.com/ProtonMail/go-autostart/quote.go: -------------------------------------------------------------------------------- 1 | // +build !darwin 2 | 3 | package autostart 4 | 5 | import ( 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func quote(args []string) string { 11 | for i, v := range args { 12 | args[i] = strconv.Quote(v) 13 | } 14 | 15 | return strings.Join(args, " ") 16 | } 17 | -------------------------------------------------------------------------------- /vendor/github.com/alecthomas/units/README.md: -------------------------------------------------------------------------------- 1 | # Units - Helpful unit multipliers and functions for Go 2 | 3 | The goal of this package is to have functionality similar to the [time](http://golang.org/pkg/time/) package. 4 | 5 | It allows for code like this: 6 | 7 | ```go 8 | n, err := ParseBase2Bytes("1KB") 9 | // n == 1024 10 | n = units.Mebibyte * 512 11 | ``` 12 | -------------------------------------------------------------------------------- /vendor/github.com/ProtonMail/go-autostart/autostart.go: -------------------------------------------------------------------------------- 1 | package autostart 2 | 3 | // An application that will be started when the user logs in. 4 | type App struct { 5 | // Unique identifier for the app. 6 | Name string 7 | // The command to execute, followed by its arguments. 8 | Exec []string 9 | // The app name. 10 | DisplayName string 11 | // The app icon. 12 | Icon string 13 | } 14 | -------------------------------------------------------------------------------- /vendor/github.com/ProtonMail/go-autostart/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /vendor/github.com/alecthomas/units/doc.go: -------------------------------------------------------------------------------- 1 | // Package units provides helpful unit multipliers and functions for Go. 2 | // 3 | // The goal of this package is to have functionality similar to the time [1] package. 4 | // 5 | // 6 | // [1] http://golang.org/pkg/time/ 7 | // 8 | // It allows for code like this: 9 | // 10 | // n, err := ParseBase2Bytes("1KB") 11 | // // n == 1024 12 | // n = units.Mebibyte * 512 13 | package units 14 | -------------------------------------------------------------------------------- /vendor/github.com/alecthomas/template/README.md: -------------------------------------------------------------------------------- 1 | # Go's `text/template` package with newline elision 2 | 3 | This is a fork of Go 1.4's [text/template](http://golang.org/pkg/text/template/) package with one addition: a backslash immediately after a closing delimiter will delete all subsequent newlines until a non-newline. 4 | 5 | eg. 6 | 7 | ``` 8 | {{if true}}\ 9 | hello 10 | {{end}}\ 11 | ``` 12 | 13 | Will result in: 14 | 15 | ``` 16 | hello\n 17 | ``` 18 | 19 | Rather than: 20 | 21 | ``` 22 | \n 23 | hello\n 24 | \n 25 | ``` 26 | -------------------------------------------------------------------------------- /vendor/github.com/alecthomas/units/si.go: -------------------------------------------------------------------------------- 1 | package units 2 | 3 | // SI units. 4 | type SI int64 5 | 6 | // SI unit multiples. 7 | const ( 8 | Kilo SI = 1000 9 | Mega = Kilo * 1000 10 | Giga = Mega * 1000 11 | Tera = Giga * 1000 12 | Peta = Tera * 1000 13 | Exa = Peta * 1000 14 | ) 15 | 16 | func MakeUnitMap(suffix, shortSuffix string, scale int64) map[string]float64 { 17 | return map[string]float64{ 18 | shortSuffix: 1, 19 | "K" + suffix: float64(scale), 20 | "M" + suffix: float64(scale * scale), 21 | "G" + suffix: float64(scale * scale * scale), 22 | "T" + suffix: float64(scale * scale * scale * scale), 23 | "P" + suffix: float64(scale * scale * scale * scale * scale), 24 | "E" + suffix: float64(scale * scale * scale * scale * scale * scale), 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Godeps/Godeps.json: -------------------------------------------------------------------------------- 1 | { 2 | "ImportPath": "s/goautostart", 3 | "GoVersion": "go1.8", 4 | "GodepVersion": "v80", 5 | "Packages": [ 6 | "./" 7 | ], 8 | "Deps": [ 9 | { 10 | "ImportPath": "github.com/ProtonMail/go-autostart", 11 | "Rev": "a27297c0e822b9a0f77e8c6d37ee771b97ae9177" 12 | }, 13 | { 14 | "ImportPath": "github.com/alecthomas/template", 15 | "Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c" 16 | }, 17 | { 18 | "ImportPath": "github.com/alecthomas/template/parse", 19 | "Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c" 20 | }, 21 | { 22 | "ImportPath": "github.com/alecthomas/units", 23 | "Rev": "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a" 24 | }, 25 | { 26 | "ImportPath": "gopkg.in/alecthomas/kingpin.v2", 27 | "Comment": "v2.2.6", 28 | "Rev": "947dcec5ba9c011838740e680966fd7087a71d0d" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/guesswidth_unix.go: -------------------------------------------------------------------------------- 1 | // +build !appengine,linux freebsd darwin dragonfly netbsd openbsd 2 | 3 | package kingpin 4 | 5 | import ( 6 | "io" 7 | "os" 8 | "strconv" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | func guessWidth(w io.Writer) int { 14 | // check if COLUMNS env is set to comply with 15 | // http://pubs.opengroup.org/onlinepubs/009604499/basedefs/xbd_chap08.html 16 | colsStr := os.Getenv("COLUMNS") 17 | if colsStr != "" { 18 | if cols, err := strconv.Atoi(colsStr); err == nil { 19 | return cols 20 | } 21 | } 22 | 23 | if t, ok := w.(*os.File); ok { 24 | fd := t.Fd() 25 | var dimensions [4]uint16 26 | 27 | if _, _, err := syscall.Syscall6( 28 | syscall.SYS_IOCTL, 29 | uintptr(fd), 30 | uintptr(syscall.TIOCGWINSZ), 31 | uintptr(unsafe.Pointer(&dimensions)), 32 | 0, 0, 0, 33 | ); err == 0 { 34 | return int(dimensions[1]) 35 | } 36 | } 37 | return 80 38 | } 39 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/completions.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | // HintAction is a function type who is expected to return a slice of possible 4 | // command line arguments. 5 | type HintAction func() []string 6 | type completionsMixin struct { 7 | hintActions []HintAction 8 | builtinHintActions []HintAction 9 | } 10 | 11 | func (a *completionsMixin) addHintAction(action HintAction) { 12 | a.hintActions = append(a.hintActions, action) 13 | } 14 | 15 | // Allow adding of HintActions which are added internally, ie, EnumVar 16 | func (a *completionsMixin) addHintActionBuiltin(action HintAction) { 17 | a.builtinHintActions = append(a.builtinHintActions, action) 18 | } 19 | 20 | func (a *completionsMixin) resolveCompletions() []string { 21 | var hints []string 22 | 23 | options := a.builtinHintActions 24 | if len(a.hintActions) > 0 { 25 | // User specified their own hintActions. Use those instead. 26 | options = a.hintActions 27 | } 28 | 29 | for _, hintAction := range options { 30 | hints = append(hints, hintAction()...) 31 | } 32 | return hints 33 | } 34 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/envar.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "os" 5 | "regexp" 6 | ) 7 | 8 | var ( 9 | envVarValuesSeparator = "\r?\n" 10 | envVarValuesTrimmer = regexp.MustCompile(envVarValuesSeparator + "$") 11 | envVarValuesSplitter = regexp.MustCompile(envVarValuesSeparator) 12 | ) 13 | 14 | type envarMixin struct { 15 | envar string 16 | noEnvar bool 17 | } 18 | 19 | func (e *envarMixin) HasEnvarValue() bool { 20 | return e.GetEnvarValue() != "" 21 | } 22 | 23 | func (e *envarMixin) GetEnvarValue() string { 24 | if e.noEnvar || e.envar == "" { 25 | return "" 26 | } 27 | return os.Getenv(e.envar) 28 | } 29 | 30 | func (e *envarMixin) GetSplitEnvarValue() []string { 31 | values := make([]string, 0) 32 | 33 | envarValue := e.GetEnvarValue() 34 | if envarValue == "" { 35 | return values 36 | } 37 | 38 | // Split by new line to extract multiple values, if any. 39 | trimmed := envVarValuesTrimmer.ReplaceAllString(envarValue, "") 40 | for _, value := range envVarValuesSplitter.Split(trimmed, -1) { 41 | values = append(values, value) 42 | } 43 | 44 | return values 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/alecthomas/units/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014 Alec Thomas 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014 Alec Thomas 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -rf autostart goautostart autostart.exe goautostart.exe *.tar.gz 3 | 4 | #linux 5 | CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -o autostart -ldflags "-s -w" && tar zcfv "autostart-linux-386.tar.gz" autostart 6 | rm -rf autostart 7 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o autostart -ldflags "-s -w" && tar zcfv "autostart-linux-amd64.tar.gz" autostart 8 | rm -rf autostart 9 | #darwin 10 | CGO_ENABLED=0 GOOS=darwin GOARCH=386 go build -o autostart -ldflags "-s -w" && tar zcfv "autostart-darwin-386.tar.gz" autostart 11 | rm -rf autostart 12 | CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o autostart -ldflags "-s -w" && tar zcfv "autostart-darwin-amd64.tar.gz" autostart 13 | rm -rf autostart 14 | #windows 15 | #apt-get install gcc-multilib 16 | #apt-get install gcc-mingw-w64 17 | CC=i686-w64-mingw32-gcc-win32 CGO_ENABLED=1 GOOS=windows GOARCH=386 go build -o autostart.exe && tar zcfv "autostart-windows-386.tar.gz" autostart.exe 18 | rm -rf autostart.exe 19 | CC=x86_64-w64-mingw32-gcc CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -o autostart.exe && tar zcfv "autostart-windows-amd64.tar.gz" autostart.exe 20 | rm -rf autostart.exe -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/actions.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | // Action callback executed at various stages after all values are populated. 4 | // The application, commands, arguments and flags all have corresponding 5 | // actions. 6 | type Action func(*ParseContext) error 7 | 8 | type actionMixin struct { 9 | actions []Action 10 | preActions []Action 11 | } 12 | 13 | type actionApplier interface { 14 | applyActions(*ParseContext) error 15 | applyPreActions(*ParseContext) error 16 | } 17 | 18 | func (a *actionMixin) addAction(action Action) { 19 | a.actions = append(a.actions, action) 20 | } 21 | 22 | func (a *actionMixin) addPreAction(action Action) { 23 | a.preActions = append(a.preActions, action) 24 | } 25 | 26 | func (a *actionMixin) applyActions(context *ParseContext) error { 27 | for _, action := range a.actions { 28 | if err := action(context); err != nil { 29 | return err 30 | } 31 | } 32 | return nil 33 | } 34 | 35 | func (a *actionMixin) applyPreActions(context *ParseContext) error { 36 | for _, preAction := range a.preActions { 37 | if err := preAction(context); err != nil { 38 | return err 39 | } 40 | } 41 | return nil 42 | } 43 | -------------------------------------------------------------------------------- /vendor/github.com/ProtonMail/go-autostart/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 ProtonMail 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/ProtonMail/go-autostart/autostart_windows.go: -------------------------------------------------------------------------------- 1 | package autostart 2 | 3 | // #cgo LDFLAGS: -lole32 -luuid 4 | /* 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | #include 8 | 9 | uint64_t CreateShortcut(char *shortcutA, char *path, char *args); 10 | */ 11 | import "C" 12 | 13 | import ( 14 | "errors" 15 | "fmt" 16 | "os" 17 | "path/filepath" 18 | "strings" 19 | ) 20 | 21 | var startupDir string 22 | 23 | func init() { 24 | startupDir = filepath.Join(os.Getenv("USERPROFILE"), "AppData", "Roaming", "Microsoft", "Windows", "Start Menu", "Programs", "Startup") 25 | } 26 | 27 | func (a *App) path() string { 28 | return filepath.Join(startupDir, a.Name+".lnk") 29 | } 30 | 31 | func (a *App) IsEnabled() bool { 32 | _, err := os.Stat(a.path()) 33 | return err == nil 34 | } 35 | 36 | func (a *App) Enable() error { 37 | path := a.Exec[0] 38 | args := strings.Join(a.Exec[1:], " ") 39 | 40 | if err := os.MkdirAll(startupDir, 0777); err != nil { 41 | return err 42 | } 43 | res := C.CreateShortcut(C.CString(a.path()), C.CString(path), C.CString(args)) 44 | if res != 0 { 45 | return errors.New(fmt.Sprintf("autostart: cannot create shortcut '%s' error code: 0x%.8x", a.path(), res)) 46 | } 47 | return nil 48 | } 49 | 50 | func (a *App) Disable() error { 51 | return os.Remove(a.path()) 52 | } 53 | -------------------------------------------------------------------------------- /vendor/github.com/ProtonMail/go-autostart/README.md: -------------------------------------------------------------------------------- 1 | # go-autostart 2 | 3 | [![GoDoc](https://godoc.org/github.com/ProtonMail/go-autostart?status.svg)](https://godoc.org/github.com/ProtonMail/go-autostart) 4 | 5 | A Go library to run a command after login. 6 | 7 | ## Usage 8 | 9 | ```go 10 | package main 11 | 12 | import ( 13 | "log" 14 | "github.com/ProtonMail/go-autostart" 15 | ) 16 | 17 | func main() { 18 | app := &autostart.App{ 19 | Name: "test", 20 | DisplayName: "Just a Test App", 21 | Exec: []string{"bash", "-c", "echo autostart >> ~/autostart.txt"}, 22 | } 23 | 24 | if app.IsEnabled() { 25 | log.Println("App is already enabled, removing it...") 26 | 27 | if err := app.Disable(); err != nil { 28 | log.Fatal(err) 29 | } 30 | } else { 31 | log.Println("Enabling app...") 32 | 33 | if err := app.Enable(); err != nil { 34 | log.Fatal(err) 35 | } 36 | } 37 | 38 | log.Println("Done!") 39 | } 40 | ``` 41 | 42 | ## Behavior 43 | 44 | * On Linux and BSD, it creates a `.desktop` file in `$XDG_CONFIG_HOME/autostart` 45 | (i.e. `$HOME/.config/autostart`). See http://askubuntu.com/questions/48321/how-do-i-start-applications-automatically-on-login 46 | * On macOS, it creates a `launchd` job. See http://blog.gordn.org/2015/03/implementing-run-on-login-for-your-node.html 47 | * On Windows, it creates a link to the program in `%USERPROFILE%\Start Menu\Programs\Startup` 48 | 49 | ## License 50 | 51 | MIT 52 | -------------------------------------------------------------------------------- /vendor/github.com/ProtonMail/go-autostart/autostart_windows.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | uint64_t CreateShortcut(char *shortcutA, char *path, char *args) { 10 | IShellLink* pISL; 11 | IPersistFile* pIPF; 12 | HRESULT hr; 13 | 14 | CoInitializeEx(NULL, COINIT_MULTITHREADED); 15 | 16 | // Shortcut filename: convert ANSI to unicode 17 | WORD shortcutW[MAX_PATH]; 18 | int nChar = MultiByteToWideChar(CP_ACP, 0, shortcutA, -1, shortcutW, MAX_PATH); 19 | 20 | hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, (LPVOID*)&pISL); 21 | if (!SUCCEEDED(hr)) { 22 | return hr+0x01000000; 23 | } 24 | 25 | // See https://msdn.microsoft.com/en-us/library/windows/desktop/bb774950(v=vs.85).aspx 26 | hr = pISL->lpVtbl->SetPath(pISL, path); 27 | if (!SUCCEEDED(hr)) { 28 | return hr+0x02000000; 29 | } 30 | 31 | hr = pISL->lpVtbl->SetArguments(pISL, args); 32 | if (!SUCCEEDED(hr)) { 33 | return hr+0x03000000; 34 | } 35 | 36 | // Save the shortcut 37 | hr = pISL->lpVtbl->QueryInterface(pISL, &IID_IPersistFile, (void**)&pIPF); 38 | if (!SUCCEEDED(hr)) { 39 | return hr+0x04000000; 40 | } 41 | 42 | hr = pIPF->lpVtbl->Save(pIPF, shortcutW, FALSE); 43 | if (!SUCCEEDED(hr)) { 44 | return hr+0x05000000; 45 | } 46 | 47 | pIPF->lpVtbl->Release(pIPF); 48 | pISL->lpVtbl->Release(pISL); 49 | 50 | return 0x0; 51 | } 52 | -------------------------------------------------------------------------------- /vendor/github.com/alecthomas/template/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/ProtonMail/go-autostart/autostart_darwin.go: -------------------------------------------------------------------------------- 1 | package autostart 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | "text/template" 7 | ) 8 | 9 | const jobTemplate = ` 10 | 11 | 12 | 13 | Label 14 | {{.Name}} 15 | ProgramArguments 16 | 17 | {{range .Exec -}} 18 | {{.}} 19 | {{end}} 20 | 21 | RunAtLoad 22 | 23 | 24 | ` 25 | 26 | var launchDir string 27 | 28 | func init() { 29 | launchDir = filepath.Join(os.Getenv("HOME"), "Library", "LaunchAgents") 30 | } 31 | 32 | func (a *App) path() string { 33 | return filepath.Join(launchDir, a.Name+".plist") 34 | } 35 | 36 | // IsEnabled Check is app enabled startup. 37 | func (a *App) IsEnabled() bool { 38 | _, err := os.Stat(a.path()) 39 | return err == nil 40 | } 41 | 42 | // Enable this app on startup. 43 | func (a *App) Enable() error { 44 | t := template.Must(template.New("job").Parse(jobTemplate)) 45 | 46 | if err := os.MkdirAll(launchDir, 0777); err != nil { 47 | return err 48 | } 49 | f, err := os.Create(a.path()) 50 | if err != nil { 51 | return err 52 | } 53 | defer f.Close() 54 | 55 | if err := t.Execute(f, a); err != nil { 56 | return err 57 | } 58 | 59 | return nil 60 | } 61 | 62 | // Disable this app on startup. 63 | func (a *App) Disable() error { 64 | 65 | return os.Remove(a.path()) 66 | } 67 | -------------------------------------------------------------------------------- /vendor/github.com/ProtonMail/go-autostart/autostart_xdg.go: -------------------------------------------------------------------------------- 1 | // +build !windows,!darwin 2 | 3 | package autostart 4 | 5 | import ( 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | "text/template" 10 | ) 11 | 12 | const desktopTemplate = `[Desktop Entry] 13 | Type=Application 14 | Name={{.DisplayName}} 15 | Exec={{.Exec}} 16 | {{- if .Icon}}Icon={{.Icon}}{{end}} 17 | X-GNOME-Autostart-enabled=true 18 | ` 19 | 20 | var autostartDir string 21 | 22 | func init() { 23 | if os.Getenv("XDG_CONFIG_HOME") != "" { 24 | autostartDir = os.Getenv("XDG_CONFIG_HOME") 25 | } else { 26 | autostartDir = filepath.Join(os.Getenv("HOME"), ".config") 27 | } 28 | autostartDir = filepath.Join(autostartDir, "autostart") 29 | } 30 | 31 | func (a *App) path() string { 32 | return filepath.Join(autostartDir, a.Name+".desktop") 33 | } 34 | 35 | // Check if the app is enabled on startup. 36 | func (a *App) IsEnabled() bool { 37 | _, err := os.Stat(a.path()) 38 | return err == nil 39 | } 40 | 41 | type app struct { 42 | *App 43 | } 44 | 45 | // Override App.Exec to return a string. 46 | func (a *app) Exec() string { 47 | return strings.Join(a.App.Exec, " ") 48 | } 49 | 50 | // Enable this app on startup. 51 | func (a *App) Enable() error { 52 | t := template.Must(template.New("desktop").Parse(desktopTemplate)) 53 | 54 | if err := os.MkdirAll(autostartDir, 0777); err != nil { 55 | return err 56 | } 57 | f, err := os.Create(a.path()) 58 | if err != nil { 59 | return err 60 | } 61 | defer f.Close() 62 | 63 | return t.Execute(f, &app{a}) 64 | } 65 | 66 | // Disable this app on startup. 67 | func (a *App) Disable() error { 68 | return os.Remove(a.path()) 69 | } 70 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "strings" 7 | 8 | "github.com/ProtonMail/go-autostart" 9 | kingpin "gopkg.in/alecthomas/kingpin.v2" 10 | ) 11 | 12 | const APP_VERSION = "1.0" 13 | 14 | func main() { 15 | app := kingpin.New("proxy", "happy with proxy") 16 | app.Author("snail").Version(APP_VERSION) 17 | nameKey := app.Flag("key", "Unique identifier for the application").Short('k').Default("").String() 18 | name := app.Flag("name", "The app name").Short('n').Default("").String() 19 | enable := app.Command("enable", "enable application auto startup") 20 | command := enable.Flag("command", "command of auto startup").Short('c').Default("").String() 21 | app.Command("disable", "disable application auto startup") 22 | cmd := kingpin.MustParse(app.Parse(os.Args[1:])) 23 | if strings.Trim(*nameKey, " ") == "" { 24 | app.Fatalf("namd key is required") 25 | return 26 | } 27 | if cmd == "enable" { 28 | if strings.Trim(*command, " ") == "" { 29 | app.Fatalf("command is required") 30 | return 31 | } 32 | } 33 | if *name == "" { 34 | *name = *nameKey 35 | } 36 | //log.Println(*command, strings.Fields(*command)) 37 | autostart := &autostart.App{ 38 | Name: *nameKey, 39 | DisplayName: *name, 40 | Exec: strings.Fields(*command), 41 | } 42 | 43 | if cmd == "enable" { 44 | if autostart.IsEnabled() { 45 | log.Println(*name + " is already enabled") 46 | return 47 | } 48 | log.Println("Enabling app...") 49 | if err := autostart.Enable(); err != nil { 50 | log.Fatal(err) 51 | } 52 | } else { 53 | if err := autostart.Disable(); err != nil { 54 | log.Fatal(err) 55 | } 56 | } 57 | log.Println("Done!") 58 | } 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Autostart 2 | 3 | [![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/autostart/) [![license](https://img.shields.io/github/license/snail007/autostart.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/autostart/total.svg?style=plastic)](https://github.com/snail007/autostart/releases) [![download](https://img.shields.io/github/release/snail007/autostart.svg?style=plastic)](https://github.com/snail007/autostart/releases) 4 | 5 | autostart tools to set your application auto startup after desktop login,only for desktop version of linux , windows , mac. 6 | 7 | # Behavior 8 | On Linux and BSD, it creates a .desktop file in $XDG_CONFIG_HOME/autostart (i.e. $HOME/.config/autostart). See http://askubuntu.com/questions/48321/how-do-i-start-applications-automatically-on-login 9 | On macOS, it creates a launchd job. See http://blog.gordn.org/2015/03/implementing-run-on-login-for-your-node.html 10 | On Windows, it creates a link to the program in %USERPROFILE%\Start Menu\Programs\Startup 11 | 12 | # Usage 13 | On linux and mac , the command is autostart. 14 | On windows , the command is autostart.exe. 15 | 16 | ## 1.Enable Application autostart. 17 | ***linux&mac*** 18 | `autostart enable -k "demokey" -n "my demo application" -c "echo \"autostart\">~/autostart.txt"` 19 | help: 20 | `autostart enable --help` 21 | 22 | ***windows*** 23 | `autostart.exe enable -k test -n test -c "c:\\windows\explorer.exe c:"` 24 | help: 25 | `autostart.exe enable --help` 26 | 27 | ## 2.Disable Application autostart. 28 | ***linux&mac*** 29 | `autostart disable -k "demokey"` 30 | help: 31 | `autostart disable --help` 32 | 33 | ***windows*** 34 | `autostart.exe disable -k "test"` 35 | help: 36 | `autostart.exe disable --help` 37 | 38 | 39 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/values.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"type": "bool", "parser": "strconv.ParseBool(s)"}, 3 | {"type": "string", "parser": "s, error(nil)", "format": "string(*f.v)", "plural": "Strings"}, 4 | {"type": "uint", "parser": "strconv.ParseUint(s, 0, 64)", "plural": "Uints"}, 5 | {"type": "uint8", "parser": "strconv.ParseUint(s, 0, 8)"}, 6 | {"type": "uint16", "parser": "strconv.ParseUint(s, 0, 16)"}, 7 | {"type": "uint32", "parser": "strconv.ParseUint(s, 0, 32)"}, 8 | {"type": "uint64", "parser": "strconv.ParseUint(s, 0, 64)"}, 9 | {"type": "int", "parser": "strconv.ParseFloat(s, 64)", "plural": "Ints"}, 10 | {"type": "int8", "parser": "strconv.ParseInt(s, 0, 8)"}, 11 | {"type": "int16", "parser": "strconv.ParseInt(s, 0, 16)"}, 12 | {"type": "int32", "parser": "strconv.ParseInt(s, 0, 32)"}, 13 | {"type": "int64", "parser": "strconv.ParseInt(s, 0, 64)"}, 14 | {"type": "float64", "parser": "strconv.ParseFloat(s, 64)"}, 15 | {"type": "float32", "parser": "strconv.ParseFloat(s, 32)"}, 16 | {"name": "Duration", "type": "time.Duration", "no_value_parser": true}, 17 | {"name": "IP", "type": "net.IP", "no_value_parser": true}, 18 | {"name": "TCPAddr", "Type": "*net.TCPAddr", "plural": "TCPList", "no_value_parser": true}, 19 | {"name": "ExistingFile", "Type": "string", "plural": "ExistingFiles", "no_value_parser": true}, 20 | {"name": "ExistingDir", "Type": "string", "plural": "ExistingDirs", "no_value_parser": true}, 21 | {"name": "ExistingFileOrDir", "Type": "string", "plural": "ExistingFilesOrDirs", "no_value_parser": true}, 22 | {"name": "Regexp", "Type": "*regexp.Regexp", "parser": "regexp.Compile(s)"}, 23 | {"name": "ResolvedIP", "Type": "net.IP", "parser": "resolveHost(s)", "help": "Resolve a hostname or IP to an IP."}, 24 | {"name": "HexBytes", "Type": "[]byte", "parser": "hex.DecodeString(s)", "help": "Bytes as a hex string."} 25 | ] 26 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/doc.go: -------------------------------------------------------------------------------- 1 | // Package kingpin provides command line interfaces like this: 2 | // 3 | // $ chat 4 | // usage: chat [] [] [ ...] 5 | // 6 | // Flags: 7 | // --debug enable debug mode 8 | // --help Show help. 9 | // --server=127.0.0.1 server address 10 | // 11 | // Commands: 12 | // help 13 | // Show help for a command. 14 | // 15 | // post [] 16 | // Post a message to a channel. 17 | // 18 | // register 19 | // Register a new user. 20 | // 21 | // $ chat help post 22 | // usage: chat [] post [] [] 23 | // 24 | // Post a message to a channel. 25 | // 26 | // Flags: 27 | // --image=IMAGE image to post 28 | // 29 | // Args: 30 | // channel to post to 31 | // [] text to post 32 | // $ chat post --image=~/Downloads/owls.jpg pics 33 | // 34 | // From code like this: 35 | // 36 | // package main 37 | // 38 | // import "gopkg.in/alecthomas/kingpin.v2" 39 | // 40 | // var ( 41 | // debug = kingpin.Flag("debug", "enable debug mode").Default("false").Bool() 42 | // serverIP = kingpin.Flag("server", "server address").Default("127.0.0.1").IP() 43 | // 44 | // register = kingpin.Command("register", "Register a new user.") 45 | // registerNick = register.Arg("nick", "nickname for user").Required().String() 46 | // registerName = register.Arg("name", "name of user").Required().String() 47 | // 48 | // post = kingpin.Command("post", "Post a message to a channel.") 49 | // postImage = post.Flag("image", "image to post").ExistingFile() 50 | // postChannel = post.Arg("channel", "channel to post to").Required().String() 51 | // postText = post.Arg("text", "text to post").String() 52 | // ) 53 | // 54 | // func main() { 55 | // switch kingpin.Parse() { 56 | // // Register user 57 | // case "register": 58 | // println(*registerNick) 59 | // 60 | // // Post message 61 | // case "post": 62 | // if *postImage != nil { 63 | // } 64 | // if *postText != "" { 65 | // } 66 | // } 67 | // } 68 | package kingpin 69 | -------------------------------------------------------------------------------- /vendor/github.com/alecthomas/units/bytes.go: -------------------------------------------------------------------------------- 1 | package units 2 | 3 | // Base2Bytes is the old non-SI power-of-2 byte scale (1024 bytes in a kilobyte, 4 | // etc.). 5 | type Base2Bytes int64 6 | 7 | // Base-2 byte units. 8 | const ( 9 | Kibibyte Base2Bytes = 1024 10 | KiB = Kibibyte 11 | Mebibyte = Kibibyte * 1024 12 | MiB = Mebibyte 13 | Gibibyte = Mebibyte * 1024 14 | GiB = Gibibyte 15 | Tebibyte = Gibibyte * 1024 16 | TiB = Tebibyte 17 | Pebibyte = Tebibyte * 1024 18 | PiB = Pebibyte 19 | Exbibyte = Pebibyte * 1024 20 | EiB = Exbibyte 21 | ) 22 | 23 | var ( 24 | bytesUnitMap = MakeUnitMap("iB", "B", 1024) 25 | oldBytesUnitMap = MakeUnitMap("B", "B", 1024) 26 | ) 27 | 28 | // ParseBase2Bytes supports both iB and B in base-2 multipliers. That is, KB 29 | // and KiB are both 1024. 30 | func ParseBase2Bytes(s string) (Base2Bytes, error) { 31 | n, err := ParseUnit(s, bytesUnitMap) 32 | if err != nil { 33 | n, err = ParseUnit(s, oldBytesUnitMap) 34 | } 35 | return Base2Bytes(n), err 36 | } 37 | 38 | func (b Base2Bytes) String() string { 39 | return ToString(int64(b), 1024, "iB", "B") 40 | } 41 | 42 | var ( 43 | metricBytesUnitMap = MakeUnitMap("B", "B", 1000) 44 | ) 45 | 46 | // MetricBytes are SI byte units (1000 bytes in a kilobyte). 47 | type MetricBytes SI 48 | 49 | // SI base-10 byte units. 50 | const ( 51 | Kilobyte MetricBytes = 1000 52 | KB = Kilobyte 53 | Megabyte = Kilobyte * 1000 54 | MB = Megabyte 55 | Gigabyte = Megabyte * 1000 56 | GB = Gigabyte 57 | Terabyte = Gigabyte * 1000 58 | TB = Terabyte 59 | Petabyte = Terabyte * 1000 60 | PB = Petabyte 61 | Exabyte = Petabyte * 1000 62 | EB = Exabyte 63 | ) 64 | 65 | // ParseMetricBytes parses base-10 metric byte units. That is, KB is 1000 bytes. 66 | func ParseMetricBytes(s string) (MetricBytes, error) { 67 | n, err := ParseUnit(s, metricBytesUnitMap) 68 | return MetricBytes(n), err 69 | } 70 | 71 | func (m MetricBytes) String() string { 72 | return ToString(int64(m), 1000, "B", "B") 73 | } 74 | 75 | // ParseStrictBytes supports both iB and B suffixes for base 2 and metric, 76 | // respectively. That is, KiB represents 1024 and KB represents 1000. 77 | func ParseStrictBytes(s string) (int64, error) { 78 | n, err := ParseUnit(s, bytesUnitMap) 79 | if err != nil { 80 | n, err = ParseUnit(s, metricBytesUnitMap) 81 | } 82 | return int64(n), err 83 | } 84 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/global.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | ) 7 | 8 | var ( 9 | // CommandLine is the default Kingpin parser. 10 | CommandLine = New(filepath.Base(os.Args[0]), "") 11 | // Global help flag. Exposed for user customisation. 12 | HelpFlag = CommandLine.HelpFlag 13 | // Top-level help command. Exposed for user customisation. May be nil. 14 | HelpCommand = CommandLine.HelpCommand 15 | // Global version flag. Exposed for user customisation. May be nil. 16 | VersionFlag = CommandLine.VersionFlag 17 | ) 18 | 19 | // Command adds a new command to the default parser. 20 | func Command(name, help string) *CmdClause { 21 | return CommandLine.Command(name, help) 22 | } 23 | 24 | // Flag adds a new flag to the default parser. 25 | func Flag(name, help string) *FlagClause { 26 | return CommandLine.Flag(name, help) 27 | } 28 | 29 | // Arg adds a new argument to the top-level of the default parser. 30 | func Arg(name, help string) *ArgClause { 31 | return CommandLine.Arg(name, help) 32 | } 33 | 34 | // Parse and return the selected command. Will call the termination handler if 35 | // an error is encountered. 36 | func Parse() string { 37 | selected := MustParse(CommandLine.Parse(os.Args[1:])) 38 | if selected == "" && CommandLine.cmdGroup.have() { 39 | Usage() 40 | CommandLine.terminate(0) 41 | } 42 | return selected 43 | } 44 | 45 | // Errorf prints an error message to stderr. 46 | func Errorf(format string, args ...interface{}) { 47 | CommandLine.Errorf(format, args...) 48 | } 49 | 50 | // Fatalf prints an error message to stderr and exits. 51 | func Fatalf(format string, args ...interface{}) { 52 | CommandLine.Fatalf(format, args...) 53 | } 54 | 55 | // FatalIfError prints an error and exits if err is not nil. The error is printed 56 | // with the given prefix. 57 | func FatalIfError(err error, format string, args ...interface{}) { 58 | CommandLine.FatalIfError(err, format, args...) 59 | } 60 | 61 | // FatalUsage prints an error message followed by usage information, then 62 | // exits with a non-zero status. 63 | func FatalUsage(format string, args ...interface{}) { 64 | CommandLine.FatalUsage(format, args...) 65 | } 66 | 67 | // FatalUsageContext writes a printf formatted error message to stderr, then 68 | // usage information for the given ParseContext, before exiting. 69 | func FatalUsageContext(context *ParseContext, format string, args ...interface{}) { 70 | CommandLine.FatalUsageContext(context, format, args...) 71 | } 72 | 73 | // Usage prints usage to stderr. 74 | func Usage() { 75 | CommandLine.Usage(os.Args[1:]) 76 | } 77 | 78 | // Set global usage template to use (defaults to DefaultUsageTemplate). 79 | func UsageTemplate(template string) *Application { 80 | return CommandLine.UsageTemplate(template) 81 | } 82 | 83 | // MustParse can be used with app.Parse(args) to exit with an error if parsing fails. 84 | func MustParse(command string, err error) string { 85 | if err != nil { 86 | Fatalf("%s, try --help", err) 87 | } 88 | return command 89 | } 90 | 91 | // Version adds a flag for displaying the application version number. 92 | func Version(version string) *Application { 93 | return CommandLine.Version(version) 94 | } 95 | -------------------------------------------------------------------------------- /vendor/github.com/alecthomas/units/util.go: -------------------------------------------------------------------------------- 1 | package units 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | var ( 10 | siUnits = []string{"", "K", "M", "G", "T", "P", "E"} 11 | ) 12 | 13 | func ToString(n int64, scale int64, suffix, baseSuffix string) string { 14 | mn := len(siUnits) 15 | out := make([]string, mn) 16 | for i, m := range siUnits { 17 | if n%scale != 0 || i == 0 && n == 0 { 18 | s := suffix 19 | if i == 0 { 20 | s = baseSuffix 21 | } 22 | out[mn-1-i] = fmt.Sprintf("%d%s%s", n%scale, m, s) 23 | } 24 | n /= scale 25 | if n == 0 { 26 | break 27 | } 28 | } 29 | return strings.Join(out, "") 30 | } 31 | 32 | // Below code ripped straight from http://golang.org/src/pkg/time/format.go?s=33392:33438#L1123 33 | var errLeadingInt = errors.New("units: bad [0-9]*") // never printed 34 | 35 | // leadingInt consumes the leading [0-9]* from s. 36 | func leadingInt(s string) (x int64, rem string, err error) { 37 | i := 0 38 | for ; i < len(s); i++ { 39 | c := s[i] 40 | if c < '0' || c > '9' { 41 | break 42 | } 43 | if x >= (1<<63-10)/10 { 44 | // overflow 45 | return 0, "", errLeadingInt 46 | } 47 | x = x*10 + int64(c) - '0' 48 | } 49 | return x, s[i:], nil 50 | } 51 | 52 | func ParseUnit(s string, unitMap map[string]float64) (int64, error) { 53 | // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+ 54 | orig := s 55 | f := float64(0) 56 | neg := false 57 | 58 | // Consume [-+]? 59 | if s != "" { 60 | c := s[0] 61 | if c == '-' || c == '+' { 62 | neg = c == '-' 63 | s = s[1:] 64 | } 65 | } 66 | // Special case: if all that is left is "0", this is zero. 67 | if s == "0" { 68 | return 0, nil 69 | } 70 | if s == "" { 71 | return 0, errors.New("units: invalid " + orig) 72 | } 73 | for s != "" { 74 | g := float64(0) // this element of the sequence 75 | 76 | var x int64 77 | var err error 78 | 79 | // The next character must be [0-9.] 80 | if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) { 81 | return 0, errors.New("units: invalid " + orig) 82 | } 83 | // Consume [0-9]* 84 | pl := len(s) 85 | x, s, err = leadingInt(s) 86 | if err != nil { 87 | return 0, errors.New("units: invalid " + orig) 88 | } 89 | g = float64(x) 90 | pre := pl != len(s) // whether we consumed anything before a period 91 | 92 | // Consume (\.[0-9]*)? 93 | post := false 94 | if s != "" && s[0] == '.' { 95 | s = s[1:] 96 | pl := len(s) 97 | x, s, err = leadingInt(s) 98 | if err != nil { 99 | return 0, errors.New("units: invalid " + orig) 100 | } 101 | scale := 1.0 102 | for n := pl - len(s); n > 0; n-- { 103 | scale *= 10 104 | } 105 | g += float64(x) / scale 106 | post = pl != len(s) 107 | } 108 | if !pre && !post { 109 | // no digits (e.g. ".s" or "-.s") 110 | return 0, errors.New("units: invalid " + orig) 111 | } 112 | 113 | // Consume unit. 114 | i := 0 115 | for ; i < len(s); i++ { 116 | c := s[i] 117 | if c == '.' || ('0' <= c && c <= '9') { 118 | break 119 | } 120 | } 121 | u := s[:i] 122 | s = s[i:] 123 | unit, ok := unitMap[u] 124 | if !ok { 125 | return 0, errors.New("units: unknown unit " + u + " in " + orig) 126 | } 127 | 128 | f += g * unit 129 | } 130 | 131 | if neg { 132 | f = -f 133 | } 134 | if f < float64(-1<<63) || f > float64(1<<63-1) { 135 | return 0, errors.New("units: overflow parsing unit") 136 | } 137 | return int64(f), nil 138 | } 139 | -------------------------------------------------------------------------------- /vendor/github.com/alecthomas/template/helper.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Helper functions to make constructing templates easier. 6 | 7 | package template 8 | 9 | import ( 10 | "fmt" 11 | "io/ioutil" 12 | "path/filepath" 13 | ) 14 | 15 | // Functions and methods to parse templates. 16 | 17 | // Must is a helper that wraps a call to a function returning (*Template, error) 18 | // and panics if the error is non-nil. It is intended for use in variable 19 | // initializations such as 20 | // var t = template.Must(template.New("name").Parse("text")) 21 | func Must(t *Template, err error) *Template { 22 | if err != nil { 23 | panic(err) 24 | } 25 | return t 26 | } 27 | 28 | // ParseFiles creates a new Template and parses the template definitions from 29 | // the named files. The returned template's name will have the (base) name and 30 | // (parsed) contents of the first file. There must be at least one file. 31 | // If an error occurs, parsing stops and the returned *Template is nil. 32 | func ParseFiles(filenames ...string) (*Template, error) { 33 | return parseFiles(nil, filenames...) 34 | } 35 | 36 | // ParseFiles parses the named files and associates the resulting templates with 37 | // t. If an error occurs, parsing stops and the returned template is nil; 38 | // otherwise it is t. There must be at least one file. 39 | func (t *Template) ParseFiles(filenames ...string) (*Template, error) { 40 | return parseFiles(t, filenames...) 41 | } 42 | 43 | // parseFiles is the helper for the method and function. If the argument 44 | // template is nil, it is created from the first file. 45 | func parseFiles(t *Template, filenames ...string) (*Template, error) { 46 | if len(filenames) == 0 { 47 | // Not really a problem, but be consistent. 48 | return nil, fmt.Errorf("template: no files named in call to ParseFiles") 49 | } 50 | for _, filename := range filenames { 51 | b, err := ioutil.ReadFile(filename) 52 | if err != nil { 53 | return nil, err 54 | } 55 | s := string(b) 56 | name := filepath.Base(filename) 57 | // First template becomes return value if not already defined, 58 | // and we use that one for subsequent New calls to associate 59 | // all the templates together. Also, if this file has the same name 60 | // as t, this file becomes the contents of t, so 61 | // t, err := New(name).Funcs(xxx).ParseFiles(name) 62 | // works. Otherwise we create a new template associated with t. 63 | var tmpl *Template 64 | if t == nil { 65 | t = New(name) 66 | } 67 | if name == t.Name() { 68 | tmpl = t 69 | } else { 70 | tmpl = t.New(name) 71 | } 72 | _, err = tmpl.Parse(s) 73 | if err != nil { 74 | return nil, err 75 | } 76 | } 77 | return t, nil 78 | } 79 | 80 | // ParseGlob creates a new Template and parses the template definitions from the 81 | // files identified by the pattern, which must match at least one file. The 82 | // returned template will have the (base) name and (parsed) contents of the 83 | // first file matched by the pattern. ParseGlob is equivalent to calling 84 | // ParseFiles with the list of files matched by the pattern. 85 | func ParseGlob(pattern string) (*Template, error) { 86 | return parseGlob(nil, pattern) 87 | } 88 | 89 | // ParseGlob parses the template definitions in the files identified by the 90 | // pattern and associates the resulting templates with t. The pattern is 91 | // processed by filepath.Glob and must match at least one file. ParseGlob is 92 | // equivalent to calling t.ParseFiles with the list of files matched by the 93 | // pattern. 94 | func (t *Template) ParseGlob(pattern string) (*Template, error) { 95 | return parseGlob(t, pattern) 96 | } 97 | 98 | // parseGlob is the implementation of the function and method ParseGlob. 99 | func parseGlob(t *Template, pattern string) (*Template, error) { 100 | filenames, err := filepath.Glob(pattern) 101 | if err != nil { 102 | return nil, err 103 | } 104 | if len(filenames) == 0 { 105 | return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern) 106 | } 107 | return parseFiles(t, filenames...) 108 | } 109 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/args.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type argGroup struct { 8 | args []*ArgClause 9 | } 10 | 11 | func newArgGroup() *argGroup { 12 | return &argGroup{} 13 | } 14 | 15 | func (a *argGroup) have() bool { 16 | return len(a.args) > 0 17 | } 18 | 19 | // GetArg gets an argument definition. 20 | // 21 | // This allows existing arguments to be modified after definition but before parsing. Useful for 22 | // modular applications. 23 | func (a *argGroup) GetArg(name string) *ArgClause { 24 | for _, arg := range a.args { 25 | if arg.name == name { 26 | return arg 27 | } 28 | } 29 | return nil 30 | } 31 | 32 | func (a *argGroup) Arg(name, help string) *ArgClause { 33 | arg := newArg(name, help) 34 | a.args = append(a.args, arg) 35 | return arg 36 | } 37 | 38 | func (a *argGroup) init() error { 39 | required := 0 40 | seen := map[string]struct{}{} 41 | previousArgMustBeLast := false 42 | for i, arg := range a.args { 43 | if previousArgMustBeLast { 44 | return fmt.Errorf("Args() can't be followed by another argument '%s'", arg.name) 45 | } 46 | if arg.consumesRemainder() { 47 | previousArgMustBeLast = true 48 | } 49 | if _, ok := seen[arg.name]; ok { 50 | return fmt.Errorf("duplicate argument '%s'", arg.name) 51 | } 52 | seen[arg.name] = struct{}{} 53 | if arg.required && required != i { 54 | return fmt.Errorf("required arguments found after non-required") 55 | } 56 | if arg.required { 57 | required++ 58 | } 59 | if err := arg.init(); err != nil { 60 | return err 61 | } 62 | } 63 | return nil 64 | } 65 | 66 | type ArgClause struct { 67 | actionMixin 68 | parserMixin 69 | completionsMixin 70 | envarMixin 71 | name string 72 | help string 73 | defaultValues []string 74 | required bool 75 | } 76 | 77 | func newArg(name, help string) *ArgClause { 78 | a := &ArgClause{ 79 | name: name, 80 | help: help, 81 | } 82 | return a 83 | } 84 | 85 | func (a *ArgClause) setDefault() error { 86 | if a.HasEnvarValue() { 87 | if v, ok := a.value.(remainderArg); !ok || !v.IsCumulative() { 88 | // Use the value as-is 89 | return a.value.Set(a.GetEnvarValue()) 90 | } 91 | for _, value := range a.GetSplitEnvarValue() { 92 | if err := a.value.Set(value); err != nil { 93 | return err 94 | } 95 | } 96 | return nil 97 | } 98 | 99 | if len(a.defaultValues) > 0 { 100 | for _, defaultValue := range a.defaultValues { 101 | if err := a.value.Set(defaultValue); err != nil { 102 | return err 103 | } 104 | } 105 | return nil 106 | } 107 | 108 | return nil 109 | } 110 | 111 | func (a *ArgClause) needsValue() bool { 112 | haveDefault := len(a.defaultValues) > 0 113 | return a.required && !(haveDefault || a.HasEnvarValue()) 114 | } 115 | 116 | func (a *ArgClause) consumesRemainder() bool { 117 | if r, ok := a.value.(remainderArg); ok { 118 | return r.IsCumulative() 119 | } 120 | return false 121 | } 122 | 123 | // Required arguments must be input by the user. They can not have a Default() value provided. 124 | func (a *ArgClause) Required() *ArgClause { 125 | a.required = true 126 | return a 127 | } 128 | 129 | // Default values for this argument. They *must* be parseable by the value of the argument. 130 | func (a *ArgClause) Default(values ...string) *ArgClause { 131 | a.defaultValues = values 132 | return a 133 | } 134 | 135 | // Envar overrides the default value(s) for a flag from an environment variable, 136 | // if it is set. Several default values can be provided by using new lines to 137 | // separate them. 138 | func (a *ArgClause) Envar(name string) *ArgClause { 139 | a.envar = name 140 | a.noEnvar = false 141 | return a 142 | } 143 | 144 | // NoEnvar forces environment variable defaults to be disabled for this flag. 145 | // Most useful in conjunction with app.DefaultEnvars(). 146 | func (a *ArgClause) NoEnvar() *ArgClause { 147 | a.envar = "" 148 | a.noEnvar = true 149 | return a 150 | } 151 | 152 | func (a *ArgClause) Action(action Action) *ArgClause { 153 | a.addAction(action) 154 | return a 155 | } 156 | 157 | func (a *ArgClause) PreAction(action Action) *ArgClause { 158 | a.addPreAction(action) 159 | return a 160 | } 161 | 162 | // HintAction registers a HintAction (function) for the arg to provide completions 163 | func (a *ArgClause) HintAction(action HintAction) *ArgClause { 164 | a.addHintAction(action) 165 | return a 166 | } 167 | 168 | // HintOptions registers any number of options for the flag to provide completions 169 | func (a *ArgClause) HintOptions(options ...string) *ArgClause { 170 | a.addHintAction(func() []string { 171 | return options 172 | }) 173 | return a 174 | } 175 | 176 | func (a *ArgClause) init() error { 177 | if a.required && len(a.defaultValues) > 0 { 178 | return fmt.Errorf("required argument '%s' with unusable default value", a.name) 179 | } 180 | if a.value == nil { 181 | return fmt.Errorf("no parser defined for arg '%s'", a.name) 182 | } 183 | return nil 184 | } 185 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/model.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | // Data model for Kingpin command-line structure. 10 | 11 | type FlagGroupModel struct { 12 | Flags []*FlagModel 13 | } 14 | 15 | func (f *FlagGroupModel) FlagSummary() string { 16 | out := []string{} 17 | count := 0 18 | for _, flag := range f.Flags { 19 | if flag.Name != "help" { 20 | count++ 21 | } 22 | if flag.Required { 23 | if flag.IsBoolFlag() { 24 | out = append(out, fmt.Sprintf("--[no-]%s", flag.Name)) 25 | } else { 26 | out = append(out, fmt.Sprintf("--%s=%s", flag.Name, flag.FormatPlaceHolder())) 27 | } 28 | } 29 | } 30 | if count != len(out) { 31 | out = append(out, "[]") 32 | } 33 | return strings.Join(out, " ") 34 | } 35 | 36 | type FlagModel struct { 37 | Name string 38 | Help string 39 | Short rune 40 | Default []string 41 | Envar string 42 | PlaceHolder string 43 | Required bool 44 | Hidden bool 45 | Value Value 46 | } 47 | 48 | func (f *FlagModel) String() string { 49 | return f.Value.String() 50 | } 51 | 52 | func (f *FlagModel) IsBoolFlag() bool { 53 | if fl, ok := f.Value.(boolFlag); ok { 54 | return fl.IsBoolFlag() 55 | } 56 | return false 57 | } 58 | 59 | func (f *FlagModel) FormatPlaceHolder() string { 60 | if f.PlaceHolder != "" { 61 | return f.PlaceHolder 62 | } 63 | if len(f.Default) > 0 { 64 | ellipsis := "" 65 | if len(f.Default) > 1 { 66 | ellipsis = "..." 67 | } 68 | if _, ok := f.Value.(*stringValue); ok { 69 | return strconv.Quote(f.Default[0]) + ellipsis 70 | } 71 | return f.Default[0] + ellipsis 72 | } 73 | return strings.ToUpper(f.Name) 74 | } 75 | 76 | type ArgGroupModel struct { 77 | Args []*ArgModel 78 | } 79 | 80 | func (a *ArgGroupModel) ArgSummary() string { 81 | depth := 0 82 | out := []string{} 83 | for _, arg := range a.Args { 84 | h := "<" + arg.Name + ">" 85 | if !arg.Required { 86 | h = "[" + h 87 | depth++ 88 | } 89 | out = append(out, h) 90 | } 91 | out[len(out)-1] = out[len(out)-1] + strings.Repeat("]", depth) 92 | return strings.Join(out, " ") 93 | } 94 | 95 | type ArgModel struct { 96 | Name string 97 | Help string 98 | Default []string 99 | Envar string 100 | Required bool 101 | Value Value 102 | } 103 | 104 | func (a *ArgModel) String() string { 105 | return a.Value.String() 106 | } 107 | 108 | type CmdGroupModel struct { 109 | Commands []*CmdModel 110 | } 111 | 112 | func (c *CmdGroupModel) FlattenedCommands() (out []*CmdModel) { 113 | for _, cmd := range c.Commands { 114 | if len(cmd.Commands) == 0 { 115 | out = append(out, cmd) 116 | } 117 | out = append(out, cmd.FlattenedCommands()...) 118 | } 119 | return 120 | } 121 | 122 | type CmdModel struct { 123 | Name string 124 | Aliases []string 125 | Help string 126 | FullCommand string 127 | Depth int 128 | Hidden bool 129 | Default bool 130 | *FlagGroupModel 131 | *ArgGroupModel 132 | *CmdGroupModel 133 | } 134 | 135 | func (c *CmdModel) String() string { 136 | return c.FullCommand 137 | } 138 | 139 | type ApplicationModel struct { 140 | Name string 141 | Help string 142 | Version string 143 | Author string 144 | *ArgGroupModel 145 | *CmdGroupModel 146 | *FlagGroupModel 147 | } 148 | 149 | func (a *Application) Model() *ApplicationModel { 150 | return &ApplicationModel{ 151 | Name: a.Name, 152 | Help: a.Help, 153 | Version: a.version, 154 | Author: a.author, 155 | FlagGroupModel: a.flagGroup.Model(), 156 | ArgGroupModel: a.argGroup.Model(), 157 | CmdGroupModel: a.cmdGroup.Model(), 158 | } 159 | } 160 | 161 | func (a *argGroup) Model() *ArgGroupModel { 162 | m := &ArgGroupModel{} 163 | for _, arg := range a.args { 164 | m.Args = append(m.Args, arg.Model()) 165 | } 166 | return m 167 | } 168 | 169 | func (a *ArgClause) Model() *ArgModel { 170 | return &ArgModel{ 171 | Name: a.name, 172 | Help: a.help, 173 | Default: a.defaultValues, 174 | Envar: a.envar, 175 | Required: a.required, 176 | Value: a.value, 177 | } 178 | } 179 | 180 | func (f *flagGroup) Model() *FlagGroupModel { 181 | m := &FlagGroupModel{} 182 | for _, fl := range f.flagOrder { 183 | m.Flags = append(m.Flags, fl.Model()) 184 | } 185 | return m 186 | } 187 | 188 | func (f *FlagClause) Model() *FlagModel { 189 | return &FlagModel{ 190 | Name: f.name, 191 | Help: f.help, 192 | Short: rune(f.shorthand), 193 | Default: f.defaultValues, 194 | Envar: f.envar, 195 | PlaceHolder: f.placeholder, 196 | Required: f.required, 197 | Hidden: f.hidden, 198 | Value: f.value, 199 | } 200 | } 201 | 202 | func (c *cmdGroup) Model() *CmdGroupModel { 203 | m := &CmdGroupModel{} 204 | for _, cm := range c.commandOrder { 205 | m.Commands = append(m.Commands, cm.Model()) 206 | } 207 | return m 208 | } 209 | 210 | func (c *CmdClause) Model() *CmdModel { 211 | depth := 0 212 | for i := c; i != nil; i = i.parent { 213 | depth++ 214 | } 215 | return &CmdModel{ 216 | Name: c.name, 217 | Aliases: c.aliases, 218 | Help: c.help, 219 | Depth: depth, 220 | Hidden: c.hidden, 221 | Default: c.isDefault, 222 | FullCommand: c.FullCommand(), 223 | FlagGroupModel: c.flagGroup.Model(), 224 | ArgGroupModel: c.argGroup.Model(), 225 | CmdGroupModel: c.cmdGroup.Model(), 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/parsers.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "net" 5 | "net/url" 6 | "os" 7 | "time" 8 | 9 | "github.com/alecthomas/units" 10 | ) 11 | 12 | type Settings interface { 13 | SetValue(value Value) 14 | } 15 | 16 | type parserMixin struct { 17 | value Value 18 | required bool 19 | } 20 | 21 | func (p *parserMixin) SetValue(value Value) { 22 | p.value = value 23 | } 24 | 25 | // StringMap provides key=value parsing into a map. 26 | func (p *parserMixin) StringMap() (target *map[string]string) { 27 | target = &(map[string]string{}) 28 | p.StringMapVar(target) 29 | return 30 | } 31 | 32 | // Duration sets the parser to a time.Duration parser. 33 | func (p *parserMixin) Duration() (target *time.Duration) { 34 | target = new(time.Duration) 35 | p.DurationVar(target) 36 | return 37 | } 38 | 39 | // Bytes parses numeric byte units. eg. 1.5KB 40 | func (p *parserMixin) Bytes() (target *units.Base2Bytes) { 41 | target = new(units.Base2Bytes) 42 | p.BytesVar(target) 43 | return 44 | } 45 | 46 | // IP sets the parser to a net.IP parser. 47 | func (p *parserMixin) IP() (target *net.IP) { 48 | target = new(net.IP) 49 | p.IPVar(target) 50 | return 51 | } 52 | 53 | // TCP (host:port) address. 54 | func (p *parserMixin) TCP() (target **net.TCPAddr) { 55 | target = new(*net.TCPAddr) 56 | p.TCPVar(target) 57 | return 58 | } 59 | 60 | // TCPVar (host:port) address. 61 | func (p *parserMixin) TCPVar(target **net.TCPAddr) { 62 | p.SetValue(newTCPAddrValue(target)) 63 | } 64 | 65 | // ExistingFile sets the parser to one that requires and returns an existing file. 66 | func (p *parserMixin) ExistingFile() (target *string) { 67 | target = new(string) 68 | p.ExistingFileVar(target) 69 | return 70 | } 71 | 72 | // ExistingDir sets the parser to one that requires and returns an existing directory. 73 | func (p *parserMixin) ExistingDir() (target *string) { 74 | target = new(string) 75 | p.ExistingDirVar(target) 76 | return 77 | } 78 | 79 | // ExistingFileOrDir sets the parser to one that requires and returns an existing file OR directory. 80 | func (p *parserMixin) ExistingFileOrDir() (target *string) { 81 | target = new(string) 82 | p.ExistingFileOrDirVar(target) 83 | return 84 | } 85 | 86 | // File returns an os.File against an existing file. 87 | func (p *parserMixin) File() (target **os.File) { 88 | target = new(*os.File) 89 | p.FileVar(target) 90 | return 91 | } 92 | 93 | // File attempts to open a File with os.OpenFile(flag, perm). 94 | func (p *parserMixin) OpenFile(flag int, perm os.FileMode) (target **os.File) { 95 | target = new(*os.File) 96 | p.OpenFileVar(target, flag, perm) 97 | return 98 | } 99 | 100 | // URL provides a valid, parsed url.URL. 101 | func (p *parserMixin) URL() (target **url.URL) { 102 | target = new(*url.URL) 103 | p.URLVar(target) 104 | return 105 | } 106 | 107 | // StringMap provides key=value parsing into a map. 108 | func (p *parserMixin) StringMapVar(target *map[string]string) { 109 | p.SetValue(newStringMapValue(target)) 110 | } 111 | 112 | // Float sets the parser to a float64 parser. 113 | func (p *parserMixin) Float() (target *float64) { 114 | return p.Float64() 115 | } 116 | 117 | // Float sets the parser to a float64 parser. 118 | func (p *parserMixin) FloatVar(target *float64) { 119 | p.Float64Var(target) 120 | } 121 | 122 | // Duration sets the parser to a time.Duration parser. 123 | func (p *parserMixin) DurationVar(target *time.Duration) { 124 | p.SetValue(newDurationValue(target)) 125 | } 126 | 127 | // BytesVar parses numeric byte units. eg. 1.5KB 128 | func (p *parserMixin) BytesVar(target *units.Base2Bytes) { 129 | p.SetValue(newBytesValue(target)) 130 | } 131 | 132 | // IP sets the parser to a net.IP parser. 133 | func (p *parserMixin) IPVar(target *net.IP) { 134 | p.SetValue(newIPValue(target)) 135 | } 136 | 137 | // ExistingFile sets the parser to one that requires and returns an existing file. 138 | func (p *parserMixin) ExistingFileVar(target *string) { 139 | p.SetValue(newExistingFileValue(target)) 140 | } 141 | 142 | // ExistingDir sets the parser to one that requires and returns an existing directory. 143 | func (p *parserMixin) ExistingDirVar(target *string) { 144 | p.SetValue(newExistingDirValue(target)) 145 | } 146 | 147 | // ExistingDir sets the parser to one that requires and returns an existing directory. 148 | func (p *parserMixin) ExistingFileOrDirVar(target *string) { 149 | p.SetValue(newExistingFileOrDirValue(target)) 150 | } 151 | 152 | // FileVar opens an existing file. 153 | func (p *parserMixin) FileVar(target **os.File) { 154 | p.SetValue(newFileValue(target, os.O_RDONLY, 0)) 155 | } 156 | 157 | // OpenFileVar calls os.OpenFile(flag, perm) 158 | func (p *parserMixin) OpenFileVar(target **os.File, flag int, perm os.FileMode) { 159 | p.SetValue(newFileValue(target, flag, perm)) 160 | } 161 | 162 | // URL provides a valid, parsed url.URL. 163 | func (p *parserMixin) URLVar(target **url.URL) { 164 | p.SetValue(newURLValue(target)) 165 | } 166 | 167 | // URLList provides a parsed list of url.URL values. 168 | func (p *parserMixin) URLList() (target *[]*url.URL) { 169 | target = new([]*url.URL) 170 | p.URLListVar(target) 171 | return 172 | } 173 | 174 | // URLListVar provides a parsed list of url.URL values. 175 | func (p *parserMixin) URLListVar(target *[]*url.URL) { 176 | p.SetValue(newURLListValue(target)) 177 | } 178 | 179 | // Enum allows a value from a set of options. 180 | func (p *parserMixin) Enum(options ...string) (target *string) { 181 | target = new(string) 182 | p.EnumVar(target, options...) 183 | return 184 | } 185 | 186 | // EnumVar allows a value from a set of options. 187 | func (p *parserMixin) EnumVar(target *string, options ...string) { 188 | p.SetValue(newEnumFlag(target, options...)) 189 | } 190 | 191 | // Enums allows a set of values from a set of options. 192 | func (p *parserMixin) Enums(options ...string) (target *[]string) { 193 | target = new([]string) 194 | p.EnumsVar(target, options...) 195 | return 196 | } 197 | 198 | // EnumVar allows a value from a set of options. 199 | func (p *parserMixin) EnumsVar(target *[]string, options ...string) { 200 | p.SetValue(newEnumsFlag(target, options...)) 201 | } 202 | 203 | // A Counter increments a number each time it is encountered. 204 | func (p *parserMixin) Counter() (target *int) { 205 | target = new(int) 206 | p.CounterVar(target) 207 | return 208 | } 209 | 210 | func (p *parserMixin) CounterVar(target *int) { 211 | p.SetValue(newCounterValue(target)) 212 | } 213 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/usage.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "go/doc" 7 | "io" 8 | "strings" 9 | 10 | "github.com/alecthomas/template" 11 | ) 12 | 13 | var ( 14 | preIndent = " " 15 | ) 16 | 17 | func formatTwoColumns(w io.Writer, indent, padding, width int, rows [][2]string) { 18 | // Find size of first column. 19 | s := 0 20 | for _, row := range rows { 21 | if c := len(row[0]); c > s && c < 30 { 22 | s = c 23 | } 24 | } 25 | 26 | indentStr := strings.Repeat(" ", indent) 27 | offsetStr := strings.Repeat(" ", s+padding) 28 | 29 | for _, row := range rows { 30 | buf := bytes.NewBuffer(nil) 31 | doc.ToText(buf, row[1], "", preIndent, width-s-padding-indent) 32 | lines := strings.Split(strings.TrimRight(buf.String(), "\n"), "\n") 33 | fmt.Fprintf(w, "%s%-*s%*s", indentStr, s, row[0], padding, "") 34 | if len(row[0]) >= 30 { 35 | fmt.Fprintf(w, "\n%s%s", indentStr, offsetStr) 36 | } 37 | fmt.Fprintf(w, "%s\n", lines[0]) 38 | for _, line := range lines[1:] { 39 | fmt.Fprintf(w, "%s%s%s\n", indentStr, offsetStr, line) 40 | } 41 | } 42 | } 43 | 44 | // Usage writes application usage to w. It parses args to determine 45 | // appropriate help context, such as which command to show help for. 46 | func (a *Application) Usage(args []string) { 47 | context, err := a.parseContext(true, args) 48 | a.FatalIfError(err, "") 49 | if err := a.UsageForContextWithTemplate(context, 2, a.usageTemplate); err != nil { 50 | panic(err) 51 | } 52 | } 53 | 54 | func formatAppUsage(app *ApplicationModel) string { 55 | s := []string{app.Name} 56 | if len(app.Flags) > 0 { 57 | s = append(s, app.FlagSummary()) 58 | } 59 | if len(app.Args) > 0 { 60 | s = append(s, app.ArgSummary()) 61 | } 62 | return strings.Join(s, " ") 63 | } 64 | 65 | func formatCmdUsage(app *ApplicationModel, cmd *CmdModel) string { 66 | s := []string{app.Name, cmd.String()} 67 | if len(app.Flags) > 0 { 68 | s = append(s, app.FlagSummary()) 69 | } 70 | if len(app.Args) > 0 { 71 | s = append(s, app.ArgSummary()) 72 | } 73 | return strings.Join(s, " ") 74 | } 75 | 76 | func formatFlag(haveShort bool, flag *FlagModel) string { 77 | flagString := "" 78 | if flag.Short != 0 { 79 | flagString += fmt.Sprintf("-%c, --%s", flag.Short, flag.Name) 80 | } else { 81 | if haveShort { 82 | flagString += fmt.Sprintf(" --%s", flag.Name) 83 | } else { 84 | flagString += fmt.Sprintf("--%s", flag.Name) 85 | } 86 | } 87 | if !flag.IsBoolFlag() { 88 | flagString += fmt.Sprintf("=%s", flag.FormatPlaceHolder()) 89 | } 90 | if v, ok := flag.Value.(repeatableFlag); ok && v.IsCumulative() { 91 | flagString += " ..." 92 | } 93 | return flagString 94 | } 95 | 96 | type templateParseContext struct { 97 | SelectedCommand *CmdModel 98 | *FlagGroupModel 99 | *ArgGroupModel 100 | } 101 | 102 | type templateContext struct { 103 | App *ApplicationModel 104 | Width int 105 | Context *templateParseContext 106 | } 107 | 108 | // UsageForContext displays usage information from a ParseContext (obtained from 109 | // Application.ParseContext() or Action(f) callbacks). 110 | func (a *Application) UsageForContext(context *ParseContext) error { 111 | return a.UsageForContextWithTemplate(context, 2, a.usageTemplate) 112 | } 113 | 114 | // UsageForContextWithTemplate is the base usage function. You generally don't need to use this. 115 | func (a *Application) UsageForContextWithTemplate(context *ParseContext, indent int, tmpl string) error { 116 | width := guessWidth(a.usageWriter) 117 | funcs := template.FuncMap{ 118 | "Indent": func(level int) string { 119 | return strings.Repeat(" ", level*indent) 120 | }, 121 | "Wrap": func(indent int, s string) string { 122 | buf := bytes.NewBuffer(nil) 123 | indentText := strings.Repeat(" ", indent) 124 | doc.ToText(buf, s, indentText, " "+indentText, width-indent) 125 | return buf.String() 126 | }, 127 | "FormatFlag": formatFlag, 128 | "FlagsToTwoColumns": func(f []*FlagModel) [][2]string { 129 | rows := [][2]string{} 130 | haveShort := false 131 | for _, flag := range f { 132 | if flag.Short != 0 { 133 | haveShort = true 134 | break 135 | } 136 | } 137 | for _, flag := range f { 138 | if !flag.Hidden { 139 | rows = append(rows, [2]string{formatFlag(haveShort, flag), flag.Help}) 140 | } 141 | } 142 | return rows 143 | }, 144 | "RequiredFlags": func(f []*FlagModel) []*FlagModel { 145 | requiredFlags := []*FlagModel{} 146 | for _, flag := range f { 147 | if flag.Required { 148 | requiredFlags = append(requiredFlags, flag) 149 | } 150 | } 151 | return requiredFlags 152 | }, 153 | "OptionalFlags": func(f []*FlagModel) []*FlagModel { 154 | optionalFlags := []*FlagModel{} 155 | for _, flag := range f { 156 | if !flag.Required { 157 | optionalFlags = append(optionalFlags, flag) 158 | } 159 | } 160 | return optionalFlags 161 | }, 162 | "ArgsToTwoColumns": func(a []*ArgModel) [][2]string { 163 | rows := [][2]string{} 164 | for _, arg := range a { 165 | s := "<" + arg.Name + ">" 166 | if !arg.Required { 167 | s = "[" + s + "]" 168 | } 169 | rows = append(rows, [2]string{s, arg.Help}) 170 | } 171 | return rows 172 | }, 173 | "FormatTwoColumns": func(rows [][2]string) string { 174 | buf := bytes.NewBuffer(nil) 175 | formatTwoColumns(buf, indent, indent, width, rows) 176 | return buf.String() 177 | }, 178 | "FormatTwoColumnsWithIndent": func(rows [][2]string, indent, padding int) string { 179 | buf := bytes.NewBuffer(nil) 180 | formatTwoColumns(buf, indent, padding, width, rows) 181 | return buf.String() 182 | }, 183 | "FormatAppUsage": formatAppUsage, 184 | "FormatCommandUsage": formatCmdUsage, 185 | "IsCumulative": func(value Value) bool { 186 | r, ok := value.(remainderArg) 187 | return ok && r.IsCumulative() 188 | }, 189 | "Char": func(c rune) string { 190 | return string(c) 191 | }, 192 | } 193 | t, err := template.New("usage").Funcs(funcs).Parse(tmpl) 194 | if err != nil { 195 | return err 196 | } 197 | var selectedCommand *CmdModel 198 | if context.SelectedCommand != nil { 199 | selectedCommand = context.SelectedCommand.Model() 200 | } 201 | ctx := templateContext{ 202 | App: a.Model(), 203 | Width: width, 204 | Context: &templateParseContext{ 205 | SelectedCommand: selectedCommand, 206 | FlagGroupModel: context.flags.Model(), 207 | ArgGroupModel: context.arguments.Model(), 208 | }, 209 | } 210 | return t.Execute(a.usageWriter, ctx) 211 | } 212 | -------------------------------------------------------------------------------- /vendor/github.com/alecthomas/template/template.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package template 6 | 7 | import ( 8 | "fmt" 9 | "reflect" 10 | 11 | "github.com/alecthomas/template/parse" 12 | ) 13 | 14 | // common holds the information shared by related templates. 15 | type common struct { 16 | tmpl map[string]*Template 17 | // We use two maps, one for parsing and one for execution. 18 | // This separation makes the API cleaner since it doesn't 19 | // expose reflection to the client. 20 | parseFuncs FuncMap 21 | execFuncs map[string]reflect.Value 22 | } 23 | 24 | // Template is the representation of a parsed template. The *parse.Tree 25 | // field is exported only for use by html/template and should be treated 26 | // as unexported by all other clients. 27 | type Template struct { 28 | name string 29 | *parse.Tree 30 | *common 31 | leftDelim string 32 | rightDelim string 33 | } 34 | 35 | // New allocates a new template with the given name. 36 | func New(name string) *Template { 37 | return &Template{ 38 | name: name, 39 | } 40 | } 41 | 42 | // Name returns the name of the template. 43 | func (t *Template) Name() string { 44 | return t.name 45 | } 46 | 47 | // New allocates a new template associated with the given one and with the same 48 | // delimiters. The association, which is transitive, allows one template to 49 | // invoke another with a {{template}} action. 50 | func (t *Template) New(name string) *Template { 51 | t.init() 52 | return &Template{ 53 | name: name, 54 | common: t.common, 55 | leftDelim: t.leftDelim, 56 | rightDelim: t.rightDelim, 57 | } 58 | } 59 | 60 | func (t *Template) init() { 61 | if t.common == nil { 62 | t.common = new(common) 63 | t.tmpl = make(map[string]*Template) 64 | t.parseFuncs = make(FuncMap) 65 | t.execFuncs = make(map[string]reflect.Value) 66 | } 67 | } 68 | 69 | // Clone returns a duplicate of the template, including all associated 70 | // templates. The actual representation is not copied, but the name space of 71 | // associated templates is, so further calls to Parse in the copy will add 72 | // templates to the copy but not to the original. Clone can be used to prepare 73 | // common templates and use them with variant definitions for other templates 74 | // by adding the variants after the clone is made. 75 | func (t *Template) Clone() (*Template, error) { 76 | nt := t.copy(nil) 77 | nt.init() 78 | nt.tmpl[t.name] = nt 79 | for k, v := range t.tmpl { 80 | if k == t.name { // Already installed. 81 | continue 82 | } 83 | // The associated templates share nt's common structure. 84 | tmpl := v.copy(nt.common) 85 | nt.tmpl[k] = tmpl 86 | } 87 | for k, v := range t.parseFuncs { 88 | nt.parseFuncs[k] = v 89 | } 90 | for k, v := range t.execFuncs { 91 | nt.execFuncs[k] = v 92 | } 93 | return nt, nil 94 | } 95 | 96 | // copy returns a shallow copy of t, with common set to the argument. 97 | func (t *Template) copy(c *common) *Template { 98 | nt := New(t.name) 99 | nt.Tree = t.Tree 100 | nt.common = c 101 | nt.leftDelim = t.leftDelim 102 | nt.rightDelim = t.rightDelim 103 | return nt 104 | } 105 | 106 | // AddParseTree creates a new template with the name and parse tree 107 | // and associates it with t. 108 | func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) { 109 | if t.common != nil && t.tmpl[name] != nil { 110 | return nil, fmt.Errorf("template: redefinition of template %q", name) 111 | } 112 | nt := t.New(name) 113 | nt.Tree = tree 114 | t.tmpl[name] = nt 115 | return nt, nil 116 | } 117 | 118 | // Templates returns a slice of the templates associated with t, including t 119 | // itself. 120 | func (t *Template) Templates() []*Template { 121 | if t.common == nil { 122 | return nil 123 | } 124 | // Return a slice so we don't expose the map. 125 | m := make([]*Template, 0, len(t.tmpl)) 126 | for _, v := range t.tmpl { 127 | m = append(m, v) 128 | } 129 | return m 130 | } 131 | 132 | // Delims sets the action delimiters to the specified strings, to be used in 133 | // subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template 134 | // definitions will inherit the settings. An empty delimiter stands for the 135 | // corresponding default: {{ or }}. 136 | // The return value is the template, so calls can be chained. 137 | func (t *Template) Delims(left, right string) *Template { 138 | t.leftDelim = left 139 | t.rightDelim = right 140 | return t 141 | } 142 | 143 | // Funcs adds the elements of the argument map to the template's function map. 144 | // It panics if a value in the map is not a function with appropriate return 145 | // type. However, it is legal to overwrite elements of the map. The return 146 | // value is the template, so calls can be chained. 147 | func (t *Template) Funcs(funcMap FuncMap) *Template { 148 | t.init() 149 | addValueFuncs(t.execFuncs, funcMap) 150 | addFuncs(t.parseFuncs, funcMap) 151 | return t 152 | } 153 | 154 | // Lookup returns the template with the given name that is associated with t, 155 | // or nil if there is no such template. 156 | func (t *Template) Lookup(name string) *Template { 157 | if t.common == nil { 158 | return nil 159 | } 160 | return t.tmpl[name] 161 | } 162 | 163 | // Parse parses a string into a template. Nested template definitions will be 164 | // associated with the top-level template t. Parse may be called multiple times 165 | // to parse definitions of templates to associate with t. It is an error if a 166 | // resulting template is non-empty (contains content other than template 167 | // definitions) and would replace a non-empty template with the same name. 168 | // (In multiple calls to Parse with the same receiver template, only one call 169 | // can contain text other than space, comments, and template definitions.) 170 | func (t *Template) Parse(text string) (*Template, error) { 171 | t.init() 172 | trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins) 173 | if err != nil { 174 | return nil, err 175 | } 176 | // Add the newly parsed trees, including the one for t, into our common structure. 177 | for name, tree := range trees { 178 | // If the name we parsed is the name of this template, overwrite this template. 179 | // The associate method checks it's not a redefinition. 180 | tmpl := t 181 | if name != t.name { 182 | tmpl = t.New(name) 183 | } 184 | // Even if t == tmpl, we need to install it in the common.tmpl map. 185 | if replace, err := t.associate(tmpl, tree); err != nil { 186 | return nil, err 187 | } else if replace { 188 | tmpl.Tree = tree 189 | } 190 | tmpl.leftDelim = t.leftDelim 191 | tmpl.rightDelim = t.rightDelim 192 | } 193 | return t, nil 194 | } 195 | 196 | // associate installs the new template into the group of templates associated 197 | // with t. It is an error to reuse a name except to overwrite an empty 198 | // template. The two are already known to share the common structure. 199 | // The boolean return value reports wither to store this tree as t.Tree. 200 | func (t *Template) associate(new *Template, tree *parse.Tree) (bool, error) { 201 | if new.common != t.common { 202 | panic("internal error: associate not common") 203 | } 204 | name := new.name 205 | if old := t.tmpl[name]; old != nil { 206 | oldIsEmpty := parse.IsEmptyTree(old.Root) 207 | newIsEmpty := parse.IsEmptyTree(tree.Root) 208 | if newIsEmpty { 209 | // Whether old is empty or not, new is empty; no reason to replace old. 210 | return false, nil 211 | } 212 | if !oldIsEmpty { 213 | return false, fmt.Errorf("template: redefinition of template %q", name) 214 | } 215 | } 216 | t.tmpl[name] = new 217 | return true, nil 218 | } 219 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/cmd.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type cmdMixin struct { 9 | *flagGroup 10 | *argGroup 11 | *cmdGroup 12 | actionMixin 13 | } 14 | 15 | // CmdCompletion returns completion options for arguments, if that's where 16 | // parsing left off, or commands if there aren't any unsatisfied args. 17 | func (c *cmdMixin) CmdCompletion(context *ParseContext) []string { 18 | var options []string 19 | 20 | // Count args already satisfied - we won't complete those, and add any 21 | // default commands' alternatives, since they weren't listed explicitly 22 | // and the user may want to explicitly list something else. 23 | argsSatisfied := 0 24 | for _, el := range context.Elements { 25 | switch clause := el.Clause.(type) { 26 | case *ArgClause: 27 | if el.Value != nil && *el.Value != "" { 28 | argsSatisfied++ 29 | } 30 | case *CmdClause: 31 | options = append(options, clause.completionAlts...) 32 | default: 33 | } 34 | } 35 | 36 | if argsSatisfied < len(c.argGroup.args) { 37 | // Since not all args have been satisfied, show options for the current one 38 | options = append(options, c.argGroup.args[argsSatisfied].resolveCompletions()...) 39 | } else { 40 | // If all args are satisfied, then go back to completing commands 41 | for _, cmd := range c.cmdGroup.commandOrder { 42 | if !cmd.hidden { 43 | options = append(options, cmd.name) 44 | } 45 | } 46 | } 47 | 48 | return options 49 | } 50 | 51 | func (c *cmdMixin) FlagCompletion(flagName string, flagValue string) (choices []string, flagMatch bool, optionMatch bool) { 52 | // Check if flagName matches a known flag. 53 | // If it does, show the options for the flag 54 | // Otherwise, show all flags 55 | 56 | options := []string{} 57 | 58 | for _, flag := range c.flagGroup.flagOrder { 59 | // Loop through each flag and determine if a match exists 60 | if flag.name == flagName { 61 | // User typed entire flag. Need to look for flag options. 62 | options = flag.resolveCompletions() 63 | if len(options) == 0 { 64 | // No Options to Choose From, Assume Match. 65 | return options, true, true 66 | } 67 | 68 | // Loop options to find if the user specified value matches 69 | isPrefix := false 70 | matched := false 71 | 72 | for _, opt := range options { 73 | if flagValue == opt { 74 | matched = true 75 | } else if strings.HasPrefix(opt, flagValue) { 76 | isPrefix = true 77 | } 78 | } 79 | 80 | // Matched Flag Directly 81 | // Flag Value Not Prefixed, and Matched Directly 82 | return options, true, !isPrefix && matched 83 | } 84 | 85 | if !flag.hidden { 86 | options = append(options, "--"+flag.name) 87 | } 88 | } 89 | // No Flag directly matched. 90 | return options, false, false 91 | 92 | } 93 | 94 | type cmdGroup struct { 95 | app *Application 96 | parent *CmdClause 97 | commands map[string]*CmdClause 98 | commandOrder []*CmdClause 99 | } 100 | 101 | func (c *cmdGroup) defaultSubcommand() *CmdClause { 102 | for _, cmd := range c.commandOrder { 103 | if cmd.isDefault { 104 | return cmd 105 | } 106 | } 107 | return nil 108 | } 109 | 110 | func (c *cmdGroup) cmdNames() []string { 111 | names := make([]string, 0, len(c.commandOrder)) 112 | for _, cmd := range c.commandOrder { 113 | names = append(names, cmd.name) 114 | } 115 | return names 116 | } 117 | 118 | // GetArg gets a command definition. 119 | // 120 | // This allows existing commands to be modified after definition but before parsing. Useful for 121 | // modular applications. 122 | func (c *cmdGroup) GetCommand(name string) *CmdClause { 123 | return c.commands[name] 124 | } 125 | 126 | func newCmdGroup(app *Application) *cmdGroup { 127 | return &cmdGroup{ 128 | app: app, 129 | commands: make(map[string]*CmdClause), 130 | } 131 | } 132 | 133 | func (c *cmdGroup) flattenedCommands() (out []*CmdClause) { 134 | for _, cmd := range c.commandOrder { 135 | if len(cmd.commands) == 0 { 136 | out = append(out, cmd) 137 | } 138 | out = append(out, cmd.flattenedCommands()...) 139 | } 140 | return 141 | } 142 | 143 | func (c *cmdGroup) addCommand(name, help string) *CmdClause { 144 | cmd := newCommand(c.app, name, help) 145 | c.commands[name] = cmd 146 | c.commandOrder = append(c.commandOrder, cmd) 147 | return cmd 148 | } 149 | 150 | func (c *cmdGroup) init() error { 151 | seen := map[string]bool{} 152 | if c.defaultSubcommand() != nil && !c.have() { 153 | return fmt.Errorf("default subcommand %q provided but no subcommands defined", c.defaultSubcommand().name) 154 | } 155 | defaults := []string{} 156 | for _, cmd := range c.commandOrder { 157 | if cmd.isDefault { 158 | defaults = append(defaults, cmd.name) 159 | } 160 | if seen[cmd.name] { 161 | return fmt.Errorf("duplicate command %q", cmd.name) 162 | } 163 | seen[cmd.name] = true 164 | for _, alias := range cmd.aliases { 165 | if seen[alias] { 166 | return fmt.Errorf("alias duplicates existing command %q", alias) 167 | } 168 | c.commands[alias] = cmd 169 | } 170 | if err := cmd.init(); err != nil { 171 | return err 172 | } 173 | } 174 | if len(defaults) > 1 { 175 | return fmt.Errorf("more than one default subcommand exists: %s", strings.Join(defaults, ", ")) 176 | } 177 | return nil 178 | } 179 | 180 | func (c *cmdGroup) have() bool { 181 | return len(c.commands) > 0 182 | } 183 | 184 | type CmdClauseValidator func(*CmdClause) error 185 | 186 | // A CmdClause is a single top-level command. It encapsulates a set of flags 187 | // and either subcommands or positional arguments. 188 | type CmdClause struct { 189 | cmdMixin 190 | app *Application 191 | name string 192 | aliases []string 193 | help string 194 | isDefault bool 195 | validator CmdClauseValidator 196 | hidden bool 197 | completionAlts []string 198 | } 199 | 200 | func newCommand(app *Application, name, help string) *CmdClause { 201 | c := &CmdClause{ 202 | app: app, 203 | name: name, 204 | help: help, 205 | } 206 | c.flagGroup = newFlagGroup() 207 | c.argGroup = newArgGroup() 208 | c.cmdGroup = newCmdGroup(app) 209 | return c 210 | } 211 | 212 | // Add an Alias for this command. 213 | func (c *CmdClause) Alias(name string) *CmdClause { 214 | c.aliases = append(c.aliases, name) 215 | return c 216 | } 217 | 218 | // Validate sets a validation function to run when parsing. 219 | func (c *CmdClause) Validate(validator CmdClauseValidator) *CmdClause { 220 | c.validator = validator 221 | return c 222 | } 223 | 224 | func (c *CmdClause) FullCommand() string { 225 | out := []string{c.name} 226 | for p := c.parent; p != nil; p = p.parent { 227 | out = append([]string{p.name}, out...) 228 | } 229 | return strings.Join(out, " ") 230 | } 231 | 232 | // Command adds a new sub-command. 233 | func (c *CmdClause) Command(name, help string) *CmdClause { 234 | cmd := c.addCommand(name, help) 235 | cmd.parent = c 236 | return cmd 237 | } 238 | 239 | // Default makes this command the default if commands don't match. 240 | func (c *CmdClause) Default() *CmdClause { 241 | c.isDefault = true 242 | return c 243 | } 244 | 245 | func (c *CmdClause) Action(action Action) *CmdClause { 246 | c.addAction(action) 247 | return c 248 | } 249 | 250 | func (c *CmdClause) PreAction(action Action) *CmdClause { 251 | c.addPreAction(action) 252 | return c 253 | } 254 | 255 | func (c *CmdClause) init() error { 256 | if err := c.flagGroup.init(c.app.defaultEnvarPrefix()); err != nil { 257 | return err 258 | } 259 | if c.argGroup.have() && c.cmdGroup.have() { 260 | return fmt.Errorf("can't mix Arg()s with Command()s") 261 | } 262 | if err := c.argGroup.init(); err != nil { 263 | return err 264 | } 265 | if err := c.cmdGroup.init(); err != nil { 266 | return err 267 | } 268 | return nil 269 | } 270 | 271 | func (c *CmdClause) Hidden() *CmdClause { 272 | c.hidden = true 273 | return c 274 | } 275 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/templates.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | // Default usage template. 4 | var DefaultUsageTemplate = `{{define "FormatCommand"}}\ 5 | {{if .FlagSummary}} {{.FlagSummary}}{{end}}\ 6 | {{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\ 7 | {{end}}\ 8 | 9 | {{define "FormatCommands"}}\ 10 | {{range .FlattenedCommands}}\ 11 | {{if not .Hidden}}\ 12 | {{.FullCommand}}{{if .Default}}*{{end}}{{template "FormatCommand" .}} 13 | {{.Help|Wrap 4}} 14 | {{end}}\ 15 | {{end}}\ 16 | {{end}}\ 17 | 18 | {{define "FormatUsage"}}\ 19 | {{template "FormatCommand" .}}{{if .Commands}} [ ...]{{end}} 20 | {{if .Help}} 21 | {{.Help|Wrap 0}}\ 22 | {{end}}\ 23 | 24 | {{end}}\ 25 | 26 | {{if .Context.SelectedCommand}}\ 27 | usage: {{.App.Name}} {{.Context.SelectedCommand}}{{template "FormatUsage" .Context.SelectedCommand}} 28 | {{else}}\ 29 | usage: {{.App.Name}}{{template "FormatUsage" .App}} 30 | {{end}}\ 31 | {{if .Context.Flags}}\ 32 | Flags: 33 | {{.Context.Flags|FlagsToTwoColumns|FormatTwoColumns}} 34 | {{end}}\ 35 | {{if .Context.Args}}\ 36 | Args: 37 | {{.Context.Args|ArgsToTwoColumns|FormatTwoColumns}} 38 | {{end}}\ 39 | {{if .Context.SelectedCommand}}\ 40 | {{if len .Context.SelectedCommand.Commands}}\ 41 | Subcommands: 42 | {{template "FormatCommands" .Context.SelectedCommand}} 43 | {{end}}\ 44 | {{else if .App.Commands}}\ 45 | Commands: 46 | {{template "FormatCommands" .App}} 47 | {{end}}\ 48 | ` 49 | 50 | // Usage template where command's optional flags are listed separately 51 | var SeparateOptionalFlagsUsageTemplate = `{{define "FormatCommand"}}\ 52 | {{if .FlagSummary}} {{.FlagSummary}}{{end}}\ 53 | {{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\ 54 | {{end}}\ 55 | 56 | {{define "FormatCommands"}}\ 57 | {{range .FlattenedCommands}}\ 58 | {{if not .Hidden}}\ 59 | {{.FullCommand}}{{if .Default}}*{{end}}{{template "FormatCommand" .}} 60 | {{.Help|Wrap 4}} 61 | {{end}}\ 62 | {{end}}\ 63 | {{end}}\ 64 | 65 | {{define "FormatUsage"}}\ 66 | {{template "FormatCommand" .}}{{if .Commands}} [ ...]{{end}} 67 | {{if .Help}} 68 | {{.Help|Wrap 0}}\ 69 | {{end}}\ 70 | 71 | {{end}}\ 72 | {{if .Context.SelectedCommand}}\ 73 | usage: {{.App.Name}} {{.Context.SelectedCommand}}{{template "FormatUsage" .Context.SelectedCommand}} 74 | {{else}}\ 75 | usage: {{.App.Name}}{{template "FormatUsage" .App}} 76 | {{end}}\ 77 | 78 | {{if .Context.Flags|RequiredFlags}}\ 79 | Required flags: 80 | {{.Context.Flags|RequiredFlags|FlagsToTwoColumns|FormatTwoColumns}} 81 | {{end}}\ 82 | {{if .Context.Flags|OptionalFlags}}\ 83 | Optional flags: 84 | {{.Context.Flags|OptionalFlags|FlagsToTwoColumns|FormatTwoColumns}} 85 | {{end}}\ 86 | {{if .Context.Args}}\ 87 | Args: 88 | {{.Context.Args|ArgsToTwoColumns|FormatTwoColumns}} 89 | {{end}}\ 90 | {{if .Context.SelectedCommand}}\ 91 | Subcommands: 92 | {{if .Context.SelectedCommand.Commands}}\ 93 | {{template "FormatCommands" .Context.SelectedCommand}} 94 | {{end}}\ 95 | {{else if .App.Commands}}\ 96 | Commands: 97 | {{template "FormatCommands" .App}} 98 | {{end}}\ 99 | ` 100 | 101 | // Usage template with compactly formatted commands. 102 | var CompactUsageTemplate = `{{define "FormatCommand"}}\ 103 | {{if .FlagSummary}} {{.FlagSummary}}{{end}}\ 104 | {{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\ 105 | {{end}}\ 106 | 107 | {{define "FormatCommandList"}}\ 108 | {{range .}}\ 109 | {{if not .Hidden}}\ 110 | {{.Depth|Indent}}{{.Name}}{{if .Default}}*{{end}}{{template "FormatCommand" .}} 111 | {{end}}\ 112 | {{template "FormatCommandList" .Commands}}\ 113 | {{end}}\ 114 | {{end}}\ 115 | 116 | {{define "FormatUsage"}}\ 117 | {{template "FormatCommand" .}}{{if .Commands}} [ ...]{{end}} 118 | {{if .Help}} 119 | {{.Help|Wrap 0}}\ 120 | {{end}}\ 121 | 122 | {{end}}\ 123 | 124 | {{if .Context.SelectedCommand}}\ 125 | usage: {{.App.Name}} {{.Context.SelectedCommand}}{{template "FormatUsage" .Context.SelectedCommand}} 126 | {{else}}\ 127 | usage: {{.App.Name}}{{template "FormatUsage" .App}} 128 | {{end}}\ 129 | {{if .Context.Flags}}\ 130 | Flags: 131 | {{.Context.Flags|FlagsToTwoColumns|FormatTwoColumns}} 132 | {{end}}\ 133 | {{if .Context.Args}}\ 134 | Args: 135 | {{.Context.Args|ArgsToTwoColumns|FormatTwoColumns}} 136 | {{end}}\ 137 | {{if .Context.SelectedCommand}}\ 138 | {{if .Context.SelectedCommand.Commands}}\ 139 | Commands: 140 | {{.Context.SelectedCommand}} 141 | {{template "FormatCommandList" .Context.SelectedCommand.Commands}} 142 | {{end}}\ 143 | {{else if .App.Commands}}\ 144 | Commands: 145 | {{template "FormatCommandList" .App.Commands}} 146 | {{end}}\ 147 | ` 148 | 149 | var ManPageTemplate = `{{define "FormatFlags"}}\ 150 | {{range .Flags}}\ 151 | {{if not .Hidden}}\ 152 | .TP 153 | \fB{{if .Short}}-{{.Short|Char}}, {{end}}--{{.Name}}{{if not .IsBoolFlag}}={{.FormatPlaceHolder}}{{end}}\\fR 154 | {{.Help}} 155 | {{end}}\ 156 | {{end}}\ 157 | {{end}}\ 158 | 159 | {{define "FormatCommand"}}\ 160 | {{if .FlagSummary}} {{.FlagSummary}}{{end}}\ 161 | {{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}{{if .Default}}*{{end}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\ 162 | {{end}}\ 163 | 164 | {{define "FormatCommands"}}\ 165 | {{range .FlattenedCommands}}\ 166 | {{if not .Hidden}}\ 167 | .SS 168 | \fB{{.FullCommand}}{{template "FormatCommand" .}}\\fR 169 | .PP 170 | {{.Help}} 171 | {{template "FormatFlags" .}}\ 172 | {{end}}\ 173 | {{end}}\ 174 | {{end}}\ 175 | 176 | {{define "FormatUsage"}}\ 177 | {{template "FormatCommand" .}}{{if .Commands}} [ ...]{{end}}\\fR 178 | {{end}}\ 179 | 180 | .TH {{.App.Name}} 1 {{.App.Version}} "{{.App.Author}}" 181 | .SH "NAME" 182 | {{.App.Name}} 183 | .SH "SYNOPSIS" 184 | .TP 185 | \fB{{.App.Name}}{{template "FormatUsage" .App}} 186 | .SH "DESCRIPTION" 187 | {{.App.Help}} 188 | .SH "OPTIONS" 189 | {{template "FormatFlags" .App}}\ 190 | {{if .App.Commands}}\ 191 | .SH "COMMANDS" 192 | {{template "FormatCommands" .App}}\ 193 | {{end}}\ 194 | ` 195 | 196 | // Default usage template. 197 | var LongHelpTemplate = `{{define "FormatCommand"}}\ 198 | {{if .FlagSummary}} {{.FlagSummary}}{{end}}\ 199 | {{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\ 200 | {{end}}\ 201 | 202 | {{define "FormatCommands"}}\ 203 | {{range .FlattenedCommands}}\ 204 | {{if not .Hidden}}\ 205 | {{.FullCommand}}{{template "FormatCommand" .}} 206 | {{.Help|Wrap 4}} 207 | {{with .Flags|FlagsToTwoColumns}}{{FormatTwoColumnsWithIndent . 4 2}}{{end}} 208 | {{end}}\ 209 | {{end}}\ 210 | {{end}}\ 211 | 212 | {{define "FormatUsage"}}\ 213 | {{template "FormatCommand" .}}{{if .Commands}} [ ...]{{end}} 214 | {{if .Help}} 215 | {{.Help|Wrap 0}}\ 216 | {{end}}\ 217 | 218 | {{end}}\ 219 | 220 | usage: {{.App.Name}}{{template "FormatUsage" .App}} 221 | {{if .Context.Flags}}\ 222 | Flags: 223 | {{.Context.Flags|FlagsToTwoColumns|FormatTwoColumns}} 224 | {{end}}\ 225 | {{if .Context.Args}}\ 226 | Args: 227 | {{.Context.Args|ArgsToTwoColumns|FormatTwoColumns}} 228 | {{end}}\ 229 | {{if .App.Commands}}\ 230 | Commands: 231 | {{template "FormatCommands" .App}} 232 | {{end}}\ 233 | ` 234 | 235 | var BashCompletionTemplate = ` 236 | _{{.App.Name}}_bash_autocomplete() { 237 | local cur prev opts base 238 | COMPREPLY=() 239 | cur="${COMP_WORDS[COMP_CWORD]}" 240 | opts=$( ${COMP_WORDS[0]} --completion-bash ${COMP_WORDS[@]:1:$COMP_CWORD} ) 241 | COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) 242 | return 0 243 | } 244 | complete -F _{{.App.Name}}_bash_autocomplete {{.App.Name}} 245 | 246 | ` 247 | 248 | var ZshCompletionTemplate = ` 249 | #compdef {{.App.Name}} 250 | autoload -U compinit && compinit 251 | autoload -U bashcompinit && bashcompinit 252 | 253 | _{{.App.Name}}_bash_autocomplete() { 254 | local cur prev opts base 255 | COMPREPLY=() 256 | cur="${COMP_WORDS[COMP_CWORD]}" 257 | opts=$( ${COMP_WORDS[0]} --completion-bash ${COMP_WORDS[@]:1:$COMP_CWORD} ) 258 | COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) 259 | return 0 260 | } 261 | complete -F _{{.App.Name}}_bash_autocomplete {{.App.Name}} 262 | ` 263 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/flags.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type flagGroup struct { 9 | short map[string]*FlagClause 10 | long map[string]*FlagClause 11 | flagOrder []*FlagClause 12 | } 13 | 14 | func newFlagGroup() *flagGroup { 15 | return &flagGroup{ 16 | short: map[string]*FlagClause{}, 17 | long: map[string]*FlagClause{}, 18 | } 19 | } 20 | 21 | // GetFlag gets a flag definition. 22 | // 23 | // This allows existing flags to be modified after definition but before parsing. Useful for 24 | // modular applications. 25 | func (f *flagGroup) GetFlag(name string) *FlagClause { 26 | return f.long[name] 27 | } 28 | 29 | // Flag defines a new flag with the given long name and help. 30 | func (f *flagGroup) Flag(name, help string) *FlagClause { 31 | flag := newFlag(name, help) 32 | f.long[name] = flag 33 | f.flagOrder = append(f.flagOrder, flag) 34 | return flag 35 | } 36 | 37 | func (f *flagGroup) init(defaultEnvarPrefix string) error { 38 | if err := f.checkDuplicates(); err != nil { 39 | return err 40 | } 41 | for _, flag := range f.long { 42 | if defaultEnvarPrefix != "" && !flag.noEnvar && flag.envar == "" { 43 | flag.envar = envarTransform(defaultEnvarPrefix + "_" + flag.name) 44 | } 45 | if err := flag.init(); err != nil { 46 | return err 47 | } 48 | if flag.shorthand != 0 { 49 | f.short[string(flag.shorthand)] = flag 50 | } 51 | } 52 | return nil 53 | } 54 | 55 | func (f *flagGroup) checkDuplicates() error { 56 | seenShort := map[rune]bool{} 57 | seenLong := map[string]bool{} 58 | for _, flag := range f.flagOrder { 59 | if flag.shorthand != 0 { 60 | if _, ok := seenShort[flag.shorthand]; ok { 61 | return fmt.Errorf("duplicate short flag -%c", flag.shorthand) 62 | } 63 | seenShort[flag.shorthand] = true 64 | } 65 | if _, ok := seenLong[flag.name]; ok { 66 | return fmt.Errorf("duplicate long flag --%s", flag.name) 67 | } 68 | seenLong[flag.name] = true 69 | } 70 | return nil 71 | } 72 | 73 | func (f *flagGroup) parse(context *ParseContext) (*FlagClause, error) { 74 | var token *Token 75 | 76 | loop: 77 | for { 78 | token = context.Peek() 79 | switch token.Type { 80 | case TokenEOL: 81 | break loop 82 | 83 | case TokenLong, TokenShort: 84 | flagToken := token 85 | defaultValue := "" 86 | var flag *FlagClause 87 | var ok bool 88 | invert := false 89 | 90 | name := token.Value 91 | if token.Type == TokenLong { 92 | flag, ok = f.long[name] 93 | if !ok { 94 | if strings.HasPrefix(name, "no-") { 95 | name = name[3:] 96 | invert = true 97 | } 98 | flag, ok = f.long[name] 99 | } 100 | if !ok { 101 | return nil, fmt.Errorf("unknown long flag '%s'", flagToken) 102 | } 103 | } else { 104 | flag, ok = f.short[name] 105 | if !ok { 106 | return nil, fmt.Errorf("unknown short flag '%s'", flagToken) 107 | } 108 | } 109 | 110 | context.Next() 111 | 112 | fb, ok := flag.value.(boolFlag) 113 | if ok && fb.IsBoolFlag() { 114 | if invert { 115 | defaultValue = "false" 116 | } else { 117 | defaultValue = "true" 118 | } 119 | } else { 120 | if invert { 121 | context.Push(token) 122 | return nil, fmt.Errorf("unknown long flag '%s'", flagToken) 123 | } 124 | token = context.Peek() 125 | if token.Type != TokenArg { 126 | context.Push(token) 127 | return nil, fmt.Errorf("expected argument for flag '%s'", flagToken) 128 | } 129 | context.Next() 130 | defaultValue = token.Value 131 | } 132 | 133 | context.matchedFlag(flag, defaultValue) 134 | return flag, nil 135 | 136 | default: 137 | break loop 138 | } 139 | } 140 | return nil, nil 141 | } 142 | 143 | // FlagClause is a fluid interface used to build flags. 144 | type FlagClause struct { 145 | parserMixin 146 | actionMixin 147 | completionsMixin 148 | envarMixin 149 | name string 150 | shorthand rune 151 | help string 152 | defaultValues []string 153 | placeholder string 154 | hidden bool 155 | } 156 | 157 | func newFlag(name, help string) *FlagClause { 158 | f := &FlagClause{ 159 | name: name, 160 | help: help, 161 | } 162 | return f 163 | } 164 | 165 | func (f *FlagClause) setDefault() error { 166 | if f.HasEnvarValue() { 167 | if v, ok := f.value.(repeatableFlag); !ok || !v.IsCumulative() { 168 | // Use the value as-is 169 | return f.value.Set(f.GetEnvarValue()) 170 | } else { 171 | for _, value := range f.GetSplitEnvarValue() { 172 | if err := f.value.Set(value); err != nil { 173 | return err 174 | } 175 | } 176 | return nil 177 | } 178 | } 179 | 180 | if len(f.defaultValues) > 0 { 181 | for _, defaultValue := range f.defaultValues { 182 | if err := f.value.Set(defaultValue); err != nil { 183 | return err 184 | } 185 | } 186 | return nil 187 | } 188 | 189 | return nil 190 | } 191 | 192 | func (f *FlagClause) needsValue() bool { 193 | haveDefault := len(f.defaultValues) > 0 194 | return f.required && !(haveDefault || f.HasEnvarValue()) 195 | } 196 | 197 | func (f *FlagClause) init() error { 198 | if f.required && len(f.defaultValues) > 0 { 199 | return fmt.Errorf("required flag '--%s' with default value that will never be used", f.name) 200 | } 201 | if f.value == nil { 202 | return fmt.Errorf("no type defined for --%s (eg. .String())", f.name) 203 | } 204 | if v, ok := f.value.(repeatableFlag); (!ok || !v.IsCumulative()) && len(f.defaultValues) > 1 { 205 | return fmt.Errorf("invalid default for '--%s', expecting single value", f.name) 206 | } 207 | return nil 208 | } 209 | 210 | // Dispatch to the given function after the flag is parsed and validated. 211 | func (f *FlagClause) Action(action Action) *FlagClause { 212 | f.addAction(action) 213 | return f 214 | } 215 | 216 | func (f *FlagClause) PreAction(action Action) *FlagClause { 217 | f.addPreAction(action) 218 | return f 219 | } 220 | 221 | // HintAction registers a HintAction (function) for the flag to provide completions 222 | func (a *FlagClause) HintAction(action HintAction) *FlagClause { 223 | a.addHintAction(action) 224 | return a 225 | } 226 | 227 | // HintOptions registers any number of options for the flag to provide completions 228 | func (a *FlagClause) HintOptions(options ...string) *FlagClause { 229 | a.addHintAction(func() []string { 230 | return options 231 | }) 232 | return a 233 | } 234 | 235 | func (a *FlagClause) EnumVar(target *string, options ...string) { 236 | a.parserMixin.EnumVar(target, options...) 237 | a.addHintActionBuiltin(func() []string { 238 | return options 239 | }) 240 | } 241 | 242 | func (a *FlagClause) Enum(options ...string) (target *string) { 243 | a.addHintActionBuiltin(func() []string { 244 | return options 245 | }) 246 | return a.parserMixin.Enum(options...) 247 | } 248 | 249 | // Default values for this flag. They *must* be parseable by the value of the flag. 250 | func (f *FlagClause) Default(values ...string) *FlagClause { 251 | f.defaultValues = values 252 | return f 253 | } 254 | 255 | // DEPRECATED: Use Envar(name) instead. 256 | func (f *FlagClause) OverrideDefaultFromEnvar(envar string) *FlagClause { 257 | return f.Envar(envar) 258 | } 259 | 260 | // Envar overrides the default value(s) for a flag from an environment variable, 261 | // if it is set. Several default values can be provided by using new lines to 262 | // separate them. 263 | func (f *FlagClause) Envar(name string) *FlagClause { 264 | f.envar = name 265 | f.noEnvar = false 266 | return f 267 | } 268 | 269 | // NoEnvar forces environment variable defaults to be disabled for this flag. 270 | // Most useful in conjunction with app.DefaultEnvars(). 271 | func (f *FlagClause) NoEnvar() *FlagClause { 272 | f.envar = "" 273 | f.noEnvar = true 274 | return f 275 | } 276 | 277 | // PlaceHolder sets the place-holder string used for flag values in the help. The 278 | // default behaviour is to use the value provided by Default() if provided, 279 | // then fall back on the capitalized flag name. 280 | func (f *FlagClause) PlaceHolder(placeholder string) *FlagClause { 281 | f.placeholder = placeholder 282 | return f 283 | } 284 | 285 | // Hidden hides a flag from usage but still allows it to be used. 286 | func (f *FlagClause) Hidden() *FlagClause { 287 | f.hidden = true 288 | return f 289 | } 290 | 291 | // Required makes the flag required. You can not provide a Default() value to a Required() flag. 292 | func (f *FlagClause) Required() *FlagClause { 293 | f.required = true 294 | return f 295 | } 296 | 297 | // Short sets the short flag name. 298 | func (f *FlagClause) Short(name rune) *FlagClause { 299 | f.shorthand = name 300 | return f 301 | } 302 | 303 | // Bool makes this flag a boolean flag. 304 | func (f *FlagClause) Bool() (target *bool) { 305 | target = new(bool) 306 | f.SetValue(newBoolValue(target)) 307 | return 308 | } 309 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/parser.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "strings" 8 | "unicode/utf8" 9 | ) 10 | 11 | type TokenType int 12 | 13 | // Token types. 14 | const ( 15 | TokenShort TokenType = iota 16 | TokenLong 17 | TokenArg 18 | TokenError 19 | TokenEOL 20 | ) 21 | 22 | func (t TokenType) String() string { 23 | switch t { 24 | case TokenShort: 25 | return "short flag" 26 | case TokenLong: 27 | return "long flag" 28 | case TokenArg: 29 | return "argument" 30 | case TokenError: 31 | return "error" 32 | case TokenEOL: 33 | return "" 34 | } 35 | return "?" 36 | } 37 | 38 | var ( 39 | TokenEOLMarker = Token{-1, TokenEOL, ""} 40 | ) 41 | 42 | type Token struct { 43 | Index int 44 | Type TokenType 45 | Value string 46 | } 47 | 48 | func (t *Token) Equal(o *Token) bool { 49 | return t.Index == o.Index 50 | } 51 | 52 | func (t *Token) IsFlag() bool { 53 | return t.Type == TokenShort || t.Type == TokenLong 54 | } 55 | 56 | func (t *Token) IsEOF() bool { 57 | return t.Type == TokenEOL 58 | } 59 | 60 | func (t *Token) String() string { 61 | switch t.Type { 62 | case TokenShort: 63 | return "-" + t.Value 64 | case TokenLong: 65 | return "--" + t.Value 66 | case TokenArg: 67 | return t.Value 68 | case TokenError: 69 | return "error: " + t.Value 70 | case TokenEOL: 71 | return "" 72 | default: 73 | panic("unhandled type") 74 | } 75 | } 76 | 77 | // A union of possible elements in a parse stack. 78 | type ParseElement struct { 79 | // Clause is either *CmdClause, *ArgClause or *FlagClause. 80 | Clause interface{} 81 | // Value is corresponding value for an ArgClause or FlagClause (if any). 82 | Value *string 83 | } 84 | 85 | // ParseContext holds the current context of the parser. When passed to 86 | // Action() callbacks Elements will be fully populated with *FlagClause, 87 | // *ArgClause and *CmdClause values and their corresponding arguments (if 88 | // any). 89 | type ParseContext struct { 90 | SelectedCommand *CmdClause 91 | ignoreDefault bool 92 | argsOnly bool 93 | peek []*Token 94 | argi int // Index of current command-line arg we're processing. 95 | args []string 96 | rawArgs []string 97 | flags *flagGroup 98 | arguments *argGroup 99 | argumenti int // Cursor into arguments 100 | // Flags, arguments and commands encountered and collected during parse. 101 | Elements []*ParseElement 102 | } 103 | 104 | func (p *ParseContext) nextArg() *ArgClause { 105 | if p.argumenti >= len(p.arguments.args) { 106 | return nil 107 | } 108 | arg := p.arguments.args[p.argumenti] 109 | if !arg.consumesRemainder() { 110 | p.argumenti++ 111 | } 112 | return arg 113 | } 114 | 115 | func (p *ParseContext) next() { 116 | p.argi++ 117 | p.args = p.args[1:] 118 | } 119 | 120 | // HasTrailingArgs returns true if there are unparsed command-line arguments. 121 | // This can occur if the parser can not match remaining arguments. 122 | func (p *ParseContext) HasTrailingArgs() bool { 123 | return len(p.args) > 0 124 | } 125 | 126 | func tokenize(args []string, ignoreDefault bool) *ParseContext { 127 | return &ParseContext{ 128 | ignoreDefault: ignoreDefault, 129 | args: args, 130 | rawArgs: args, 131 | flags: newFlagGroup(), 132 | arguments: newArgGroup(), 133 | } 134 | } 135 | 136 | func (p *ParseContext) mergeFlags(flags *flagGroup) { 137 | for _, flag := range flags.flagOrder { 138 | if flag.shorthand != 0 { 139 | p.flags.short[string(flag.shorthand)] = flag 140 | } 141 | p.flags.long[flag.name] = flag 142 | p.flags.flagOrder = append(p.flags.flagOrder, flag) 143 | } 144 | } 145 | 146 | func (p *ParseContext) mergeArgs(args *argGroup) { 147 | for _, arg := range args.args { 148 | p.arguments.args = append(p.arguments.args, arg) 149 | } 150 | } 151 | 152 | func (p *ParseContext) EOL() bool { 153 | return p.Peek().Type == TokenEOL 154 | } 155 | 156 | func (p *ParseContext) Error() bool { 157 | return p.Peek().Type == TokenError 158 | } 159 | 160 | // Next token in the parse context. 161 | func (p *ParseContext) Next() *Token { 162 | if len(p.peek) > 0 { 163 | return p.pop() 164 | } 165 | 166 | // End of tokens. 167 | if len(p.args) == 0 { 168 | return &Token{Index: p.argi, Type: TokenEOL} 169 | } 170 | 171 | arg := p.args[0] 172 | p.next() 173 | 174 | if p.argsOnly { 175 | return &Token{p.argi, TokenArg, arg} 176 | } 177 | 178 | // All remaining args are passed directly. 179 | if arg == "--" { 180 | p.argsOnly = true 181 | return p.Next() 182 | } 183 | 184 | if strings.HasPrefix(arg, "--") { 185 | parts := strings.SplitN(arg[2:], "=", 2) 186 | token := &Token{p.argi, TokenLong, parts[0]} 187 | if len(parts) == 2 { 188 | p.Push(&Token{p.argi, TokenArg, parts[1]}) 189 | } 190 | return token 191 | } 192 | 193 | if strings.HasPrefix(arg, "-") { 194 | if len(arg) == 1 { 195 | return &Token{Index: p.argi, Type: TokenShort} 196 | } 197 | shortRune, size := utf8.DecodeRuneInString(arg[1:]) 198 | short := string(shortRune) 199 | flag, ok := p.flags.short[short] 200 | // Not a known short flag, we'll just return it anyway. 201 | if !ok { 202 | } else if fb, ok := flag.value.(boolFlag); ok && fb.IsBoolFlag() { 203 | // Bool short flag. 204 | } else { 205 | // Short flag with combined argument: -fARG 206 | token := &Token{p.argi, TokenShort, short} 207 | if len(arg) > size+1 { 208 | p.Push(&Token{p.argi, TokenArg, arg[size+1:]}) 209 | } 210 | return token 211 | } 212 | 213 | if len(arg) > size+1 { 214 | p.args = append([]string{"-" + arg[size+1:]}, p.args...) 215 | } 216 | return &Token{p.argi, TokenShort, short} 217 | } else if strings.HasPrefix(arg, "@") { 218 | expanded, err := ExpandArgsFromFile(arg[1:]) 219 | if err != nil { 220 | return &Token{p.argi, TokenError, err.Error()} 221 | } 222 | if len(p.args) == 0 { 223 | p.args = expanded 224 | } else { 225 | p.args = append(expanded, p.args...) 226 | } 227 | return p.Next() 228 | } 229 | 230 | return &Token{p.argi, TokenArg, arg} 231 | } 232 | 233 | func (p *ParseContext) Peek() *Token { 234 | if len(p.peek) == 0 { 235 | return p.Push(p.Next()) 236 | } 237 | return p.peek[len(p.peek)-1] 238 | } 239 | 240 | func (p *ParseContext) Push(token *Token) *Token { 241 | p.peek = append(p.peek, token) 242 | return token 243 | } 244 | 245 | func (p *ParseContext) pop() *Token { 246 | end := len(p.peek) - 1 247 | token := p.peek[end] 248 | p.peek = p.peek[0:end] 249 | return token 250 | } 251 | 252 | func (p *ParseContext) String() string { 253 | return p.SelectedCommand.FullCommand() 254 | } 255 | 256 | func (p *ParseContext) matchedFlag(flag *FlagClause, value string) { 257 | p.Elements = append(p.Elements, &ParseElement{Clause: flag, Value: &value}) 258 | } 259 | 260 | func (p *ParseContext) matchedArg(arg *ArgClause, value string) { 261 | p.Elements = append(p.Elements, &ParseElement{Clause: arg, Value: &value}) 262 | } 263 | 264 | func (p *ParseContext) matchedCmd(cmd *CmdClause) { 265 | p.Elements = append(p.Elements, &ParseElement{Clause: cmd}) 266 | p.mergeFlags(cmd.flagGroup) 267 | p.mergeArgs(cmd.argGroup) 268 | p.SelectedCommand = cmd 269 | } 270 | 271 | // Expand arguments from a file. Lines starting with # will be treated as comments. 272 | func ExpandArgsFromFile(filename string) (out []string, err error) { 273 | if filename == "" { 274 | return nil, fmt.Errorf("expected @ file to expand arguments from") 275 | } 276 | r, err := os.Open(filename) 277 | if err != nil { 278 | return nil, fmt.Errorf("failed to open arguments file %q: %s", filename, err) 279 | } 280 | defer r.Close() 281 | scanner := bufio.NewScanner(r) 282 | for scanner.Scan() { 283 | line := scanner.Text() 284 | if strings.HasPrefix(line, "#") { 285 | continue 286 | } 287 | out = append(out, line) 288 | } 289 | err = scanner.Err() 290 | if err != nil { 291 | return nil, fmt.Errorf("failed to read arguments from %q: %s", filename, err) 292 | } 293 | return 294 | } 295 | 296 | func parse(context *ParseContext, app *Application) (err error) { 297 | context.mergeFlags(app.flagGroup) 298 | context.mergeArgs(app.argGroup) 299 | 300 | cmds := app.cmdGroup 301 | ignoreDefault := context.ignoreDefault 302 | 303 | loop: 304 | for !context.EOL() && !context.Error() { 305 | token := context.Peek() 306 | 307 | switch token.Type { 308 | case TokenLong, TokenShort: 309 | if flag, err := context.flags.parse(context); err != nil { 310 | if !ignoreDefault { 311 | if cmd := cmds.defaultSubcommand(); cmd != nil { 312 | cmd.completionAlts = cmds.cmdNames() 313 | context.matchedCmd(cmd) 314 | cmds = cmd.cmdGroup 315 | break 316 | } 317 | } 318 | return err 319 | } else if flag == HelpFlag { 320 | ignoreDefault = true 321 | } 322 | 323 | case TokenArg: 324 | if cmds.have() { 325 | selectedDefault := false 326 | cmd, ok := cmds.commands[token.String()] 327 | if !ok { 328 | if !ignoreDefault { 329 | if cmd = cmds.defaultSubcommand(); cmd != nil { 330 | cmd.completionAlts = cmds.cmdNames() 331 | selectedDefault = true 332 | } 333 | } 334 | if cmd == nil { 335 | return fmt.Errorf("expected command but got %q", token) 336 | } 337 | } 338 | if cmd == HelpCommand { 339 | ignoreDefault = true 340 | } 341 | cmd.completionAlts = nil 342 | context.matchedCmd(cmd) 343 | cmds = cmd.cmdGroup 344 | if !selectedDefault { 345 | context.Next() 346 | } 347 | } else if context.arguments.have() { 348 | if app.noInterspersed { 349 | // no more flags 350 | context.argsOnly = true 351 | } 352 | arg := context.nextArg() 353 | if arg == nil { 354 | break loop 355 | } 356 | context.matchedArg(arg, token.String()) 357 | context.Next() 358 | } else { 359 | break loop 360 | } 361 | 362 | case TokenEOL: 363 | break loop 364 | } 365 | } 366 | 367 | // Move to innermost default command. 368 | for !ignoreDefault { 369 | if cmd := cmds.defaultSubcommand(); cmd != nil { 370 | cmd.completionAlts = cmds.cmdNames() 371 | context.matchedCmd(cmd) 372 | cmds = cmd.cmdGroup 373 | } else { 374 | break 375 | } 376 | } 377 | 378 | if context.Error() { 379 | return fmt.Errorf("%s", context.Peek().Value) 380 | } 381 | 382 | if !context.EOL() { 383 | return fmt.Errorf("unexpected %s", context.Peek()) 384 | } 385 | 386 | // Set defaults for all remaining args. 387 | for arg := context.nextArg(); arg != nil && !arg.consumesRemainder(); arg = context.nextArg() { 388 | for _, defaultValue := range arg.defaultValues { 389 | if err := arg.value.Set(defaultValue); err != nil { 390 | return fmt.Errorf("invalid default value '%s' for argument '%s'", defaultValue, arg.name) 391 | } 392 | } 393 | } 394 | 395 | return 396 | } 397 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/values.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | //go:generate go run ./cmd/genvalues/main.go 4 | 5 | import ( 6 | "fmt" 7 | "net" 8 | "net/url" 9 | "os" 10 | "reflect" 11 | "regexp" 12 | "strings" 13 | "time" 14 | 15 | "github.com/alecthomas/units" 16 | ) 17 | 18 | // NOTE: Most of the base type values were lifted from: 19 | // http://golang.org/src/pkg/flag/flag.go?s=20146:20222 20 | 21 | // Value is the interface to the dynamic value stored in a flag. 22 | // (The default value is represented as a string.) 23 | // 24 | // If a Value has an IsBoolFlag() bool method returning true, the command-line 25 | // parser makes --name equivalent to -name=true rather than using the next 26 | // command-line argument, and adds a --no-name counterpart for negating the 27 | // flag. 28 | type Value interface { 29 | String() string 30 | Set(string) error 31 | } 32 | 33 | // Getter is an interface that allows the contents of a Value to be retrieved. 34 | // It wraps the Value interface, rather than being part of it, because it 35 | // appeared after Go 1 and its compatibility rules. All Value types provided 36 | // by this package satisfy the Getter interface. 37 | type Getter interface { 38 | Value 39 | Get() interface{} 40 | } 41 | 42 | // Optional interface to indicate boolean flags that don't accept a value, and 43 | // implicitly have a --no- negation counterpart. 44 | type boolFlag interface { 45 | Value 46 | IsBoolFlag() bool 47 | } 48 | 49 | // Optional interface for arguments that cumulatively consume all remaining 50 | // input. 51 | type remainderArg interface { 52 | Value 53 | IsCumulative() bool 54 | } 55 | 56 | // Optional interface for flags that can be repeated. 57 | type repeatableFlag interface { 58 | Value 59 | IsCumulative() bool 60 | } 61 | 62 | type accumulator struct { 63 | element func(value interface{}) Value 64 | typ reflect.Type 65 | slice reflect.Value 66 | } 67 | 68 | // Use reflection to accumulate values into a slice. 69 | // 70 | // target := []string{} 71 | // newAccumulator(&target, func (value interface{}) Value { 72 | // return newStringValue(value.(*string)) 73 | // }) 74 | func newAccumulator(slice interface{}, element func(value interface{}) Value) *accumulator { 75 | typ := reflect.TypeOf(slice) 76 | if typ.Kind() != reflect.Ptr || typ.Elem().Kind() != reflect.Slice { 77 | panic("expected a pointer to a slice") 78 | } 79 | return &accumulator{ 80 | element: element, 81 | typ: typ.Elem().Elem(), 82 | slice: reflect.ValueOf(slice), 83 | } 84 | } 85 | 86 | func (a *accumulator) String() string { 87 | out := []string{} 88 | s := a.slice.Elem() 89 | for i := 0; i < s.Len(); i++ { 90 | out = append(out, a.element(s.Index(i).Addr().Interface()).String()) 91 | } 92 | return strings.Join(out, ",") 93 | } 94 | 95 | func (a *accumulator) Set(value string) error { 96 | e := reflect.New(a.typ) 97 | if err := a.element(e.Interface()).Set(value); err != nil { 98 | return err 99 | } 100 | slice := reflect.Append(a.slice.Elem(), e.Elem()) 101 | a.slice.Elem().Set(slice) 102 | return nil 103 | } 104 | 105 | func (a *accumulator) Get() interface{} { 106 | return a.slice.Interface() 107 | } 108 | 109 | func (a *accumulator) IsCumulative() bool { 110 | return true 111 | } 112 | 113 | func (b *boolValue) IsBoolFlag() bool { return true } 114 | 115 | // -- time.Duration Value 116 | type durationValue time.Duration 117 | 118 | func newDurationValue(p *time.Duration) *durationValue { 119 | return (*durationValue)(p) 120 | } 121 | 122 | func (d *durationValue) Set(s string) error { 123 | v, err := time.ParseDuration(s) 124 | *d = durationValue(v) 125 | return err 126 | } 127 | 128 | func (d *durationValue) Get() interface{} { return time.Duration(*d) } 129 | 130 | func (d *durationValue) String() string { return (*time.Duration)(d).String() } 131 | 132 | // -- map[string]string Value 133 | type stringMapValue map[string]string 134 | 135 | func newStringMapValue(p *map[string]string) *stringMapValue { 136 | return (*stringMapValue)(p) 137 | } 138 | 139 | var stringMapRegex = regexp.MustCompile("[:=]") 140 | 141 | func (s *stringMapValue) Set(value string) error { 142 | parts := stringMapRegex.Split(value, 2) 143 | if len(parts) != 2 { 144 | return fmt.Errorf("expected KEY=VALUE got '%s'", value) 145 | } 146 | (*s)[parts[0]] = parts[1] 147 | return nil 148 | } 149 | 150 | func (s *stringMapValue) Get() interface{} { 151 | return (map[string]string)(*s) 152 | } 153 | 154 | func (s *stringMapValue) String() string { 155 | return fmt.Sprintf("%s", map[string]string(*s)) 156 | } 157 | 158 | func (s *stringMapValue) IsCumulative() bool { 159 | return true 160 | } 161 | 162 | // -- net.IP Value 163 | type ipValue net.IP 164 | 165 | func newIPValue(p *net.IP) *ipValue { 166 | return (*ipValue)(p) 167 | } 168 | 169 | func (i *ipValue) Set(value string) error { 170 | if ip := net.ParseIP(value); ip == nil { 171 | return fmt.Errorf("'%s' is not an IP address", value) 172 | } else { 173 | *i = *(*ipValue)(&ip) 174 | return nil 175 | } 176 | } 177 | 178 | func (i *ipValue) Get() interface{} { 179 | return (net.IP)(*i) 180 | } 181 | 182 | func (i *ipValue) String() string { 183 | return (*net.IP)(i).String() 184 | } 185 | 186 | // -- *net.TCPAddr Value 187 | type tcpAddrValue struct { 188 | addr **net.TCPAddr 189 | } 190 | 191 | func newTCPAddrValue(p **net.TCPAddr) *tcpAddrValue { 192 | return &tcpAddrValue{p} 193 | } 194 | 195 | func (i *tcpAddrValue) Set(value string) error { 196 | if addr, err := net.ResolveTCPAddr("tcp", value); err != nil { 197 | return fmt.Errorf("'%s' is not a valid TCP address: %s", value, err) 198 | } else { 199 | *i.addr = addr 200 | return nil 201 | } 202 | } 203 | 204 | func (t *tcpAddrValue) Get() interface{} { 205 | return (*net.TCPAddr)(*t.addr) 206 | } 207 | 208 | func (i *tcpAddrValue) String() string { 209 | return (*i.addr).String() 210 | } 211 | 212 | // -- existingFile Value 213 | 214 | type fileStatValue struct { 215 | path *string 216 | predicate func(os.FileInfo) error 217 | } 218 | 219 | func newFileStatValue(p *string, predicate func(os.FileInfo) error) *fileStatValue { 220 | return &fileStatValue{ 221 | path: p, 222 | predicate: predicate, 223 | } 224 | } 225 | 226 | func (e *fileStatValue) Set(value string) error { 227 | if s, err := os.Stat(value); os.IsNotExist(err) { 228 | return fmt.Errorf("path '%s' does not exist", value) 229 | } else if err != nil { 230 | return err 231 | } else if err := e.predicate(s); err != nil { 232 | return err 233 | } 234 | *e.path = value 235 | return nil 236 | } 237 | 238 | func (f *fileStatValue) Get() interface{} { 239 | return (string)(*f.path) 240 | } 241 | 242 | func (e *fileStatValue) String() string { 243 | return *e.path 244 | } 245 | 246 | // -- os.File value 247 | 248 | type fileValue struct { 249 | f **os.File 250 | flag int 251 | perm os.FileMode 252 | } 253 | 254 | func newFileValue(p **os.File, flag int, perm os.FileMode) *fileValue { 255 | return &fileValue{p, flag, perm} 256 | } 257 | 258 | func (f *fileValue) Set(value string) error { 259 | if fd, err := os.OpenFile(value, f.flag, f.perm); err != nil { 260 | return err 261 | } else { 262 | *f.f = fd 263 | return nil 264 | } 265 | } 266 | 267 | func (f *fileValue) Get() interface{} { 268 | return (*os.File)(*f.f) 269 | } 270 | 271 | func (f *fileValue) String() string { 272 | if *f.f == nil { 273 | return "" 274 | } 275 | return (*f.f).Name() 276 | } 277 | 278 | // -- url.URL Value 279 | type urlValue struct { 280 | u **url.URL 281 | } 282 | 283 | func newURLValue(p **url.URL) *urlValue { 284 | return &urlValue{p} 285 | } 286 | 287 | func (u *urlValue) Set(value string) error { 288 | if url, err := url.Parse(value); err != nil { 289 | return fmt.Errorf("invalid URL: %s", err) 290 | } else { 291 | *u.u = url 292 | return nil 293 | } 294 | } 295 | 296 | func (u *urlValue) Get() interface{} { 297 | return (*url.URL)(*u.u) 298 | } 299 | 300 | func (u *urlValue) String() string { 301 | if *u.u == nil { 302 | return "" 303 | } 304 | return (*u.u).String() 305 | } 306 | 307 | // -- []*url.URL Value 308 | type urlListValue []*url.URL 309 | 310 | func newURLListValue(p *[]*url.URL) *urlListValue { 311 | return (*urlListValue)(p) 312 | } 313 | 314 | func (u *urlListValue) Set(value string) error { 315 | if url, err := url.Parse(value); err != nil { 316 | return fmt.Errorf("invalid URL: %s", err) 317 | } else { 318 | *u = append(*u, url) 319 | return nil 320 | } 321 | } 322 | 323 | func (u *urlListValue) Get() interface{} { 324 | return ([]*url.URL)(*u) 325 | } 326 | 327 | func (u *urlListValue) String() string { 328 | out := []string{} 329 | for _, url := range *u { 330 | out = append(out, url.String()) 331 | } 332 | return strings.Join(out, ",") 333 | } 334 | 335 | func (u *urlListValue) IsCumulative() bool { 336 | return true 337 | } 338 | 339 | // A flag whose value must be in a set of options. 340 | type enumValue struct { 341 | value *string 342 | options []string 343 | } 344 | 345 | func newEnumFlag(target *string, options ...string) *enumValue { 346 | return &enumValue{ 347 | value: target, 348 | options: options, 349 | } 350 | } 351 | 352 | func (a *enumValue) String() string { 353 | return *a.value 354 | } 355 | 356 | func (a *enumValue) Set(value string) error { 357 | for _, v := range a.options { 358 | if v == value { 359 | *a.value = value 360 | return nil 361 | } 362 | } 363 | return fmt.Errorf("enum value must be one of %s, got '%s'", strings.Join(a.options, ","), value) 364 | } 365 | 366 | func (e *enumValue) Get() interface{} { 367 | return (string)(*e.value) 368 | } 369 | 370 | // -- []string Enum Value 371 | type enumsValue struct { 372 | value *[]string 373 | options []string 374 | } 375 | 376 | func newEnumsFlag(target *[]string, options ...string) *enumsValue { 377 | return &enumsValue{ 378 | value: target, 379 | options: options, 380 | } 381 | } 382 | 383 | func (s *enumsValue) Set(value string) error { 384 | for _, v := range s.options { 385 | if v == value { 386 | *s.value = append(*s.value, value) 387 | return nil 388 | } 389 | } 390 | return fmt.Errorf("enum value must be one of %s, got '%s'", strings.Join(s.options, ","), value) 391 | } 392 | 393 | func (e *enumsValue) Get() interface{} { 394 | return ([]string)(*e.value) 395 | } 396 | 397 | func (s *enumsValue) String() string { 398 | return strings.Join(*s.value, ",") 399 | } 400 | 401 | func (s *enumsValue) IsCumulative() bool { 402 | return true 403 | } 404 | 405 | // -- units.Base2Bytes Value 406 | type bytesValue units.Base2Bytes 407 | 408 | func newBytesValue(p *units.Base2Bytes) *bytesValue { 409 | return (*bytesValue)(p) 410 | } 411 | 412 | func (d *bytesValue) Set(s string) error { 413 | v, err := units.ParseBase2Bytes(s) 414 | *d = bytesValue(v) 415 | return err 416 | } 417 | 418 | func (d *bytesValue) Get() interface{} { return units.Base2Bytes(*d) } 419 | 420 | func (d *bytesValue) String() string { return (*units.Base2Bytes)(d).String() } 421 | 422 | func newExistingFileValue(target *string) *fileStatValue { 423 | return newFileStatValue(target, func(s os.FileInfo) error { 424 | if s.IsDir() { 425 | return fmt.Errorf("'%s' is a directory", s.Name()) 426 | } 427 | return nil 428 | }) 429 | } 430 | 431 | func newExistingDirValue(target *string) *fileStatValue { 432 | return newFileStatValue(target, func(s os.FileInfo) error { 433 | if !s.IsDir() { 434 | return fmt.Errorf("'%s' is a file", s.Name()) 435 | } 436 | return nil 437 | }) 438 | } 439 | 440 | func newExistingFileOrDirValue(target *string) *fileStatValue { 441 | return newFileStatValue(target, func(s os.FileInfo) error { return nil }) 442 | } 443 | 444 | type counterValue int 445 | 446 | func newCounterValue(n *int) *counterValue { 447 | return (*counterValue)(n) 448 | } 449 | 450 | func (c *counterValue) Set(s string) error { 451 | *c++ 452 | return nil 453 | } 454 | 455 | func (c *counterValue) Get() interface{} { return (int)(*c) } 456 | func (c *counterValue) IsBoolFlag() bool { return true } 457 | func (c *counterValue) String() string { return fmt.Sprintf("%d", *c) } 458 | func (c *counterValue) IsCumulative() bool { return true } 459 | 460 | func resolveHost(value string) (net.IP, error) { 461 | if ip := net.ParseIP(value); ip != nil { 462 | return ip, nil 463 | } else { 464 | if addr, err := net.ResolveIPAddr("ip", value); err != nil { 465 | return nil, err 466 | } else { 467 | return addr.IP, nil 468 | } 469 | } 470 | } 471 | -------------------------------------------------------------------------------- /vendor/github.com/alecthomas/template/parse/lex.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package parse 6 | 7 | import ( 8 | "fmt" 9 | "strings" 10 | "unicode" 11 | "unicode/utf8" 12 | ) 13 | 14 | // item represents a token or text string returned from the scanner. 15 | type item struct { 16 | typ itemType // The type of this item. 17 | pos Pos // The starting position, in bytes, of this item in the input string. 18 | val string // The value of this item. 19 | } 20 | 21 | func (i item) String() string { 22 | switch { 23 | case i.typ == itemEOF: 24 | return "EOF" 25 | case i.typ == itemError: 26 | return i.val 27 | case i.typ > itemKeyword: 28 | return fmt.Sprintf("<%s>", i.val) 29 | case len(i.val) > 10: 30 | return fmt.Sprintf("%.10q...", i.val) 31 | } 32 | return fmt.Sprintf("%q", i.val) 33 | } 34 | 35 | // itemType identifies the type of lex items. 36 | type itemType int 37 | 38 | const ( 39 | itemError itemType = iota // error occurred; value is text of error 40 | itemBool // boolean constant 41 | itemChar // printable ASCII character; grab bag for comma etc. 42 | itemCharConstant // character constant 43 | itemComplex // complex constant (1+2i); imaginary is just a number 44 | itemColonEquals // colon-equals (':=') introducing a declaration 45 | itemEOF 46 | itemField // alphanumeric identifier starting with '.' 47 | itemIdentifier // alphanumeric identifier not starting with '.' 48 | itemLeftDelim // left action delimiter 49 | itemLeftParen // '(' inside action 50 | itemNumber // simple number, including imaginary 51 | itemPipe // pipe symbol 52 | itemRawString // raw quoted string (includes quotes) 53 | itemRightDelim // right action delimiter 54 | itemElideNewline // elide newline after right delim 55 | itemRightParen // ')' inside action 56 | itemSpace // run of spaces separating arguments 57 | itemString // quoted string (includes quotes) 58 | itemText // plain text 59 | itemVariable // variable starting with '$', such as '$' or '$1' or '$hello' 60 | // Keywords appear after all the rest. 61 | itemKeyword // used only to delimit the keywords 62 | itemDot // the cursor, spelled '.' 63 | itemDefine // define keyword 64 | itemElse // else keyword 65 | itemEnd // end keyword 66 | itemIf // if keyword 67 | itemNil // the untyped nil constant, easiest to treat as a keyword 68 | itemRange // range keyword 69 | itemTemplate // template keyword 70 | itemWith // with keyword 71 | ) 72 | 73 | var key = map[string]itemType{ 74 | ".": itemDot, 75 | "define": itemDefine, 76 | "else": itemElse, 77 | "end": itemEnd, 78 | "if": itemIf, 79 | "range": itemRange, 80 | "nil": itemNil, 81 | "template": itemTemplate, 82 | "with": itemWith, 83 | } 84 | 85 | const eof = -1 86 | 87 | // stateFn represents the state of the scanner as a function that returns the next state. 88 | type stateFn func(*lexer) stateFn 89 | 90 | // lexer holds the state of the scanner. 91 | type lexer struct { 92 | name string // the name of the input; used only for error reports 93 | input string // the string being scanned 94 | leftDelim string // start of action 95 | rightDelim string // end of action 96 | state stateFn // the next lexing function to enter 97 | pos Pos // current position in the input 98 | start Pos // start position of this item 99 | width Pos // width of last rune read from input 100 | lastPos Pos // position of most recent item returned by nextItem 101 | items chan item // channel of scanned items 102 | parenDepth int // nesting depth of ( ) exprs 103 | } 104 | 105 | // next returns the next rune in the input. 106 | func (l *lexer) next() rune { 107 | if int(l.pos) >= len(l.input) { 108 | l.width = 0 109 | return eof 110 | } 111 | r, w := utf8.DecodeRuneInString(l.input[l.pos:]) 112 | l.width = Pos(w) 113 | l.pos += l.width 114 | return r 115 | } 116 | 117 | // peek returns but does not consume the next rune in the input. 118 | func (l *lexer) peek() rune { 119 | r := l.next() 120 | l.backup() 121 | return r 122 | } 123 | 124 | // backup steps back one rune. Can only be called once per call of next. 125 | func (l *lexer) backup() { 126 | l.pos -= l.width 127 | } 128 | 129 | // emit passes an item back to the client. 130 | func (l *lexer) emit(t itemType) { 131 | l.items <- item{t, l.start, l.input[l.start:l.pos]} 132 | l.start = l.pos 133 | } 134 | 135 | // ignore skips over the pending input before this point. 136 | func (l *lexer) ignore() { 137 | l.start = l.pos 138 | } 139 | 140 | // accept consumes the next rune if it's from the valid set. 141 | func (l *lexer) accept(valid string) bool { 142 | if strings.IndexRune(valid, l.next()) >= 0 { 143 | return true 144 | } 145 | l.backup() 146 | return false 147 | } 148 | 149 | // acceptRun consumes a run of runes from the valid set. 150 | func (l *lexer) acceptRun(valid string) { 151 | for strings.IndexRune(valid, l.next()) >= 0 { 152 | } 153 | l.backup() 154 | } 155 | 156 | // lineNumber reports which line we're on, based on the position of 157 | // the previous item returned by nextItem. Doing it this way 158 | // means we don't have to worry about peek double counting. 159 | func (l *lexer) lineNumber() int { 160 | return 1 + strings.Count(l.input[:l.lastPos], "\n") 161 | } 162 | 163 | // errorf returns an error token and terminates the scan by passing 164 | // back a nil pointer that will be the next state, terminating l.nextItem. 165 | func (l *lexer) errorf(format string, args ...interface{}) stateFn { 166 | l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)} 167 | return nil 168 | } 169 | 170 | // nextItem returns the next item from the input. 171 | func (l *lexer) nextItem() item { 172 | item := <-l.items 173 | l.lastPos = item.pos 174 | return item 175 | } 176 | 177 | // lex creates a new scanner for the input string. 178 | func lex(name, input, left, right string) *lexer { 179 | if left == "" { 180 | left = leftDelim 181 | } 182 | if right == "" { 183 | right = rightDelim 184 | } 185 | l := &lexer{ 186 | name: name, 187 | input: input, 188 | leftDelim: left, 189 | rightDelim: right, 190 | items: make(chan item), 191 | } 192 | go l.run() 193 | return l 194 | } 195 | 196 | // run runs the state machine for the lexer. 197 | func (l *lexer) run() { 198 | for l.state = lexText; l.state != nil; { 199 | l.state = l.state(l) 200 | } 201 | } 202 | 203 | // state functions 204 | 205 | const ( 206 | leftDelim = "{{" 207 | rightDelim = "}}" 208 | leftComment = "/*" 209 | rightComment = "*/" 210 | ) 211 | 212 | // lexText scans until an opening action delimiter, "{{". 213 | func lexText(l *lexer) stateFn { 214 | for { 215 | if strings.HasPrefix(l.input[l.pos:], l.leftDelim) { 216 | if l.pos > l.start { 217 | l.emit(itemText) 218 | } 219 | return lexLeftDelim 220 | } 221 | if l.next() == eof { 222 | break 223 | } 224 | } 225 | // Correctly reached EOF. 226 | if l.pos > l.start { 227 | l.emit(itemText) 228 | } 229 | l.emit(itemEOF) 230 | return nil 231 | } 232 | 233 | // lexLeftDelim scans the left delimiter, which is known to be present. 234 | func lexLeftDelim(l *lexer) stateFn { 235 | l.pos += Pos(len(l.leftDelim)) 236 | if strings.HasPrefix(l.input[l.pos:], leftComment) { 237 | return lexComment 238 | } 239 | l.emit(itemLeftDelim) 240 | l.parenDepth = 0 241 | return lexInsideAction 242 | } 243 | 244 | // lexComment scans a comment. The left comment marker is known to be present. 245 | func lexComment(l *lexer) stateFn { 246 | l.pos += Pos(len(leftComment)) 247 | i := strings.Index(l.input[l.pos:], rightComment) 248 | if i < 0 { 249 | return l.errorf("unclosed comment") 250 | } 251 | l.pos += Pos(i + len(rightComment)) 252 | if !strings.HasPrefix(l.input[l.pos:], l.rightDelim) { 253 | return l.errorf("comment ends before closing delimiter") 254 | 255 | } 256 | l.pos += Pos(len(l.rightDelim)) 257 | l.ignore() 258 | return lexText 259 | } 260 | 261 | // lexRightDelim scans the right delimiter, which is known to be present. 262 | func lexRightDelim(l *lexer) stateFn { 263 | l.pos += Pos(len(l.rightDelim)) 264 | l.emit(itemRightDelim) 265 | if l.peek() == '\\' { 266 | l.pos++ 267 | l.emit(itemElideNewline) 268 | } 269 | return lexText 270 | } 271 | 272 | // lexInsideAction scans the elements inside action delimiters. 273 | func lexInsideAction(l *lexer) stateFn { 274 | // Either number, quoted string, or identifier. 275 | // Spaces separate arguments; runs of spaces turn into itemSpace. 276 | // Pipe symbols separate and are emitted. 277 | if strings.HasPrefix(l.input[l.pos:], l.rightDelim+"\\") || strings.HasPrefix(l.input[l.pos:], l.rightDelim) { 278 | if l.parenDepth == 0 { 279 | return lexRightDelim 280 | } 281 | return l.errorf("unclosed left paren") 282 | } 283 | switch r := l.next(); { 284 | case r == eof || isEndOfLine(r): 285 | return l.errorf("unclosed action") 286 | case isSpace(r): 287 | return lexSpace 288 | case r == ':': 289 | if l.next() != '=' { 290 | return l.errorf("expected :=") 291 | } 292 | l.emit(itemColonEquals) 293 | case r == '|': 294 | l.emit(itemPipe) 295 | case r == '"': 296 | return lexQuote 297 | case r == '`': 298 | return lexRawQuote 299 | case r == '$': 300 | return lexVariable 301 | case r == '\'': 302 | return lexChar 303 | case r == '.': 304 | // special look-ahead for ".field" so we don't break l.backup(). 305 | if l.pos < Pos(len(l.input)) { 306 | r := l.input[l.pos] 307 | if r < '0' || '9' < r { 308 | return lexField 309 | } 310 | } 311 | fallthrough // '.' can start a number. 312 | case r == '+' || r == '-' || ('0' <= r && r <= '9'): 313 | l.backup() 314 | return lexNumber 315 | case isAlphaNumeric(r): 316 | l.backup() 317 | return lexIdentifier 318 | case r == '(': 319 | l.emit(itemLeftParen) 320 | l.parenDepth++ 321 | return lexInsideAction 322 | case r == ')': 323 | l.emit(itemRightParen) 324 | l.parenDepth-- 325 | if l.parenDepth < 0 { 326 | return l.errorf("unexpected right paren %#U", r) 327 | } 328 | return lexInsideAction 329 | case r <= unicode.MaxASCII && unicode.IsPrint(r): 330 | l.emit(itemChar) 331 | return lexInsideAction 332 | default: 333 | return l.errorf("unrecognized character in action: %#U", r) 334 | } 335 | return lexInsideAction 336 | } 337 | 338 | // lexSpace scans a run of space characters. 339 | // One space has already been seen. 340 | func lexSpace(l *lexer) stateFn { 341 | for isSpace(l.peek()) { 342 | l.next() 343 | } 344 | l.emit(itemSpace) 345 | return lexInsideAction 346 | } 347 | 348 | // lexIdentifier scans an alphanumeric. 349 | func lexIdentifier(l *lexer) stateFn { 350 | Loop: 351 | for { 352 | switch r := l.next(); { 353 | case isAlphaNumeric(r): 354 | // absorb. 355 | default: 356 | l.backup() 357 | word := l.input[l.start:l.pos] 358 | if !l.atTerminator() { 359 | return l.errorf("bad character %#U", r) 360 | } 361 | switch { 362 | case key[word] > itemKeyword: 363 | l.emit(key[word]) 364 | case word[0] == '.': 365 | l.emit(itemField) 366 | case word == "true", word == "false": 367 | l.emit(itemBool) 368 | default: 369 | l.emit(itemIdentifier) 370 | } 371 | break Loop 372 | } 373 | } 374 | return lexInsideAction 375 | } 376 | 377 | // lexField scans a field: .Alphanumeric. 378 | // The . has been scanned. 379 | func lexField(l *lexer) stateFn { 380 | return lexFieldOrVariable(l, itemField) 381 | } 382 | 383 | // lexVariable scans a Variable: $Alphanumeric. 384 | // The $ has been scanned. 385 | func lexVariable(l *lexer) stateFn { 386 | if l.atTerminator() { // Nothing interesting follows -> "$". 387 | l.emit(itemVariable) 388 | return lexInsideAction 389 | } 390 | return lexFieldOrVariable(l, itemVariable) 391 | } 392 | 393 | // lexVariable scans a field or variable: [.$]Alphanumeric. 394 | // The . or $ has been scanned. 395 | func lexFieldOrVariable(l *lexer, typ itemType) stateFn { 396 | if l.atTerminator() { // Nothing interesting follows -> "." or "$". 397 | if typ == itemVariable { 398 | l.emit(itemVariable) 399 | } else { 400 | l.emit(itemDot) 401 | } 402 | return lexInsideAction 403 | } 404 | var r rune 405 | for { 406 | r = l.next() 407 | if !isAlphaNumeric(r) { 408 | l.backup() 409 | break 410 | } 411 | } 412 | if !l.atTerminator() { 413 | return l.errorf("bad character %#U", r) 414 | } 415 | l.emit(typ) 416 | return lexInsideAction 417 | } 418 | 419 | // atTerminator reports whether the input is at valid termination character to 420 | // appear after an identifier. Breaks .X.Y into two pieces. Also catches cases 421 | // like "$x+2" not being acceptable without a space, in case we decide one 422 | // day to implement arithmetic. 423 | func (l *lexer) atTerminator() bool { 424 | r := l.peek() 425 | if isSpace(r) || isEndOfLine(r) { 426 | return true 427 | } 428 | switch r { 429 | case eof, '.', ',', '|', ':', ')', '(': 430 | return true 431 | } 432 | // Does r start the delimiter? This can be ambiguous (with delim=="//", $x/2 will 433 | // succeed but should fail) but only in extremely rare cases caused by willfully 434 | // bad choice of delimiter. 435 | if rd, _ := utf8.DecodeRuneInString(l.rightDelim); rd == r { 436 | return true 437 | } 438 | return false 439 | } 440 | 441 | // lexChar scans a character constant. The initial quote is already 442 | // scanned. Syntax checking is done by the parser. 443 | func lexChar(l *lexer) stateFn { 444 | Loop: 445 | for { 446 | switch l.next() { 447 | case '\\': 448 | if r := l.next(); r != eof && r != '\n' { 449 | break 450 | } 451 | fallthrough 452 | case eof, '\n': 453 | return l.errorf("unterminated character constant") 454 | case '\'': 455 | break Loop 456 | } 457 | } 458 | l.emit(itemCharConstant) 459 | return lexInsideAction 460 | } 461 | 462 | // lexNumber scans a number: decimal, octal, hex, float, or imaginary. This 463 | // isn't a perfect number scanner - for instance it accepts "." and "0x0.2" 464 | // and "089" - but when it's wrong the input is invalid and the parser (via 465 | // strconv) will notice. 466 | func lexNumber(l *lexer) stateFn { 467 | if !l.scanNumber() { 468 | return l.errorf("bad number syntax: %q", l.input[l.start:l.pos]) 469 | } 470 | if sign := l.peek(); sign == '+' || sign == '-' { 471 | // Complex: 1+2i. No spaces, must end in 'i'. 472 | if !l.scanNumber() || l.input[l.pos-1] != 'i' { 473 | return l.errorf("bad number syntax: %q", l.input[l.start:l.pos]) 474 | } 475 | l.emit(itemComplex) 476 | } else { 477 | l.emit(itemNumber) 478 | } 479 | return lexInsideAction 480 | } 481 | 482 | func (l *lexer) scanNumber() bool { 483 | // Optional leading sign. 484 | l.accept("+-") 485 | // Is it hex? 486 | digits := "0123456789" 487 | if l.accept("0") && l.accept("xX") { 488 | digits = "0123456789abcdefABCDEF" 489 | } 490 | l.acceptRun(digits) 491 | if l.accept(".") { 492 | l.acceptRun(digits) 493 | } 494 | if l.accept("eE") { 495 | l.accept("+-") 496 | l.acceptRun("0123456789") 497 | } 498 | // Is it imaginary? 499 | l.accept("i") 500 | // Next thing mustn't be alphanumeric. 501 | if isAlphaNumeric(l.peek()) { 502 | l.next() 503 | return false 504 | } 505 | return true 506 | } 507 | 508 | // lexQuote scans a quoted string. 509 | func lexQuote(l *lexer) stateFn { 510 | Loop: 511 | for { 512 | switch l.next() { 513 | case '\\': 514 | if r := l.next(); r != eof && r != '\n' { 515 | break 516 | } 517 | fallthrough 518 | case eof, '\n': 519 | return l.errorf("unterminated quoted string") 520 | case '"': 521 | break Loop 522 | } 523 | } 524 | l.emit(itemString) 525 | return lexInsideAction 526 | } 527 | 528 | // lexRawQuote scans a raw quoted string. 529 | func lexRawQuote(l *lexer) stateFn { 530 | Loop: 531 | for { 532 | switch l.next() { 533 | case eof, '\n': 534 | return l.errorf("unterminated raw quoted string") 535 | case '`': 536 | break Loop 537 | } 538 | } 539 | l.emit(itemRawString) 540 | return lexInsideAction 541 | } 542 | 543 | // isSpace reports whether r is a space character. 544 | func isSpace(r rune) bool { 545 | return r == ' ' || r == '\t' 546 | } 547 | 548 | // isEndOfLine reports whether r is an end-of-line character. 549 | func isEndOfLine(r rune) bool { 550 | return r == '\r' || r == '\n' 551 | } 552 | 553 | // isAlphaNumeric reports whether r is an alphabetic, digit, or underscore. 554 | func isAlphaNumeric(r rune) bool { 555 | return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) 556 | } 557 | -------------------------------------------------------------------------------- /vendor/github.com/alecthomas/template/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Package template implements data-driven templates for generating textual output. 7 | 8 | To generate HTML output, see package html/template, which has the same interface 9 | as this package but automatically secures HTML output against certain attacks. 10 | 11 | Templates are executed by applying them to a data structure. Annotations in the 12 | template refer to elements of the data structure (typically a field of a struct 13 | or a key in a map) to control execution and derive values to be displayed. 14 | Execution of the template walks the structure and sets the cursor, represented 15 | by a period '.' and called "dot", to the value at the current location in the 16 | structure as execution proceeds. 17 | 18 | The input text for a template is UTF-8-encoded text in any format. 19 | "Actions"--data evaluations or control structures--are delimited by 20 | "{{" and "}}"; all text outside actions is copied to the output unchanged. 21 | Actions may not span newlines, although comments can. 22 | 23 | Once parsed, a template may be executed safely in parallel. 24 | 25 | Here is a trivial example that prints "17 items are made of wool". 26 | 27 | type Inventory struct { 28 | Material string 29 | Count uint 30 | } 31 | sweaters := Inventory{"wool", 17} 32 | tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}") 33 | if err != nil { panic(err) } 34 | err = tmpl.Execute(os.Stdout, sweaters) 35 | if err != nil { panic(err) } 36 | 37 | More intricate examples appear below. 38 | 39 | Actions 40 | 41 | Here is the list of actions. "Arguments" and "pipelines" are evaluations of 42 | data, defined in detail below. 43 | 44 | */ 45 | // {{/* a comment */}} 46 | // A comment; discarded. May contain newlines. 47 | // Comments do not nest and must start and end at the 48 | // delimiters, as shown here. 49 | /* 50 | 51 | {{pipeline}} 52 | The default textual representation of the value of the pipeline 53 | is copied to the output. 54 | 55 | {{if pipeline}} T1 {{end}} 56 | If the value of the pipeline is empty, no output is generated; 57 | otherwise, T1 is executed. The empty values are false, 0, any 58 | nil pointer or interface value, and any array, slice, map, or 59 | string of length zero. 60 | Dot is unaffected. 61 | 62 | {{if pipeline}} T1 {{else}} T0 {{end}} 63 | If the value of the pipeline is empty, T0 is executed; 64 | otherwise, T1 is executed. Dot is unaffected. 65 | 66 | {{if pipeline}} T1 {{else if pipeline}} T0 {{end}} 67 | To simplify the appearance of if-else chains, the else action 68 | of an if may include another if directly; the effect is exactly 69 | the same as writing 70 | {{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}} 71 | 72 | {{range pipeline}} T1 {{end}} 73 | The value of the pipeline must be an array, slice, map, or channel. 74 | If the value of the pipeline has length zero, nothing is output; 75 | otherwise, dot is set to the successive elements of the array, 76 | slice, or map and T1 is executed. If the value is a map and the 77 | keys are of basic type with a defined order ("comparable"), the 78 | elements will be visited in sorted key order. 79 | 80 | {{range pipeline}} T1 {{else}} T0 {{end}} 81 | The value of the pipeline must be an array, slice, map, or channel. 82 | If the value of the pipeline has length zero, dot is unaffected and 83 | T0 is executed; otherwise, dot is set to the successive elements 84 | of the array, slice, or map and T1 is executed. 85 | 86 | {{template "name"}} 87 | The template with the specified name is executed with nil data. 88 | 89 | {{template "name" pipeline}} 90 | The template with the specified name is executed with dot set 91 | to the value of the pipeline. 92 | 93 | {{with pipeline}} T1 {{end}} 94 | If the value of the pipeline is empty, no output is generated; 95 | otherwise, dot is set to the value of the pipeline and T1 is 96 | executed. 97 | 98 | {{with pipeline}} T1 {{else}} T0 {{end}} 99 | If the value of the pipeline is empty, dot is unaffected and T0 100 | is executed; otherwise, dot is set to the value of the pipeline 101 | and T1 is executed. 102 | 103 | Arguments 104 | 105 | An argument is a simple value, denoted by one of the following. 106 | 107 | - A boolean, string, character, integer, floating-point, imaginary 108 | or complex constant in Go syntax. These behave like Go's untyped 109 | constants, although raw strings may not span newlines. 110 | - The keyword nil, representing an untyped Go nil. 111 | - The character '.' (period): 112 | . 113 | The result is the value of dot. 114 | - A variable name, which is a (possibly empty) alphanumeric string 115 | preceded by a dollar sign, such as 116 | $piOver2 117 | or 118 | $ 119 | The result is the value of the variable. 120 | Variables are described below. 121 | - The name of a field of the data, which must be a struct, preceded 122 | by a period, such as 123 | .Field 124 | The result is the value of the field. Field invocations may be 125 | chained: 126 | .Field1.Field2 127 | Fields can also be evaluated on variables, including chaining: 128 | $x.Field1.Field2 129 | - The name of a key of the data, which must be a map, preceded 130 | by a period, such as 131 | .Key 132 | The result is the map element value indexed by the key. 133 | Key invocations may be chained and combined with fields to any 134 | depth: 135 | .Field1.Key1.Field2.Key2 136 | Although the key must be an alphanumeric identifier, unlike with 137 | field names they do not need to start with an upper case letter. 138 | Keys can also be evaluated on variables, including chaining: 139 | $x.key1.key2 140 | - The name of a niladic method of the data, preceded by a period, 141 | such as 142 | .Method 143 | The result is the value of invoking the method with dot as the 144 | receiver, dot.Method(). Such a method must have one return value (of 145 | any type) or two return values, the second of which is an error. 146 | If it has two and the returned error is non-nil, execution terminates 147 | and an error is returned to the caller as the value of Execute. 148 | Method invocations may be chained and combined with fields and keys 149 | to any depth: 150 | .Field1.Key1.Method1.Field2.Key2.Method2 151 | Methods can also be evaluated on variables, including chaining: 152 | $x.Method1.Field 153 | - The name of a niladic function, such as 154 | fun 155 | The result is the value of invoking the function, fun(). The return 156 | types and values behave as in methods. Functions and function 157 | names are described below. 158 | - A parenthesized instance of one the above, for grouping. The result 159 | may be accessed by a field or map key invocation. 160 | print (.F1 arg1) (.F2 arg2) 161 | (.StructValuedMethod "arg").Field 162 | 163 | Arguments may evaluate to any type; if they are pointers the implementation 164 | automatically indirects to the base type when required. 165 | If an evaluation yields a function value, such as a function-valued 166 | field of a struct, the function is not invoked automatically, but it 167 | can be used as a truth value for an if action and the like. To invoke 168 | it, use the call function, defined below. 169 | 170 | A pipeline is a possibly chained sequence of "commands". A command is a simple 171 | value (argument) or a function or method call, possibly with multiple arguments: 172 | 173 | Argument 174 | The result is the value of evaluating the argument. 175 | .Method [Argument...] 176 | The method can be alone or the last element of a chain but, 177 | unlike methods in the middle of a chain, it can take arguments. 178 | The result is the value of calling the method with the 179 | arguments: 180 | dot.Method(Argument1, etc.) 181 | functionName [Argument...] 182 | The result is the value of calling the function associated 183 | with the name: 184 | function(Argument1, etc.) 185 | Functions and function names are described below. 186 | 187 | Pipelines 188 | 189 | A pipeline may be "chained" by separating a sequence of commands with pipeline 190 | characters '|'. In a chained pipeline, the result of the each command is 191 | passed as the last argument of the following command. The output of the final 192 | command in the pipeline is the value of the pipeline. 193 | 194 | The output of a command will be either one value or two values, the second of 195 | which has type error. If that second value is present and evaluates to 196 | non-nil, execution terminates and the error is returned to the caller of 197 | Execute. 198 | 199 | Variables 200 | 201 | A pipeline inside an action may initialize a variable to capture the result. 202 | The initialization has syntax 203 | 204 | $variable := pipeline 205 | 206 | where $variable is the name of the variable. An action that declares a 207 | variable produces no output. 208 | 209 | If a "range" action initializes a variable, the variable is set to the 210 | successive elements of the iteration. Also, a "range" may declare two 211 | variables, separated by a comma: 212 | 213 | range $index, $element := pipeline 214 | 215 | in which case $index and $element are set to the successive values of the 216 | array/slice index or map key and element, respectively. Note that if there is 217 | only one variable, it is assigned the element; this is opposite to the 218 | convention in Go range clauses. 219 | 220 | A variable's scope extends to the "end" action of the control structure ("if", 221 | "with", or "range") in which it is declared, or to the end of the template if 222 | there is no such control structure. A template invocation does not inherit 223 | variables from the point of its invocation. 224 | 225 | When execution begins, $ is set to the data argument passed to Execute, that is, 226 | to the starting value of dot. 227 | 228 | Examples 229 | 230 | Here are some example one-line templates demonstrating pipelines and variables. 231 | All produce the quoted word "output": 232 | 233 | {{"\"output\""}} 234 | A string constant. 235 | {{`"output"`}} 236 | A raw string constant. 237 | {{printf "%q" "output"}} 238 | A function call. 239 | {{"output" | printf "%q"}} 240 | A function call whose final argument comes from the previous 241 | command. 242 | {{printf "%q" (print "out" "put")}} 243 | A parenthesized argument. 244 | {{"put" | printf "%s%s" "out" | printf "%q"}} 245 | A more elaborate call. 246 | {{"output" | printf "%s" | printf "%q"}} 247 | A longer chain. 248 | {{with "output"}}{{printf "%q" .}}{{end}} 249 | A with action using dot. 250 | {{with $x := "output" | printf "%q"}}{{$x}}{{end}} 251 | A with action that creates and uses a variable. 252 | {{with $x := "output"}}{{printf "%q" $x}}{{end}} 253 | A with action that uses the variable in another action. 254 | {{with $x := "output"}}{{$x | printf "%q"}}{{end}} 255 | The same, but pipelined. 256 | 257 | Functions 258 | 259 | During execution functions are found in two function maps: first in the 260 | template, then in the global function map. By default, no functions are defined 261 | in the template but the Funcs method can be used to add them. 262 | 263 | Predefined global functions are named as follows. 264 | 265 | and 266 | Returns the boolean AND of its arguments by returning the 267 | first empty argument or the last argument, that is, 268 | "and x y" behaves as "if x then y else x". All the 269 | arguments are evaluated. 270 | call 271 | Returns the result of calling the first argument, which 272 | must be a function, with the remaining arguments as parameters. 273 | Thus "call .X.Y 1 2" is, in Go notation, dot.X.Y(1, 2) where 274 | Y is a func-valued field, map entry, or the like. 275 | The first argument must be the result of an evaluation 276 | that yields a value of function type (as distinct from 277 | a predefined function such as print). The function must 278 | return either one or two result values, the second of which 279 | is of type error. If the arguments don't match the function 280 | or the returned error value is non-nil, execution stops. 281 | html 282 | Returns the escaped HTML equivalent of the textual 283 | representation of its arguments. 284 | index 285 | Returns the result of indexing its first argument by the 286 | following arguments. Thus "index x 1 2 3" is, in Go syntax, 287 | x[1][2][3]. Each indexed item must be a map, slice, or array. 288 | js 289 | Returns the escaped JavaScript equivalent of the textual 290 | representation of its arguments. 291 | len 292 | Returns the integer length of its argument. 293 | not 294 | Returns the boolean negation of its single argument. 295 | or 296 | Returns the boolean OR of its arguments by returning the 297 | first non-empty argument or the last argument, that is, 298 | "or x y" behaves as "if x then x else y". All the 299 | arguments are evaluated. 300 | print 301 | An alias for fmt.Sprint 302 | printf 303 | An alias for fmt.Sprintf 304 | println 305 | An alias for fmt.Sprintln 306 | urlquery 307 | Returns the escaped value of the textual representation of 308 | its arguments in a form suitable for embedding in a URL query. 309 | 310 | The boolean functions take any zero value to be false and a non-zero 311 | value to be true. 312 | 313 | There is also a set of binary comparison operators defined as 314 | functions: 315 | 316 | eq 317 | Returns the boolean truth of arg1 == arg2 318 | ne 319 | Returns the boolean truth of arg1 != arg2 320 | lt 321 | Returns the boolean truth of arg1 < arg2 322 | le 323 | Returns the boolean truth of arg1 <= arg2 324 | gt 325 | Returns the boolean truth of arg1 > arg2 326 | ge 327 | Returns the boolean truth of arg1 >= arg2 328 | 329 | For simpler multi-way equality tests, eq (only) accepts two or more 330 | arguments and compares the second and subsequent to the first, 331 | returning in effect 332 | 333 | arg1==arg2 || arg1==arg3 || arg1==arg4 ... 334 | 335 | (Unlike with || in Go, however, eq is a function call and all the 336 | arguments will be evaluated.) 337 | 338 | The comparison functions work on basic types only (or named basic 339 | types, such as "type Celsius float32"). They implement the Go rules 340 | for comparison of values, except that size and exact type are 341 | ignored, so any integer value, signed or unsigned, may be compared 342 | with any other integer value. (The arithmetic value is compared, 343 | not the bit pattern, so all negative integers are less than all 344 | unsigned integers.) However, as usual, one may not compare an int 345 | with a float32 and so on. 346 | 347 | Associated templates 348 | 349 | Each template is named by a string specified when it is created. Also, each 350 | template is associated with zero or more other templates that it may invoke by 351 | name; such associations are transitive and form a name space of templates. 352 | 353 | A template may use a template invocation to instantiate another associated 354 | template; see the explanation of the "template" action above. The name must be 355 | that of a template associated with the template that contains the invocation. 356 | 357 | Nested template definitions 358 | 359 | When parsing a template, another template may be defined and associated with the 360 | template being parsed. Template definitions must appear at the top level of the 361 | template, much like global variables in a Go program. 362 | 363 | The syntax of such definitions is to surround each template declaration with a 364 | "define" and "end" action. 365 | 366 | The define action names the template being created by providing a string 367 | constant. Here is a simple example: 368 | 369 | `{{define "T1"}}ONE{{end}} 370 | {{define "T2"}}TWO{{end}} 371 | {{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}} 372 | {{template "T3"}}` 373 | 374 | This defines two templates, T1 and T2, and a third T3 that invokes the other two 375 | when it is executed. Finally it invokes T3. If executed this template will 376 | produce the text 377 | 378 | ONE TWO 379 | 380 | By construction, a template may reside in only one association. If it's 381 | necessary to have a template addressable from multiple associations, the 382 | template definition must be parsed multiple times to create distinct *Template 383 | values, or must be copied with the Clone or AddParseTree method. 384 | 385 | Parse may be called multiple times to assemble the various associated templates; 386 | see the ParseFiles and ParseGlob functions and methods for simple ways to parse 387 | related templates stored in files. 388 | 389 | A template may be executed directly or through ExecuteTemplate, which executes 390 | an associated template identified by name. To invoke our example above, we 391 | might write, 392 | 393 | err := tmpl.Execute(os.Stdout, "no data needed") 394 | if err != nil { 395 | log.Fatalf("execution failed: %s", err) 396 | } 397 | 398 | or to invoke a particular template explicitly by name, 399 | 400 | err := tmpl.ExecuteTemplate(os.Stdout, "T2", "no data needed") 401 | if err != nil { 402 | log.Fatalf("execution failed: %s", err) 403 | } 404 | 405 | */ 406 | package template 407 | -------------------------------------------------------------------------------- /vendor/github.com/alecthomas/template/funcs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package template 6 | 7 | import ( 8 | "bytes" 9 | "errors" 10 | "fmt" 11 | "io" 12 | "net/url" 13 | "reflect" 14 | "strings" 15 | "unicode" 16 | "unicode/utf8" 17 | ) 18 | 19 | // FuncMap is the type of the map defining the mapping from names to functions. 20 | // Each function must have either a single return value, or two return values of 21 | // which the second has type error. In that case, if the second (error) 22 | // return value evaluates to non-nil during execution, execution terminates and 23 | // Execute returns that error. 24 | type FuncMap map[string]interface{} 25 | 26 | var builtins = FuncMap{ 27 | "and": and, 28 | "call": call, 29 | "html": HTMLEscaper, 30 | "index": index, 31 | "js": JSEscaper, 32 | "len": length, 33 | "not": not, 34 | "or": or, 35 | "print": fmt.Sprint, 36 | "printf": fmt.Sprintf, 37 | "println": fmt.Sprintln, 38 | "urlquery": URLQueryEscaper, 39 | 40 | // Comparisons 41 | "eq": eq, // == 42 | "ge": ge, // >= 43 | "gt": gt, // > 44 | "le": le, // <= 45 | "lt": lt, // < 46 | "ne": ne, // != 47 | } 48 | 49 | var builtinFuncs = createValueFuncs(builtins) 50 | 51 | // createValueFuncs turns a FuncMap into a map[string]reflect.Value 52 | func createValueFuncs(funcMap FuncMap) map[string]reflect.Value { 53 | m := make(map[string]reflect.Value) 54 | addValueFuncs(m, funcMap) 55 | return m 56 | } 57 | 58 | // addValueFuncs adds to values the functions in funcs, converting them to reflect.Values. 59 | func addValueFuncs(out map[string]reflect.Value, in FuncMap) { 60 | for name, fn := range in { 61 | v := reflect.ValueOf(fn) 62 | if v.Kind() != reflect.Func { 63 | panic("value for " + name + " not a function") 64 | } 65 | if !goodFunc(v.Type()) { 66 | panic(fmt.Errorf("can't install method/function %q with %d results", name, v.Type().NumOut())) 67 | } 68 | out[name] = v 69 | } 70 | } 71 | 72 | // addFuncs adds to values the functions in funcs. It does no checking of the input - 73 | // call addValueFuncs first. 74 | func addFuncs(out, in FuncMap) { 75 | for name, fn := range in { 76 | out[name] = fn 77 | } 78 | } 79 | 80 | // goodFunc checks that the function or method has the right result signature. 81 | func goodFunc(typ reflect.Type) bool { 82 | // We allow functions with 1 result or 2 results where the second is an error. 83 | switch { 84 | case typ.NumOut() == 1: 85 | return true 86 | case typ.NumOut() == 2 && typ.Out(1) == errorType: 87 | return true 88 | } 89 | return false 90 | } 91 | 92 | // findFunction looks for a function in the template, and global map. 93 | func findFunction(name string, tmpl *Template) (reflect.Value, bool) { 94 | if tmpl != nil && tmpl.common != nil { 95 | if fn := tmpl.execFuncs[name]; fn.IsValid() { 96 | return fn, true 97 | } 98 | } 99 | if fn := builtinFuncs[name]; fn.IsValid() { 100 | return fn, true 101 | } 102 | return reflect.Value{}, false 103 | } 104 | 105 | // Indexing. 106 | 107 | // index returns the result of indexing its first argument by the following 108 | // arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each 109 | // indexed item must be a map, slice, or array. 110 | func index(item interface{}, indices ...interface{}) (interface{}, error) { 111 | v := reflect.ValueOf(item) 112 | for _, i := range indices { 113 | index := reflect.ValueOf(i) 114 | var isNil bool 115 | if v, isNil = indirect(v); isNil { 116 | return nil, fmt.Errorf("index of nil pointer") 117 | } 118 | switch v.Kind() { 119 | case reflect.Array, reflect.Slice, reflect.String: 120 | var x int64 121 | switch index.Kind() { 122 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 123 | x = index.Int() 124 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 125 | x = int64(index.Uint()) 126 | default: 127 | return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type()) 128 | } 129 | if x < 0 || x >= int64(v.Len()) { 130 | return nil, fmt.Errorf("index out of range: %d", x) 131 | } 132 | v = v.Index(int(x)) 133 | case reflect.Map: 134 | if !index.IsValid() { 135 | index = reflect.Zero(v.Type().Key()) 136 | } 137 | if !index.Type().AssignableTo(v.Type().Key()) { 138 | return nil, fmt.Errorf("%s is not index type for %s", index.Type(), v.Type()) 139 | } 140 | if x := v.MapIndex(index); x.IsValid() { 141 | v = x 142 | } else { 143 | v = reflect.Zero(v.Type().Elem()) 144 | } 145 | default: 146 | return nil, fmt.Errorf("can't index item of type %s", v.Type()) 147 | } 148 | } 149 | return v.Interface(), nil 150 | } 151 | 152 | // Length 153 | 154 | // length returns the length of the item, with an error if it has no defined length. 155 | func length(item interface{}) (int, error) { 156 | v, isNil := indirect(reflect.ValueOf(item)) 157 | if isNil { 158 | return 0, fmt.Errorf("len of nil pointer") 159 | } 160 | switch v.Kind() { 161 | case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String: 162 | return v.Len(), nil 163 | } 164 | return 0, fmt.Errorf("len of type %s", v.Type()) 165 | } 166 | 167 | // Function invocation 168 | 169 | // call returns the result of evaluating the first argument as a function. 170 | // The function must return 1 result, or 2 results, the second of which is an error. 171 | func call(fn interface{}, args ...interface{}) (interface{}, error) { 172 | v := reflect.ValueOf(fn) 173 | typ := v.Type() 174 | if typ.Kind() != reflect.Func { 175 | return nil, fmt.Errorf("non-function of type %s", typ) 176 | } 177 | if !goodFunc(typ) { 178 | return nil, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut()) 179 | } 180 | numIn := typ.NumIn() 181 | var dddType reflect.Type 182 | if typ.IsVariadic() { 183 | if len(args) < numIn-1 { 184 | return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1) 185 | } 186 | dddType = typ.In(numIn - 1).Elem() 187 | } else { 188 | if len(args) != numIn { 189 | return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn) 190 | } 191 | } 192 | argv := make([]reflect.Value, len(args)) 193 | for i, arg := range args { 194 | value := reflect.ValueOf(arg) 195 | // Compute the expected type. Clumsy because of variadics. 196 | var argType reflect.Type 197 | if !typ.IsVariadic() || i < numIn-1 { 198 | argType = typ.In(i) 199 | } else { 200 | argType = dddType 201 | } 202 | if !value.IsValid() && canBeNil(argType) { 203 | value = reflect.Zero(argType) 204 | } 205 | if !value.Type().AssignableTo(argType) { 206 | return nil, fmt.Errorf("arg %d has type %s; should be %s", i, value.Type(), argType) 207 | } 208 | argv[i] = value 209 | } 210 | result := v.Call(argv) 211 | if len(result) == 2 && !result[1].IsNil() { 212 | return result[0].Interface(), result[1].Interface().(error) 213 | } 214 | return result[0].Interface(), nil 215 | } 216 | 217 | // Boolean logic. 218 | 219 | func truth(a interface{}) bool { 220 | t, _ := isTrue(reflect.ValueOf(a)) 221 | return t 222 | } 223 | 224 | // and computes the Boolean AND of its arguments, returning 225 | // the first false argument it encounters, or the last argument. 226 | func and(arg0 interface{}, args ...interface{}) interface{} { 227 | if !truth(arg0) { 228 | return arg0 229 | } 230 | for i := range args { 231 | arg0 = args[i] 232 | if !truth(arg0) { 233 | break 234 | } 235 | } 236 | return arg0 237 | } 238 | 239 | // or computes the Boolean OR of its arguments, returning 240 | // the first true argument it encounters, or the last argument. 241 | func or(arg0 interface{}, args ...interface{}) interface{} { 242 | if truth(arg0) { 243 | return arg0 244 | } 245 | for i := range args { 246 | arg0 = args[i] 247 | if truth(arg0) { 248 | break 249 | } 250 | } 251 | return arg0 252 | } 253 | 254 | // not returns the Boolean negation of its argument. 255 | func not(arg interface{}) (truth bool) { 256 | truth, _ = isTrue(reflect.ValueOf(arg)) 257 | return !truth 258 | } 259 | 260 | // Comparison. 261 | 262 | // TODO: Perhaps allow comparison between signed and unsigned integers. 263 | 264 | var ( 265 | errBadComparisonType = errors.New("invalid type for comparison") 266 | errBadComparison = errors.New("incompatible types for comparison") 267 | errNoComparison = errors.New("missing argument for comparison") 268 | ) 269 | 270 | type kind int 271 | 272 | const ( 273 | invalidKind kind = iota 274 | boolKind 275 | complexKind 276 | intKind 277 | floatKind 278 | integerKind 279 | stringKind 280 | uintKind 281 | ) 282 | 283 | func basicKind(v reflect.Value) (kind, error) { 284 | switch v.Kind() { 285 | case reflect.Bool: 286 | return boolKind, nil 287 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 288 | return intKind, nil 289 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 290 | return uintKind, nil 291 | case reflect.Float32, reflect.Float64: 292 | return floatKind, nil 293 | case reflect.Complex64, reflect.Complex128: 294 | return complexKind, nil 295 | case reflect.String: 296 | return stringKind, nil 297 | } 298 | return invalidKind, errBadComparisonType 299 | } 300 | 301 | // eq evaluates the comparison a == b || a == c || ... 302 | func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) { 303 | v1 := reflect.ValueOf(arg1) 304 | k1, err := basicKind(v1) 305 | if err != nil { 306 | return false, err 307 | } 308 | if len(arg2) == 0 { 309 | return false, errNoComparison 310 | } 311 | for _, arg := range arg2 { 312 | v2 := reflect.ValueOf(arg) 313 | k2, err := basicKind(v2) 314 | if err != nil { 315 | return false, err 316 | } 317 | truth := false 318 | if k1 != k2 { 319 | // Special case: Can compare integer values regardless of type's sign. 320 | switch { 321 | case k1 == intKind && k2 == uintKind: 322 | truth = v1.Int() >= 0 && uint64(v1.Int()) == v2.Uint() 323 | case k1 == uintKind && k2 == intKind: 324 | truth = v2.Int() >= 0 && v1.Uint() == uint64(v2.Int()) 325 | default: 326 | return false, errBadComparison 327 | } 328 | } else { 329 | switch k1 { 330 | case boolKind: 331 | truth = v1.Bool() == v2.Bool() 332 | case complexKind: 333 | truth = v1.Complex() == v2.Complex() 334 | case floatKind: 335 | truth = v1.Float() == v2.Float() 336 | case intKind: 337 | truth = v1.Int() == v2.Int() 338 | case stringKind: 339 | truth = v1.String() == v2.String() 340 | case uintKind: 341 | truth = v1.Uint() == v2.Uint() 342 | default: 343 | panic("invalid kind") 344 | } 345 | } 346 | if truth { 347 | return true, nil 348 | } 349 | } 350 | return false, nil 351 | } 352 | 353 | // ne evaluates the comparison a != b. 354 | func ne(arg1, arg2 interface{}) (bool, error) { 355 | // != is the inverse of ==. 356 | equal, err := eq(arg1, arg2) 357 | return !equal, err 358 | } 359 | 360 | // lt evaluates the comparison a < b. 361 | func lt(arg1, arg2 interface{}) (bool, error) { 362 | v1 := reflect.ValueOf(arg1) 363 | k1, err := basicKind(v1) 364 | if err != nil { 365 | return false, err 366 | } 367 | v2 := reflect.ValueOf(arg2) 368 | k2, err := basicKind(v2) 369 | if err != nil { 370 | return false, err 371 | } 372 | truth := false 373 | if k1 != k2 { 374 | // Special case: Can compare integer values regardless of type's sign. 375 | switch { 376 | case k1 == intKind && k2 == uintKind: 377 | truth = v1.Int() < 0 || uint64(v1.Int()) < v2.Uint() 378 | case k1 == uintKind && k2 == intKind: 379 | truth = v2.Int() >= 0 && v1.Uint() < uint64(v2.Int()) 380 | default: 381 | return false, errBadComparison 382 | } 383 | } else { 384 | switch k1 { 385 | case boolKind, complexKind: 386 | return false, errBadComparisonType 387 | case floatKind: 388 | truth = v1.Float() < v2.Float() 389 | case intKind: 390 | truth = v1.Int() < v2.Int() 391 | case stringKind: 392 | truth = v1.String() < v2.String() 393 | case uintKind: 394 | truth = v1.Uint() < v2.Uint() 395 | default: 396 | panic("invalid kind") 397 | } 398 | } 399 | return truth, nil 400 | } 401 | 402 | // le evaluates the comparison <= b. 403 | func le(arg1, arg2 interface{}) (bool, error) { 404 | // <= is < or ==. 405 | lessThan, err := lt(arg1, arg2) 406 | if lessThan || err != nil { 407 | return lessThan, err 408 | } 409 | return eq(arg1, arg2) 410 | } 411 | 412 | // gt evaluates the comparison a > b. 413 | func gt(arg1, arg2 interface{}) (bool, error) { 414 | // > is the inverse of <=. 415 | lessOrEqual, err := le(arg1, arg2) 416 | if err != nil { 417 | return false, err 418 | } 419 | return !lessOrEqual, nil 420 | } 421 | 422 | // ge evaluates the comparison a >= b. 423 | func ge(arg1, arg2 interface{}) (bool, error) { 424 | // >= is the inverse of <. 425 | lessThan, err := lt(arg1, arg2) 426 | if err != nil { 427 | return false, err 428 | } 429 | return !lessThan, nil 430 | } 431 | 432 | // HTML escaping. 433 | 434 | var ( 435 | htmlQuot = []byte(""") // shorter than """ 436 | htmlApos = []byte("'") // shorter than "'" and apos was not in HTML until HTML5 437 | htmlAmp = []byte("&") 438 | htmlLt = []byte("<") 439 | htmlGt = []byte(">") 440 | ) 441 | 442 | // HTMLEscape writes to w the escaped HTML equivalent of the plain text data b. 443 | func HTMLEscape(w io.Writer, b []byte) { 444 | last := 0 445 | for i, c := range b { 446 | var html []byte 447 | switch c { 448 | case '"': 449 | html = htmlQuot 450 | case '\'': 451 | html = htmlApos 452 | case '&': 453 | html = htmlAmp 454 | case '<': 455 | html = htmlLt 456 | case '>': 457 | html = htmlGt 458 | default: 459 | continue 460 | } 461 | w.Write(b[last:i]) 462 | w.Write(html) 463 | last = i + 1 464 | } 465 | w.Write(b[last:]) 466 | } 467 | 468 | // HTMLEscapeString returns the escaped HTML equivalent of the plain text data s. 469 | func HTMLEscapeString(s string) string { 470 | // Avoid allocation if we can. 471 | if strings.IndexAny(s, `'"&<>`) < 0 { 472 | return s 473 | } 474 | var b bytes.Buffer 475 | HTMLEscape(&b, []byte(s)) 476 | return b.String() 477 | } 478 | 479 | // HTMLEscaper returns the escaped HTML equivalent of the textual 480 | // representation of its arguments. 481 | func HTMLEscaper(args ...interface{}) string { 482 | return HTMLEscapeString(evalArgs(args)) 483 | } 484 | 485 | // JavaScript escaping. 486 | 487 | var ( 488 | jsLowUni = []byte(`\u00`) 489 | hex = []byte("0123456789ABCDEF") 490 | 491 | jsBackslash = []byte(`\\`) 492 | jsApos = []byte(`\'`) 493 | jsQuot = []byte(`\"`) 494 | jsLt = []byte(`\x3C`) 495 | jsGt = []byte(`\x3E`) 496 | ) 497 | 498 | // JSEscape writes to w the escaped JavaScript equivalent of the plain text data b. 499 | func JSEscape(w io.Writer, b []byte) { 500 | last := 0 501 | for i := 0; i < len(b); i++ { 502 | c := b[i] 503 | 504 | if !jsIsSpecial(rune(c)) { 505 | // fast path: nothing to do 506 | continue 507 | } 508 | w.Write(b[last:i]) 509 | 510 | if c < utf8.RuneSelf { 511 | // Quotes, slashes and angle brackets get quoted. 512 | // Control characters get written as \u00XX. 513 | switch c { 514 | case '\\': 515 | w.Write(jsBackslash) 516 | case '\'': 517 | w.Write(jsApos) 518 | case '"': 519 | w.Write(jsQuot) 520 | case '<': 521 | w.Write(jsLt) 522 | case '>': 523 | w.Write(jsGt) 524 | default: 525 | w.Write(jsLowUni) 526 | t, b := c>>4, c&0x0f 527 | w.Write(hex[t : t+1]) 528 | w.Write(hex[b : b+1]) 529 | } 530 | } else { 531 | // Unicode rune. 532 | r, size := utf8.DecodeRune(b[i:]) 533 | if unicode.IsPrint(r) { 534 | w.Write(b[i : i+size]) 535 | } else { 536 | fmt.Fprintf(w, "\\u%04X", r) 537 | } 538 | i += size - 1 539 | } 540 | last = i + 1 541 | } 542 | w.Write(b[last:]) 543 | } 544 | 545 | // JSEscapeString returns the escaped JavaScript equivalent of the plain text data s. 546 | func JSEscapeString(s string) string { 547 | // Avoid allocation if we can. 548 | if strings.IndexFunc(s, jsIsSpecial) < 0 { 549 | return s 550 | } 551 | var b bytes.Buffer 552 | JSEscape(&b, []byte(s)) 553 | return b.String() 554 | } 555 | 556 | func jsIsSpecial(r rune) bool { 557 | switch r { 558 | case '\\', '\'', '"', '<', '>': 559 | return true 560 | } 561 | return r < ' ' || utf8.RuneSelf <= r 562 | } 563 | 564 | // JSEscaper returns the escaped JavaScript equivalent of the textual 565 | // representation of its arguments. 566 | func JSEscaper(args ...interface{}) string { 567 | return JSEscapeString(evalArgs(args)) 568 | } 569 | 570 | // URLQueryEscaper returns the escaped value of the textual representation of 571 | // its arguments in a form suitable for embedding in a URL query. 572 | func URLQueryEscaper(args ...interface{}) string { 573 | return url.QueryEscape(evalArgs(args)) 574 | } 575 | 576 | // evalArgs formats the list of arguments into a string. It is therefore equivalent to 577 | // fmt.Sprint(args...) 578 | // except that each argument is indirected (if a pointer), as required, 579 | // using the same rules as the default string evaluation during template 580 | // execution. 581 | func evalArgs(args []interface{}) string { 582 | ok := false 583 | var s string 584 | // Fast path for simple common case. 585 | if len(args) == 1 { 586 | s, ok = args[0].(string) 587 | } 588 | if !ok { 589 | for i, arg := range args { 590 | a, ok := printableValue(reflect.ValueOf(arg)) 591 | if ok { 592 | args[i] = a 593 | } // else left fmt do its thing 594 | } 595 | s = fmt.Sprint(args...) 596 | } 597 | return s 598 | } 599 | -------------------------------------------------------------------------------- /vendor/github.com/alecthomas/template/parse/parse.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package parse builds parse trees for templates as defined by text/template 6 | // and html/template. Clients should use those packages to construct templates 7 | // rather than this one, which provides shared internal data structures not 8 | // intended for general use. 9 | package parse 10 | 11 | import ( 12 | "bytes" 13 | "fmt" 14 | "runtime" 15 | "strconv" 16 | "strings" 17 | ) 18 | 19 | // Tree is the representation of a single parsed template. 20 | type Tree struct { 21 | Name string // name of the template represented by the tree. 22 | ParseName string // name of the top-level template during parsing, for error messages. 23 | Root *ListNode // top-level root of the tree. 24 | text string // text parsed to create the template (or its parent) 25 | // Parsing only; cleared after parse. 26 | funcs []map[string]interface{} 27 | lex *lexer 28 | token [3]item // three-token lookahead for parser. 29 | peekCount int 30 | vars []string // variables defined at the moment. 31 | } 32 | 33 | // Copy returns a copy of the Tree. Any parsing state is discarded. 34 | func (t *Tree) Copy() *Tree { 35 | if t == nil { 36 | return nil 37 | } 38 | return &Tree{ 39 | Name: t.Name, 40 | ParseName: t.ParseName, 41 | Root: t.Root.CopyList(), 42 | text: t.text, 43 | } 44 | } 45 | 46 | // Parse returns a map from template name to parse.Tree, created by parsing the 47 | // templates described in the argument string. The top-level template will be 48 | // given the specified name. If an error is encountered, parsing stops and an 49 | // empty map is returned with the error. 50 | func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (treeSet map[string]*Tree, err error) { 51 | treeSet = make(map[string]*Tree) 52 | t := New(name) 53 | t.text = text 54 | _, err = t.Parse(text, leftDelim, rightDelim, treeSet, funcs...) 55 | return 56 | } 57 | 58 | // next returns the next token. 59 | func (t *Tree) next() item { 60 | if t.peekCount > 0 { 61 | t.peekCount-- 62 | } else { 63 | t.token[0] = t.lex.nextItem() 64 | } 65 | return t.token[t.peekCount] 66 | } 67 | 68 | // backup backs the input stream up one token. 69 | func (t *Tree) backup() { 70 | t.peekCount++ 71 | } 72 | 73 | // backup2 backs the input stream up two tokens. 74 | // The zeroth token is already there. 75 | func (t *Tree) backup2(t1 item) { 76 | t.token[1] = t1 77 | t.peekCount = 2 78 | } 79 | 80 | // backup3 backs the input stream up three tokens 81 | // The zeroth token is already there. 82 | func (t *Tree) backup3(t2, t1 item) { // Reverse order: we're pushing back. 83 | t.token[1] = t1 84 | t.token[2] = t2 85 | t.peekCount = 3 86 | } 87 | 88 | // peek returns but does not consume the next token. 89 | func (t *Tree) peek() item { 90 | if t.peekCount > 0 { 91 | return t.token[t.peekCount-1] 92 | } 93 | t.peekCount = 1 94 | t.token[0] = t.lex.nextItem() 95 | return t.token[0] 96 | } 97 | 98 | // nextNonSpace returns the next non-space token. 99 | func (t *Tree) nextNonSpace() (token item) { 100 | for { 101 | token = t.next() 102 | if token.typ != itemSpace { 103 | break 104 | } 105 | } 106 | return token 107 | } 108 | 109 | // peekNonSpace returns but does not consume the next non-space token. 110 | func (t *Tree) peekNonSpace() (token item) { 111 | for { 112 | token = t.next() 113 | if token.typ != itemSpace { 114 | break 115 | } 116 | } 117 | t.backup() 118 | return token 119 | } 120 | 121 | // Parsing. 122 | 123 | // New allocates a new parse tree with the given name. 124 | func New(name string, funcs ...map[string]interface{}) *Tree { 125 | return &Tree{ 126 | Name: name, 127 | funcs: funcs, 128 | } 129 | } 130 | 131 | // ErrorContext returns a textual representation of the location of the node in the input text. 132 | // The receiver is only used when the node does not have a pointer to the tree inside, 133 | // which can occur in old code. 134 | func (t *Tree) ErrorContext(n Node) (location, context string) { 135 | pos := int(n.Position()) 136 | tree := n.tree() 137 | if tree == nil { 138 | tree = t 139 | } 140 | text := tree.text[:pos] 141 | byteNum := strings.LastIndex(text, "\n") 142 | if byteNum == -1 { 143 | byteNum = pos // On first line. 144 | } else { 145 | byteNum++ // After the newline. 146 | byteNum = pos - byteNum 147 | } 148 | lineNum := 1 + strings.Count(text, "\n") 149 | context = n.String() 150 | if len(context) > 20 { 151 | context = fmt.Sprintf("%.20s...", context) 152 | } 153 | return fmt.Sprintf("%s:%d:%d", tree.ParseName, lineNum, byteNum), context 154 | } 155 | 156 | // errorf formats the error and terminates processing. 157 | func (t *Tree) errorf(format string, args ...interface{}) { 158 | t.Root = nil 159 | format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.lex.lineNumber(), format) 160 | panic(fmt.Errorf(format, args...)) 161 | } 162 | 163 | // error terminates processing. 164 | func (t *Tree) error(err error) { 165 | t.errorf("%s", err) 166 | } 167 | 168 | // expect consumes the next token and guarantees it has the required type. 169 | func (t *Tree) expect(expected itemType, context string) item { 170 | token := t.nextNonSpace() 171 | if token.typ != expected { 172 | t.unexpected(token, context) 173 | } 174 | return token 175 | } 176 | 177 | // expectOneOf consumes the next token and guarantees it has one of the required types. 178 | func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item { 179 | token := t.nextNonSpace() 180 | if token.typ != expected1 && token.typ != expected2 { 181 | t.unexpected(token, context) 182 | } 183 | return token 184 | } 185 | 186 | // unexpected complains about the token and terminates processing. 187 | func (t *Tree) unexpected(token item, context string) { 188 | t.errorf("unexpected %s in %s", token, context) 189 | } 190 | 191 | // recover is the handler that turns panics into returns from the top level of Parse. 192 | func (t *Tree) recover(errp *error) { 193 | e := recover() 194 | if e != nil { 195 | if _, ok := e.(runtime.Error); ok { 196 | panic(e) 197 | } 198 | if t != nil { 199 | t.stopParse() 200 | } 201 | *errp = e.(error) 202 | } 203 | return 204 | } 205 | 206 | // startParse initializes the parser, using the lexer. 207 | func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) { 208 | t.Root = nil 209 | t.lex = lex 210 | t.vars = []string{"$"} 211 | t.funcs = funcs 212 | } 213 | 214 | // stopParse terminates parsing. 215 | func (t *Tree) stopParse() { 216 | t.lex = nil 217 | t.vars = nil 218 | t.funcs = nil 219 | } 220 | 221 | // Parse parses the template definition string to construct a representation of 222 | // the template for execution. If either action delimiter string is empty, the 223 | // default ("{{" or "}}") is used. Embedded template definitions are added to 224 | // the treeSet map. 225 | func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) { 226 | defer t.recover(&err) 227 | t.ParseName = t.Name 228 | t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim)) 229 | t.text = text 230 | t.parse(treeSet) 231 | t.add(treeSet) 232 | t.stopParse() 233 | return t, nil 234 | } 235 | 236 | // add adds tree to the treeSet. 237 | func (t *Tree) add(treeSet map[string]*Tree) { 238 | tree := treeSet[t.Name] 239 | if tree == nil || IsEmptyTree(tree.Root) { 240 | treeSet[t.Name] = t 241 | return 242 | } 243 | if !IsEmptyTree(t.Root) { 244 | t.errorf("template: multiple definition of template %q", t.Name) 245 | } 246 | } 247 | 248 | // IsEmptyTree reports whether this tree (node) is empty of everything but space. 249 | func IsEmptyTree(n Node) bool { 250 | switch n := n.(type) { 251 | case nil: 252 | return true 253 | case *ActionNode: 254 | case *IfNode: 255 | case *ListNode: 256 | for _, node := range n.Nodes { 257 | if !IsEmptyTree(node) { 258 | return false 259 | } 260 | } 261 | return true 262 | case *RangeNode: 263 | case *TemplateNode: 264 | case *TextNode: 265 | return len(bytes.TrimSpace(n.Text)) == 0 266 | case *WithNode: 267 | default: 268 | panic("unknown node: " + n.String()) 269 | } 270 | return false 271 | } 272 | 273 | // parse is the top-level parser for a template, essentially the same 274 | // as itemList except it also parses {{define}} actions. 275 | // It runs to EOF. 276 | func (t *Tree) parse(treeSet map[string]*Tree) (next Node) { 277 | t.Root = t.newList(t.peek().pos) 278 | for t.peek().typ != itemEOF { 279 | if t.peek().typ == itemLeftDelim { 280 | delim := t.next() 281 | if t.nextNonSpace().typ == itemDefine { 282 | newT := New("definition") // name will be updated once we know it. 283 | newT.text = t.text 284 | newT.ParseName = t.ParseName 285 | newT.startParse(t.funcs, t.lex) 286 | newT.parseDefinition(treeSet) 287 | continue 288 | } 289 | t.backup2(delim) 290 | } 291 | n := t.textOrAction() 292 | if n.Type() == nodeEnd { 293 | t.errorf("unexpected %s", n) 294 | } 295 | t.Root.append(n) 296 | } 297 | return nil 298 | } 299 | 300 | // parseDefinition parses a {{define}} ... {{end}} template definition and 301 | // installs the definition in the treeSet map. The "define" keyword has already 302 | // been scanned. 303 | func (t *Tree) parseDefinition(treeSet map[string]*Tree) { 304 | const context = "define clause" 305 | name := t.expectOneOf(itemString, itemRawString, context) 306 | var err error 307 | t.Name, err = strconv.Unquote(name.val) 308 | if err != nil { 309 | t.error(err) 310 | } 311 | t.expect(itemRightDelim, context) 312 | var end Node 313 | t.Root, end = t.itemList() 314 | if end.Type() != nodeEnd { 315 | t.errorf("unexpected %s in %s", end, context) 316 | } 317 | t.add(treeSet) 318 | t.stopParse() 319 | } 320 | 321 | // itemList: 322 | // textOrAction* 323 | // Terminates at {{end}} or {{else}}, returned separately. 324 | func (t *Tree) itemList() (list *ListNode, next Node) { 325 | list = t.newList(t.peekNonSpace().pos) 326 | for t.peekNonSpace().typ != itemEOF { 327 | n := t.textOrAction() 328 | switch n.Type() { 329 | case nodeEnd, nodeElse: 330 | return list, n 331 | } 332 | list.append(n) 333 | } 334 | t.errorf("unexpected EOF") 335 | return 336 | } 337 | 338 | // textOrAction: 339 | // text | action 340 | func (t *Tree) textOrAction() Node { 341 | switch token := t.nextNonSpace(); token.typ { 342 | case itemElideNewline: 343 | return t.elideNewline() 344 | case itemText: 345 | return t.newText(token.pos, token.val) 346 | case itemLeftDelim: 347 | return t.action() 348 | default: 349 | t.unexpected(token, "input") 350 | } 351 | return nil 352 | } 353 | 354 | // elideNewline: 355 | // Remove newlines trailing rightDelim if \\ is present. 356 | func (t *Tree) elideNewline() Node { 357 | token := t.peek() 358 | if token.typ != itemText { 359 | t.unexpected(token, "input") 360 | return nil 361 | } 362 | 363 | t.next() 364 | stripped := strings.TrimLeft(token.val, "\n\r") 365 | diff := len(token.val) - len(stripped) 366 | if diff > 0 { 367 | // This is a bit nasty. We mutate the token in-place to remove 368 | // preceding newlines. 369 | token.pos += Pos(diff) 370 | token.val = stripped 371 | } 372 | return t.newText(token.pos, token.val) 373 | } 374 | 375 | // Action: 376 | // control 377 | // command ("|" command)* 378 | // Left delim is past. Now get actions. 379 | // First word could be a keyword such as range. 380 | func (t *Tree) action() (n Node) { 381 | switch token := t.nextNonSpace(); token.typ { 382 | case itemElse: 383 | return t.elseControl() 384 | case itemEnd: 385 | return t.endControl() 386 | case itemIf: 387 | return t.ifControl() 388 | case itemRange: 389 | return t.rangeControl() 390 | case itemTemplate: 391 | return t.templateControl() 392 | case itemWith: 393 | return t.withControl() 394 | } 395 | t.backup() 396 | // Do not pop variables; they persist until "end". 397 | return t.newAction(t.peek().pos, t.lex.lineNumber(), t.pipeline("command")) 398 | } 399 | 400 | // Pipeline: 401 | // declarations? command ('|' command)* 402 | func (t *Tree) pipeline(context string) (pipe *PipeNode) { 403 | var decl []*VariableNode 404 | pos := t.peekNonSpace().pos 405 | // Are there declarations? 406 | for { 407 | if v := t.peekNonSpace(); v.typ == itemVariable { 408 | t.next() 409 | // Since space is a token, we need 3-token look-ahead here in the worst case: 410 | // in "$x foo" we need to read "foo" (as opposed to ":=") to know that $x is an 411 | // argument variable rather than a declaration. So remember the token 412 | // adjacent to the variable so we can push it back if necessary. 413 | tokenAfterVariable := t.peek() 414 | if next := t.peekNonSpace(); next.typ == itemColonEquals || (next.typ == itemChar && next.val == ",") { 415 | t.nextNonSpace() 416 | variable := t.newVariable(v.pos, v.val) 417 | decl = append(decl, variable) 418 | t.vars = append(t.vars, v.val) 419 | if next.typ == itemChar && next.val == "," { 420 | if context == "range" && len(decl) < 2 { 421 | continue 422 | } 423 | t.errorf("too many declarations in %s", context) 424 | } 425 | } else if tokenAfterVariable.typ == itemSpace { 426 | t.backup3(v, tokenAfterVariable) 427 | } else { 428 | t.backup2(v) 429 | } 430 | } 431 | break 432 | } 433 | pipe = t.newPipeline(pos, t.lex.lineNumber(), decl) 434 | for { 435 | switch token := t.nextNonSpace(); token.typ { 436 | case itemRightDelim, itemRightParen: 437 | if len(pipe.Cmds) == 0 { 438 | t.errorf("missing value for %s", context) 439 | } 440 | if token.typ == itemRightParen { 441 | t.backup() 442 | } 443 | return 444 | case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier, 445 | itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen: 446 | t.backup() 447 | pipe.append(t.command()) 448 | default: 449 | t.unexpected(token, context) 450 | } 451 | } 452 | } 453 | 454 | func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) { 455 | defer t.popVars(len(t.vars)) 456 | line = t.lex.lineNumber() 457 | pipe = t.pipeline(context) 458 | var next Node 459 | list, next = t.itemList() 460 | switch next.Type() { 461 | case nodeEnd: //done 462 | case nodeElse: 463 | if allowElseIf { 464 | // Special case for "else if". If the "else" is followed immediately by an "if", 465 | // the elseControl will have left the "if" token pending. Treat 466 | // {{if a}}_{{else if b}}_{{end}} 467 | // as 468 | // {{if a}}_{{else}}{{if b}}_{{end}}{{end}}. 469 | // To do this, parse the if as usual and stop at it {{end}}; the subsequent{{end}} 470 | // is assumed. This technique works even for long if-else-if chains. 471 | // TODO: Should we allow else-if in with and range? 472 | if t.peek().typ == itemIf { 473 | t.next() // Consume the "if" token. 474 | elseList = t.newList(next.Position()) 475 | elseList.append(t.ifControl()) 476 | // Do not consume the next item - only one {{end}} required. 477 | break 478 | } 479 | } 480 | elseList, next = t.itemList() 481 | if next.Type() != nodeEnd { 482 | t.errorf("expected end; found %s", next) 483 | } 484 | } 485 | return pipe.Position(), line, pipe, list, elseList 486 | } 487 | 488 | // If: 489 | // {{if pipeline}} itemList {{end}} 490 | // {{if pipeline}} itemList {{else}} itemList {{end}} 491 | // If keyword is past. 492 | func (t *Tree) ifControl() Node { 493 | return t.newIf(t.parseControl(true, "if")) 494 | } 495 | 496 | // Range: 497 | // {{range pipeline}} itemList {{end}} 498 | // {{range pipeline}} itemList {{else}} itemList {{end}} 499 | // Range keyword is past. 500 | func (t *Tree) rangeControl() Node { 501 | return t.newRange(t.parseControl(false, "range")) 502 | } 503 | 504 | // With: 505 | // {{with pipeline}} itemList {{end}} 506 | // {{with pipeline}} itemList {{else}} itemList {{end}} 507 | // If keyword is past. 508 | func (t *Tree) withControl() Node { 509 | return t.newWith(t.parseControl(false, "with")) 510 | } 511 | 512 | // End: 513 | // {{end}} 514 | // End keyword is past. 515 | func (t *Tree) endControl() Node { 516 | return t.newEnd(t.expect(itemRightDelim, "end").pos) 517 | } 518 | 519 | // Else: 520 | // {{else}} 521 | // Else keyword is past. 522 | func (t *Tree) elseControl() Node { 523 | // Special case for "else if". 524 | peek := t.peekNonSpace() 525 | if peek.typ == itemIf { 526 | // We see "{{else if ... " but in effect rewrite it to {{else}}{{if ... ". 527 | return t.newElse(peek.pos, t.lex.lineNumber()) 528 | } 529 | return t.newElse(t.expect(itemRightDelim, "else").pos, t.lex.lineNumber()) 530 | } 531 | 532 | // Template: 533 | // {{template stringValue pipeline}} 534 | // Template keyword is past. The name must be something that can evaluate 535 | // to a string. 536 | func (t *Tree) templateControl() Node { 537 | var name string 538 | token := t.nextNonSpace() 539 | switch token.typ { 540 | case itemString, itemRawString: 541 | s, err := strconv.Unquote(token.val) 542 | if err != nil { 543 | t.error(err) 544 | } 545 | name = s 546 | default: 547 | t.unexpected(token, "template invocation") 548 | } 549 | var pipe *PipeNode 550 | if t.nextNonSpace().typ != itemRightDelim { 551 | t.backup() 552 | // Do not pop variables; they persist until "end". 553 | pipe = t.pipeline("template") 554 | } 555 | return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe) 556 | } 557 | 558 | // command: 559 | // operand (space operand)* 560 | // space-separated arguments up to a pipeline character or right delimiter. 561 | // we consume the pipe character but leave the right delim to terminate the action. 562 | func (t *Tree) command() *CommandNode { 563 | cmd := t.newCommand(t.peekNonSpace().pos) 564 | for { 565 | t.peekNonSpace() // skip leading spaces. 566 | operand := t.operand() 567 | if operand != nil { 568 | cmd.append(operand) 569 | } 570 | switch token := t.next(); token.typ { 571 | case itemSpace: 572 | continue 573 | case itemError: 574 | t.errorf("%s", token.val) 575 | case itemRightDelim, itemRightParen: 576 | t.backup() 577 | case itemPipe: 578 | default: 579 | t.errorf("unexpected %s in operand; missing space?", token) 580 | } 581 | break 582 | } 583 | if len(cmd.Args) == 0 { 584 | t.errorf("empty command") 585 | } 586 | return cmd 587 | } 588 | 589 | // operand: 590 | // term .Field* 591 | // An operand is a space-separated component of a command, 592 | // a term possibly followed by field accesses. 593 | // A nil return means the next item is not an operand. 594 | func (t *Tree) operand() Node { 595 | node := t.term() 596 | if node == nil { 597 | return nil 598 | } 599 | if t.peek().typ == itemField { 600 | chain := t.newChain(t.peek().pos, node) 601 | for t.peek().typ == itemField { 602 | chain.Add(t.next().val) 603 | } 604 | // Compatibility with original API: If the term is of type NodeField 605 | // or NodeVariable, just put more fields on the original. 606 | // Otherwise, keep the Chain node. 607 | // TODO: Switch to Chains always when we can. 608 | switch node.Type() { 609 | case NodeField: 610 | node = t.newField(chain.Position(), chain.String()) 611 | case NodeVariable: 612 | node = t.newVariable(chain.Position(), chain.String()) 613 | default: 614 | node = chain 615 | } 616 | } 617 | return node 618 | } 619 | 620 | // term: 621 | // literal (number, string, nil, boolean) 622 | // function (identifier) 623 | // . 624 | // .Field 625 | // $ 626 | // '(' pipeline ')' 627 | // A term is a simple "expression". 628 | // A nil return means the next item is not a term. 629 | func (t *Tree) term() Node { 630 | switch token := t.nextNonSpace(); token.typ { 631 | case itemError: 632 | t.errorf("%s", token.val) 633 | case itemIdentifier: 634 | if !t.hasFunction(token.val) { 635 | t.errorf("function %q not defined", token.val) 636 | } 637 | return NewIdentifier(token.val).SetTree(t).SetPos(token.pos) 638 | case itemDot: 639 | return t.newDot(token.pos) 640 | case itemNil: 641 | return t.newNil(token.pos) 642 | case itemVariable: 643 | return t.useVar(token.pos, token.val) 644 | case itemField: 645 | return t.newField(token.pos, token.val) 646 | case itemBool: 647 | return t.newBool(token.pos, token.val == "true") 648 | case itemCharConstant, itemComplex, itemNumber: 649 | number, err := t.newNumber(token.pos, token.val, token.typ) 650 | if err != nil { 651 | t.error(err) 652 | } 653 | return number 654 | case itemLeftParen: 655 | pipe := t.pipeline("parenthesized pipeline") 656 | if token := t.next(); token.typ != itemRightParen { 657 | t.errorf("unclosed right paren: unexpected %s", token) 658 | } 659 | return pipe 660 | case itemString, itemRawString: 661 | s, err := strconv.Unquote(token.val) 662 | if err != nil { 663 | t.error(err) 664 | } 665 | return t.newString(token.pos, token.val, s) 666 | } 667 | t.backup() 668 | return nil 669 | } 670 | 671 | // hasFunction reports if a function name exists in the Tree's maps. 672 | func (t *Tree) hasFunction(name string) bool { 673 | for _, funcMap := range t.funcs { 674 | if funcMap == nil { 675 | continue 676 | } 677 | if funcMap[name] != nil { 678 | return true 679 | } 680 | } 681 | return false 682 | } 683 | 684 | // popVars trims the variable list to the specified length 685 | func (t *Tree) popVars(n int) { 686 | t.vars = t.vars[:n] 687 | } 688 | 689 | // useVar returns a node for a variable reference. It errors if the 690 | // variable is not defined. 691 | func (t *Tree) useVar(pos Pos, name string) Node { 692 | v := t.newVariable(pos, name) 693 | for _, varName := range t.vars { 694 | if varName == v.Ident[0] { 695 | return v 696 | } 697 | } 698 | t.errorf("undefined variable %q", v.Ident[0]) 699 | return nil 700 | } 701 | -------------------------------------------------------------------------------- /vendor/gopkg.in/alecthomas/kingpin.v2/app.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "regexp" 8 | "strings" 9 | ) 10 | 11 | var ( 12 | ErrCommandNotSpecified = fmt.Errorf("command not specified") 13 | ) 14 | 15 | var ( 16 | envarTransformRegexp = regexp.MustCompile(`[^a-zA-Z0-9_]+`) 17 | ) 18 | 19 | type ApplicationValidator func(*Application) error 20 | 21 | // An Application contains the definitions of flags, arguments and commands 22 | // for an application. 23 | type Application struct { 24 | cmdMixin 25 | initialized bool 26 | 27 | Name string 28 | Help string 29 | 30 | author string 31 | version string 32 | errorWriter io.Writer // Destination for errors. 33 | usageWriter io.Writer // Destination for usage 34 | usageTemplate string 35 | validator ApplicationValidator 36 | terminate func(status int) // See Terminate() 37 | noInterspersed bool // can flags be interspersed with args (or must they come first) 38 | defaultEnvars bool 39 | completion bool 40 | 41 | // Help flag. Exposed for user customisation. 42 | HelpFlag *FlagClause 43 | // Help command. Exposed for user customisation. May be nil. 44 | HelpCommand *CmdClause 45 | // Version flag. Exposed for user customisation. May be nil. 46 | VersionFlag *FlagClause 47 | } 48 | 49 | // New creates a new Kingpin application instance. 50 | func New(name, help string) *Application { 51 | a := &Application{ 52 | Name: name, 53 | Help: help, 54 | errorWriter: os.Stderr, // Left for backwards compatibility purposes. 55 | usageWriter: os.Stderr, 56 | usageTemplate: DefaultUsageTemplate, 57 | terminate: os.Exit, 58 | } 59 | a.flagGroup = newFlagGroup() 60 | a.argGroup = newArgGroup() 61 | a.cmdGroup = newCmdGroup(a) 62 | a.HelpFlag = a.Flag("help", "Show context-sensitive help (also try --help-long and --help-man).") 63 | a.HelpFlag.Bool() 64 | a.Flag("help-long", "Generate long help.").Hidden().PreAction(a.generateLongHelp).Bool() 65 | a.Flag("help-man", "Generate a man page.").Hidden().PreAction(a.generateManPage).Bool() 66 | a.Flag("completion-bash", "Output possible completions for the given args.").Hidden().BoolVar(&a.completion) 67 | a.Flag("completion-script-bash", "Generate completion script for bash.").Hidden().PreAction(a.generateBashCompletionScript).Bool() 68 | a.Flag("completion-script-zsh", "Generate completion script for ZSH.").Hidden().PreAction(a.generateZSHCompletionScript).Bool() 69 | 70 | return a 71 | } 72 | 73 | func (a *Application) generateLongHelp(c *ParseContext) error { 74 | a.Writer(os.Stdout) 75 | if err := a.UsageForContextWithTemplate(c, 2, LongHelpTemplate); err != nil { 76 | return err 77 | } 78 | a.terminate(0) 79 | return nil 80 | } 81 | 82 | func (a *Application) generateManPage(c *ParseContext) error { 83 | a.Writer(os.Stdout) 84 | if err := a.UsageForContextWithTemplate(c, 2, ManPageTemplate); err != nil { 85 | return err 86 | } 87 | a.terminate(0) 88 | return nil 89 | } 90 | 91 | func (a *Application) generateBashCompletionScript(c *ParseContext) error { 92 | a.Writer(os.Stdout) 93 | if err := a.UsageForContextWithTemplate(c, 2, BashCompletionTemplate); err != nil { 94 | return err 95 | } 96 | a.terminate(0) 97 | return nil 98 | } 99 | 100 | func (a *Application) generateZSHCompletionScript(c *ParseContext) error { 101 | a.Writer(os.Stdout) 102 | if err := a.UsageForContextWithTemplate(c, 2, ZshCompletionTemplate); err != nil { 103 | return err 104 | } 105 | a.terminate(0) 106 | return nil 107 | } 108 | 109 | // DefaultEnvars configures all flags (that do not already have an associated 110 | // envar) to use a default environment variable in the form "_". 111 | // 112 | // For example, if the application is named "foo" and a flag is named "bar- 113 | // waz" the environment variable: "FOO_BAR_WAZ". 114 | func (a *Application) DefaultEnvars() *Application { 115 | a.defaultEnvars = true 116 | return a 117 | } 118 | 119 | // Terminate specifies the termination handler. Defaults to os.Exit(status). 120 | // If nil is passed, a no-op function will be used. 121 | func (a *Application) Terminate(terminate func(int)) *Application { 122 | if terminate == nil { 123 | terminate = func(int) {} 124 | } 125 | a.terminate = terminate 126 | return a 127 | } 128 | 129 | // Writer specifies the writer to use for usage and errors. Defaults to os.Stderr. 130 | // DEPRECATED: See ErrorWriter and UsageWriter. 131 | func (a *Application) Writer(w io.Writer) *Application { 132 | a.errorWriter = w 133 | a.usageWriter = w 134 | return a 135 | } 136 | 137 | // ErrorWriter sets the io.Writer to use for errors. 138 | func (a *Application) ErrorWriter(w io.Writer) *Application { 139 | a.errorWriter = w 140 | return a 141 | } 142 | 143 | // UsageWriter sets the io.Writer to use for errors. 144 | func (a *Application) UsageWriter(w io.Writer) *Application { 145 | a.usageWriter = w 146 | return a 147 | } 148 | 149 | // UsageTemplate specifies the text template to use when displaying usage 150 | // information. The default is UsageTemplate. 151 | func (a *Application) UsageTemplate(template string) *Application { 152 | a.usageTemplate = template 153 | return a 154 | } 155 | 156 | // Validate sets a validation function to run when parsing. 157 | func (a *Application) Validate(validator ApplicationValidator) *Application { 158 | a.validator = validator 159 | return a 160 | } 161 | 162 | // ParseContext parses the given command line and returns the fully populated 163 | // ParseContext. 164 | func (a *Application) ParseContext(args []string) (*ParseContext, error) { 165 | return a.parseContext(false, args) 166 | } 167 | 168 | func (a *Application) parseContext(ignoreDefault bool, args []string) (*ParseContext, error) { 169 | if err := a.init(); err != nil { 170 | return nil, err 171 | } 172 | context := tokenize(args, ignoreDefault) 173 | err := parse(context, a) 174 | return context, err 175 | } 176 | 177 | // Parse parses command-line arguments. It returns the selected command and an 178 | // error. The selected command will be a space separated subcommand, if 179 | // subcommands have been configured. 180 | // 181 | // This will populate all flag and argument values, call all callbacks, and so 182 | // on. 183 | func (a *Application) Parse(args []string) (command string, err error) { 184 | 185 | context, parseErr := a.ParseContext(args) 186 | selected := []string{} 187 | var setValuesErr error 188 | 189 | if context == nil { 190 | // Since we do not throw error immediately, there could be a case 191 | // where a context returns nil. Protect against that. 192 | return "", parseErr 193 | } 194 | 195 | if err = a.setDefaults(context); err != nil { 196 | return "", err 197 | } 198 | 199 | selected, setValuesErr = a.setValues(context) 200 | 201 | if err = a.applyPreActions(context, !a.completion); err != nil { 202 | return "", err 203 | } 204 | 205 | if a.completion { 206 | a.generateBashCompletion(context) 207 | a.terminate(0) 208 | } else { 209 | if parseErr != nil { 210 | return "", parseErr 211 | } 212 | 213 | a.maybeHelp(context) 214 | if !context.EOL() { 215 | return "", fmt.Errorf("unexpected argument '%s'", context.Peek()) 216 | } 217 | 218 | if setValuesErr != nil { 219 | return "", setValuesErr 220 | } 221 | 222 | command, err = a.execute(context, selected) 223 | if err == ErrCommandNotSpecified { 224 | a.writeUsage(context, nil) 225 | } 226 | } 227 | return command, err 228 | } 229 | 230 | func (a *Application) writeUsage(context *ParseContext, err error) { 231 | if err != nil { 232 | a.Errorf("%s", err) 233 | } 234 | if err := a.UsageForContext(context); err != nil { 235 | panic(err) 236 | } 237 | if err != nil { 238 | a.terminate(1) 239 | } else { 240 | a.terminate(0) 241 | } 242 | } 243 | 244 | func (a *Application) maybeHelp(context *ParseContext) { 245 | for _, element := range context.Elements { 246 | if flag, ok := element.Clause.(*FlagClause); ok && flag == a.HelpFlag { 247 | // Re-parse the command-line ignoring defaults, so that help works correctly. 248 | context, _ = a.parseContext(true, context.rawArgs) 249 | a.writeUsage(context, nil) 250 | } 251 | } 252 | } 253 | 254 | // Version adds a --version flag for displaying the application version. 255 | func (a *Application) Version(version string) *Application { 256 | a.version = version 257 | a.VersionFlag = a.Flag("version", "Show application version.").PreAction(func(*ParseContext) error { 258 | fmt.Fprintln(a.usageWriter, version) 259 | a.terminate(0) 260 | return nil 261 | }) 262 | a.VersionFlag.Bool() 263 | return a 264 | } 265 | 266 | // Author sets the author output by some help templates. 267 | func (a *Application) Author(author string) *Application { 268 | a.author = author 269 | return a 270 | } 271 | 272 | // Action callback to call when all values are populated and parsing is 273 | // complete, but before any command, flag or argument actions. 274 | // 275 | // All Action() callbacks are called in the order they are encountered on the 276 | // command line. 277 | func (a *Application) Action(action Action) *Application { 278 | a.addAction(action) 279 | return a 280 | } 281 | 282 | // Action called after parsing completes but before validation and execution. 283 | func (a *Application) PreAction(action Action) *Application { 284 | a.addPreAction(action) 285 | return a 286 | } 287 | 288 | // Command adds a new top-level command. 289 | func (a *Application) Command(name, help string) *CmdClause { 290 | return a.addCommand(name, help) 291 | } 292 | 293 | // Interspersed control if flags can be interspersed with positional arguments 294 | // 295 | // true (the default) means that they can, false means that all the flags must appear before the first positional arguments. 296 | func (a *Application) Interspersed(interspersed bool) *Application { 297 | a.noInterspersed = !interspersed 298 | return a 299 | } 300 | 301 | func (a *Application) defaultEnvarPrefix() string { 302 | if a.defaultEnvars { 303 | return a.Name 304 | } 305 | return "" 306 | } 307 | 308 | func (a *Application) init() error { 309 | if a.initialized { 310 | return nil 311 | } 312 | if a.cmdGroup.have() && a.argGroup.have() { 313 | return fmt.Errorf("can't mix top-level Arg()s with Command()s") 314 | } 315 | 316 | // If we have subcommands, add a help command at the top-level. 317 | if a.cmdGroup.have() { 318 | var command []string 319 | a.HelpCommand = a.Command("help", "Show help.").PreAction(func(context *ParseContext) error { 320 | a.Usage(command) 321 | a.terminate(0) 322 | return nil 323 | }) 324 | a.HelpCommand.Arg("command", "Show help on command.").StringsVar(&command) 325 | // Make help first command. 326 | l := len(a.commandOrder) 327 | a.commandOrder = append(a.commandOrder[l-1:l], a.commandOrder[:l-1]...) 328 | } 329 | 330 | if err := a.flagGroup.init(a.defaultEnvarPrefix()); err != nil { 331 | return err 332 | } 333 | if err := a.cmdGroup.init(); err != nil { 334 | return err 335 | } 336 | if err := a.argGroup.init(); err != nil { 337 | return err 338 | } 339 | for _, cmd := range a.commands { 340 | if err := cmd.init(); err != nil { 341 | return err 342 | } 343 | } 344 | flagGroups := []*flagGroup{a.flagGroup} 345 | for _, cmd := range a.commandOrder { 346 | if err := checkDuplicateFlags(cmd, flagGroups); err != nil { 347 | return err 348 | } 349 | } 350 | a.initialized = true 351 | return nil 352 | } 353 | 354 | // Recursively check commands for duplicate flags. 355 | func checkDuplicateFlags(current *CmdClause, flagGroups []*flagGroup) error { 356 | // Check for duplicates. 357 | for _, flags := range flagGroups { 358 | for _, flag := range current.flagOrder { 359 | if flag.shorthand != 0 { 360 | if _, ok := flags.short[string(flag.shorthand)]; ok { 361 | return fmt.Errorf("duplicate short flag -%c", flag.shorthand) 362 | } 363 | } 364 | if _, ok := flags.long[flag.name]; ok { 365 | return fmt.Errorf("duplicate long flag --%s", flag.name) 366 | } 367 | } 368 | } 369 | flagGroups = append(flagGroups, current.flagGroup) 370 | // Check subcommands. 371 | for _, subcmd := range current.commandOrder { 372 | if err := checkDuplicateFlags(subcmd, flagGroups); err != nil { 373 | return err 374 | } 375 | } 376 | return nil 377 | } 378 | 379 | func (a *Application) execute(context *ParseContext, selected []string) (string, error) { 380 | var err error 381 | 382 | if err = a.validateRequired(context); err != nil { 383 | return "", err 384 | } 385 | 386 | if err = a.applyValidators(context); err != nil { 387 | return "", err 388 | } 389 | 390 | if err = a.applyActions(context); err != nil { 391 | return "", err 392 | } 393 | 394 | command := strings.Join(selected, " ") 395 | if command == "" && a.cmdGroup.have() { 396 | return "", ErrCommandNotSpecified 397 | } 398 | return command, err 399 | } 400 | 401 | func (a *Application) setDefaults(context *ParseContext) error { 402 | flagElements := map[string]*ParseElement{} 403 | for _, element := range context.Elements { 404 | if flag, ok := element.Clause.(*FlagClause); ok { 405 | if flag.name == "help" { 406 | return nil 407 | } 408 | flagElements[flag.name] = element 409 | } 410 | } 411 | 412 | argElements := map[string]*ParseElement{} 413 | for _, element := range context.Elements { 414 | if arg, ok := element.Clause.(*ArgClause); ok { 415 | argElements[arg.name] = element 416 | } 417 | } 418 | 419 | // Check required flags and set defaults. 420 | for _, flag := range context.flags.long { 421 | if flagElements[flag.name] == nil { 422 | if err := flag.setDefault(); err != nil { 423 | return err 424 | } 425 | } 426 | } 427 | 428 | for _, arg := range context.arguments.args { 429 | if argElements[arg.name] == nil { 430 | if err := arg.setDefault(); err != nil { 431 | return err 432 | } 433 | } 434 | } 435 | 436 | return nil 437 | } 438 | 439 | func (a *Application) validateRequired(context *ParseContext) error { 440 | flagElements := map[string]*ParseElement{} 441 | for _, element := range context.Elements { 442 | if flag, ok := element.Clause.(*FlagClause); ok { 443 | flagElements[flag.name] = element 444 | } 445 | } 446 | 447 | argElements := map[string]*ParseElement{} 448 | for _, element := range context.Elements { 449 | if arg, ok := element.Clause.(*ArgClause); ok { 450 | argElements[arg.name] = element 451 | } 452 | } 453 | 454 | // Check required flags and set defaults. 455 | for _, flag := range context.flags.long { 456 | if flagElements[flag.name] == nil { 457 | // Check required flags were provided. 458 | if flag.needsValue() { 459 | return fmt.Errorf("required flag --%s not provided", flag.name) 460 | } 461 | } 462 | } 463 | 464 | for _, arg := range context.arguments.args { 465 | if argElements[arg.name] == nil { 466 | if arg.needsValue() { 467 | return fmt.Errorf("required argument '%s' not provided", arg.name) 468 | } 469 | } 470 | } 471 | return nil 472 | } 473 | 474 | func (a *Application) setValues(context *ParseContext) (selected []string, err error) { 475 | // Set all arg and flag values. 476 | var ( 477 | lastCmd *CmdClause 478 | flagSet = map[string]struct{}{} 479 | ) 480 | for _, element := range context.Elements { 481 | switch clause := element.Clause.(type) { 482 | case *FlagClause: 483 | if _, ok := flagSet[clause.name]; ok { 484 | if v, ok := clause.value.(repeatableFlag); !ok || !v.IsCumulative() { 485 | return nil, fmt.Errorf("flag '%s' cannot be repeated", clause.name) 486 | } 487 | } 488 | if err = clause.value.Set(*element.Value); err != nil { 489 | return 490 | } 491 | flagSet[clause.name] = struct{}{} 492 | 493 | case *ArgClause: 494 | if err = clause.value.Set(*element.Value); err != nil { 495 | return 496 | } 497 | 498 | case *CmdClause: 499 | if clause.validator != nil { 500 | if err = clause.validator(clause); err != nil { 501 | return 502 | } 503 | } 504 | selected = append(selected, clause.name) 505 | lastCmd = clause 506 | } 507 | } 508 | 509 | if lastCmd != nil && len(lastCmd.commands) > 0 { 510 | return nil, fmt.Errorf("must select a subcommand of '%s'", lastCmd.FullCommand()) 511 | } 512 | 513 | return 514 | } 515 | 516 | func (a *Application) applyValidators(context *ParseContext) (err error) { 517 | // Call command validation functions. 518 | for _, element := range context.Elements { 519 | if cmd, ok := element.Clause.(*CmdClause); ok && cmd.validator != nil { 520 | if err = cmd.validator(cmd); err != nil { 521 | return err 522 | } 523 | } 524 | } 525 | 526 | if a.validator != nil { 527 | err = a.validator(a) 528 | } 529 | return err 530 | } 531 | 532 | func (a *Application) applyPreActions(context *ParseContext, dispatch bool) error { 533 | if err := a.actionMixin.applyPreActions(context); err != nil { 534 | return err 535 | } 536 | // Dispatch to actions. 537 | if dispatch { 538 | for _, element := range context.Elements { 539 | if applier, ok := element.Clause.(actionApplier); ok { 540 | if err := applier.applyPreActions(context); err != nil { 541 | return err 542 | } 543 | } 544 | } 545 | } 546 | 547 | return nil 548 | } 549 | 550 | func (a *Application) applyActions(context *ParseContext) error { 551 | if err := a.actionMixin.applyActions(context); err != nil { 552 | return err 553 | } 554 | // Dispatch to actions. 555 | for _, element := range context.Elements { 556 | if applier, ok := element.Clause.(actionApplier); ok { 557 | if err := applier.applyActions(context); err != nil { 558 | return err 559 | } 560 | } 561 | } 562 | return nil 563 | } 564 | 565 | // Errorf prints an error message to w in the format ": error: ". 566 | func (a *Application) Errorf(format string, args ...interface{}) { 567 | fmt.Fprintf(a.errorWriter, a.Name+": error: "+format+"\n", args...) 568 | } 569 | 570 | // Fatalf writes a formatted error to w then terminates with exit status 1. 571 | func (a *Application) Fatalf(format string, args ...interface{}) { 572 | a.Errorf(format, args...) 573 | a.terminate(1) 574 | } 575 | 576 | // FatalUsage prints an error message followed by usage information, then 577 | // exits with a non-zero status. 578 | func (a *Application) FatalUsage(format string, args ...interface{}) { 579 | a.Errorf(format, args...) 580 | // Force usage to go to error output. 581 | a.usageWriter = a.errorWriter 582 | a.Usage([]string{}) 583 | a.terminate(1) 584 | } 585 | 586 | // FatalUsageContext writes a printf formatted error message to w, then usage 587 | // information for the given ParseContext, before exiting. 588 | func (a *Application) FatalUsageContext(context *ParseContext, format string, args ...interface{}) { 589 | a.Errorf(format, args...) 590 | if err := a.UsageForContext(context); err != nil { 591 | panic(err) 592 | } 593 | a.terminate(1) 594 | } 595 | 596 | // FatalIfError prints an error and exits if err is not nil. The error is printed 597 | // with the given formatted string, if any. 598 | func (a *Application) FatalIfError(err error, format string, args ...interface{}) { 599 | if err != nil { 600 | prefix := "" 601 | if format != "" { 602 | prefix = fmt.Sprintf(format, args...) + ": " 603 | } 604 | a.Errorf(prefix+"%s", err) 605 | a.terminate(1) 606 | } 607 | } 608 | 609 | func (a *Application) completionOptions(context *ParseContext) []string { 610 | args := context.rawArgs 611 | 612 | var ( 613 | currArg string 614 | prevArg string 615 | target cmdMixin 616 | ) 617 | 618 | numArgs := len(args) 619 | if numArgs > 1 { 620 | args = args[1:] 621 | currArg = args[len(args)-1] 622 | } 623 | if numArgs > 2 { 624 | prevArg = args[len(args)-2] 625 | } 626 | 627 | target = a.cmdMixin 628 | if context.SelectedCommand != nil { 629 | // A subcommand was in use. We will use it as the target 630 | target = context.SelectedCommand.cmdMixin 631 | } 632 | 633 | if (currArg != "" && strings.HasPrefix(currArg, "--")) || strings.HasPrefix(prevArg, "--") { 634 | // Perform completion for A flag. The last/current argument started with "-" 635 | var ( 636 | flagName string // The name of a flag if given (could be half complete) 637 | flagValue string // The value assigned to a flag (if given) (could be half complete) 638 | ) 639 | 640 | if strings.HasPrefix(prevArg, "--") && !strings.HasPrefix(currArg, "--") { 641 | // Matches: ./myApp --flag value 642 | // Wont Match: ./myApp --flag -- 643 | flagName = prevArg[2:] // Strip the "--" 644 | flagValue = currArg 645 | } else if strings.HasPrefix(currArg, "--") { 646 | // Matches: ./myApp --flag -- 647 | // Matches: ./myApp --flag somevalue -- 648 | // Matches: ./myApp -- 649 | flagName = currArg[2:] // Strip the "--" 650 | } 651 | 652 | options, flagMatched, valueMatched := target.FlagCompletion(flagName, flagValue) 653 | if valueMatched { 654 | // Value Matched. Show cmdCompletions 655 | return target.CmdCompletion(context) 656 | } 657 | 658 | // Add top level flags if we're not at the top level and no match was found. 659 | if context.SelectedCommand != nil && !flagMatched { 660 | topOptions, topFlagMatched, topValueMatched := a.FlagCompletion(flagName, flagValue) 661 | if topValueMatched { 662 | // Value Matched. Back to cmdCompletions 663 | return target.CmdCompletion(context) 664 | } 665 | 666 | if topFlagMatched { 667 | // Top level had a flag which matched the input. Return it's options. 668 | options = topOptions 669 | } else { 670 | // Add top level flags 671 | options = append(options, topOptions...) 672 | } 673 | } 674 | return options 675 | } 676 | 677 | // Perform completion for sub commands and arguments. 678 | return target.CmdCompletion(context) 679 | } 680 | 681 | func (a *Application) generateBashCompletion(context *ParseContext) { 682 | options := a.completionOptions(context) 683 | fmt.Printf("%s", strings.Join(options, "\n")) 684 | } 685 | 686 | func envarTransform(name string) string { 687 | return strings.ToUpper(envarTransformRegexp.ReplaceAllString(name, "_")) 688 | } 689 | --------------------------------------------------------------------------------