vendor files
parent
0d23a7b6bc
commit
e67d1e3466
@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Bob Matcuk
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
@ -0,0 +1,87 @@
|
||||
![Release](https://img.shields.io/github/release/bmatcuk/doublestar.svg?branch=master)
|
||||
[![Build Status](https://travis-ci.org/bmatcuk/doublestar.svg?branch=master)](https://travis-ci.org/bmatcuk/doublestar)
|
||||
[![codecov.io](https://img.shields.io/codecov/c/github/bmatcuk/doublestar.svg?branch=master)](https://codecov.io/github/bmatcuk/doublestar?branch=master)
|
||||
|
||||
# doublestar
|
||||
|
||||
**doublestar** is a [golang](http://golang.org/) implementation of path pattern matching and globbing with support for "doublestar" (aka globstar: `**`) patterns.
|
||||
|
||||
doublestar patterns match files and directories recursively. For example, if you had the following directory structure:
|
||||
|
||||
```
|
||||
grandparent
|
||||
`-- parent
|
||||
|-- child1
|
||||
`-- child2
|
||||
```
|
||||
|
||||
You could find the children with patterns such as: `**/child*`, `grandparent/**/child?`, `**/parent/*`, or even just `**` by itself (which will return all files and directories recursively).
|
||||
|
||||
## Installation
|
||||
|
||||
**doublestar** can be installed via `go get`:
|
||||
|
||||
```bash
|
||||
go get github.com/bmatcuk/doublestar
|
||||
```
|
||||
|
||||
To use it in your code, you must import it:
|
||||
|
||||
```go
|
||||
import "github.com/bmatcuk/doublestar"
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
### Match
|
||||
```go
|
||||
func Match(pattern, name string) (bool, error)
|
||||
```
|
||||
|
||||
Match returns true if `name` matches the file name `pattern` ([see below](#patterns)). `name` and `pattern` are split on forward slash (`/`) characters and may be relative or absolute.
|
||||
|
||||
Note: `Match()` is meant to be a drop-in replacement for `path.Match()`. As such, it always uses `/` as the path separator. If you are writing code that will run on systems where `/` is not the path separator (such as Windows), you want to use `PathMatch()` (below) instead.
|
||||
|
||||
|
||||
### PathMatch
|
||||
```go
|
||||
func PathMatch(pattern, name string) (bool, error)
|
||||
```
|
||||
|
||||
PathMatch returns true if `name` matches the file name `pattern` ([see below](#patterns)). The difference between Match and PathMatch is that PathMatch will automatically use your system's path separator to split `name` and `pattern`.
|
||||
|
||||
`PathMatch()` is meant to be a drop-in replacement for `filepath.Match()`.
|
||||
|
||||
### Glob
|
||||
```go
|
||||
func Glob(pattern string) ([]string, error)
|
||||
```
|
||||
|
||||
Glob finds all files and directories in the filesystem that match `pattern` ([see below](#patterns)). `pattern` may be relative (to the current working directory), or absolute.
|
||||
|
||||
`Glob()` is meant to be a drop-in replacement for `filepath.Glob()`.
|
||||
|
||||
## Patterns
|
||||
|
||||
**doublestar** supports the following special terms in the patterns:
|
||||
|
||||
Special Terms | Meaning
|
||||
------------- | -------
|
||||
`*` | matches any sequence of non-path-separators
|
||||
`**` | matches any sequence of characters, including path separators
|
||||
`?` | matches any single non-path-separator character
|
||||
`[class]` | matches any single non-path-separator character against a class of characters ([see below](#character-classes))
|
||||
`{alt1,...}` | matches a sequence of characters if one of the comma-separated alternatives matches
|
||||
|
||||
Any character with a special meaning can be escaped with a backslash (`\`).
|
||||
|
||||
### Character Classes
|
||||
|
||||
Character classes support the following:
|
||||
|
||||
Class | Meaning
|
||||
---------- | -------
|
||||
`[abc]` | matches any single character within the set
|
||||
`[a-z]` | matches any single character in the range
|
||||
`[^class]` | matches any single character which does *not* match the class
|
||||
|
@ -0,0 +1,360 @@
|
||||
package doublestar
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"path"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var ErrBadPattern = path.ErrBadPattern
|
||||
|
||||
func splitPathOnSeparator(path string, separator rune) []string {
|
||||
// if the separator is '\\', then we can just split...
|
||||
if separator == '\\' { return strings.Split(path, string(separator)) }
|
||||
|
||||
// otherwise, we need to be careful of situations where the separator was escaped
|
||||
cnt := strings.Count(path, string(separator))
|
||||
if cnt == 0 { return []string{path} }
|
||||
ret := make([]string, cnt + 1)
|
||||
pathlen := len(path)
|
||||
separatorLen := utf8.RuneLen(separator)
|
||||
idx := 0
|
||||
for start := 0; start < pathlen; {
|
||||
end := indexRuneWithEscaping(path[start:], separator)
|
||||
if end == -1 {
|
||||
end = pathlen
|
||||
} else {
|
||||
end += start
|
||||
}
|
||||
ret[idx] = path[start:end]
|
||||
start = end + separatorLen
|
||||
idx++
|
||||
}
|
||||
return ret[:idx]
|
||||
}
|
||||
|
||||
func indexRuneWithEscaping(s string, r rune) int {
|
||||
end := strings.IndexRune(s, r)
|
||||
if end == -1 { return -1 }
|
||||
if end > 0 && s[end - 1] == '\\' {
|
||||
start := end + utf8.RuneLen(r)
|
||||
end = indexRuneWithEscaping(s[start:], r)
|
||||
if end != -1 { end += start }
|
||||
}
|
||||
return end
|
||||
}
|
||||
|
||||
// Match returns true if name matches the shell file name pattern.
|
||||
// The pattern syntax is:
|
||||
//
|
||||
// pattern:
|
||||
// { term }
|
||||
// term:
|
||||
// '*' matches any sequence of non-path-separators
|
||||
// '**' matches any sequence of characters, including
|
||||
// path separators.
|
||||
// '?' matches any single non-path-separator character
|
||||
// '[' [ '^' ] { character-range } ']'
|
||||
// character class (must be non-empty)
|
||||
// '{' { term } [ ',' { term } ... ] '}'
|
||||
// c matches character c (c != '*', '?', '\\', '[')
|
||||
// '\\' c matches character c
|
||||
//
|
||||
// character-range:
|
||||
// c matches character c (c != '\\', '-', ']')
|
||||
// '\\' c matches character c
|
||||
// lo '-' hi matches character c for lo <= c <= hi
|
||||
//
|
||||
// Match requires pattern to match all of name, not just a substring.
|
||||
// The path-separator defaults to the '/' character. The only possible
|
||||
// returned error is ErrBadPattern, when pattern is malformed.
|
||||
//
|
||||
// Note: this is meant as a drop-in replacement for path.Match() which
|
||||
// always uses '/' as the path separator. If you want to support systems
|
||||
// which use a different path separator (such as Windows), what you want
|
||||
// is the PathMatch() function below.
|
||||
//
|
||||
func Match(pattern, name string) (bool, error) {
|
||||
return matchWithSeparator(pattern, name, '/')
|
||||
}
|
||||
|
||||
// PathMatch is like Match except that it uses your system's path separator.
|
||||
// For most systems, this will be '/'. However, for Windows, it would be '\\'.
|
||||
// Note that for systems where the path separator is '\\', escaping is
|
||||
// disabled.
|
||||
//
|
||||
// Note: this is meant as a drop-in replacement for filepath.Match().
|
||||
//
|
||||
func PathMatch(pattern, name string) (bool, error) {
|
||||
return matchWithSeparator(pattern, name, os.PathSeparator)
|
||||
}
|
||||
|
||||
// Match returns true if name matches the shell file name pattern.
|
||||
// The pattern syntax is:
|
||||
//
|
||||
// pattern:
|
||||
// { term }
|
||||
// term:
|
||||
// '*' matches any sequence of non-path-separators
|
||||
// '**' matches any sequence of characters, including
|
||||
// path separators.
|
||||
// '?' matches any single non-path-separator character
|
||||
// '[' [ '^' ] { character-range } ']'
|
||||
// character class (must be non-empty)
|
||||
// '{' { term } [ ',' { term } ... ] '}'
|
||||
// c matches character c (c != '*', '?', '\\', '[')
|
||||
// '\\' c matches character c
|
||||
//
|
||||
// character-range:
|
||||
// c matches character c (c != '\\', '-', ']')
|
||||
// '\\' c matches character c, unless separator is '\\'
|
||||
// lo '-' hi matches character c for lo <= c <= hi
|
||||
//
|
||||
// Match requires pattern to match all of name, not just a substring.
|
||||
// The only possible returned error is ErrBadPattern, when pattern
|
||||
// is malformed.
|
||||
//
|
||||
func matchWithSeparator(pattern, name string, separator rune) (bool, error) {
|
||||
patternComponents := splitPathOnSeparator(pattern, separator)
|
||||
nameComponents := splitPathOnSeparator(name, separator)
|
||||
return doMatching(patternComponents, nameComponents)
|
||||
}
|
||||
|
||||
func doMatching(patternComponents, nameComponents []string) (matched bool, err error) {
|
||||
patternLen, nameLen := len(patternComponents), len(nameComponents)
|
||||
if patternLen == 0 && nameLen == 0 { return true, nil }
|
||||
if patternLen == 0 || nameLen == 0 { return false, nil }
|
||||
patIdx, nameIdx := 0, 0
|
||||
for ; patIdx < patternLen && nameIdx < nameLen; {
|
||||
if patternComponents[patIdx] == "**" {
|
||||
if patIdx++; patIdx >= patternLen { return true, nil }
|
||||
for ; nameIdx < nameLen; nameIdx++ {
|
||||
if m, _ := doMatching(patternComponents[patIdx:], nameComponents[nameIdx:]); m {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
} else {
|
||||
matched, err = matchComponent(patternComponents[patIdx], nameComponents[nameIdx])
|
||||
if !matched || err != nil { return }
|
||||
}
|
||||
patIdx++
|
||||
nameIdx++
|
||||
}
|
||||
return patIdx >= patternLen && nameIdx >= nameLen, nil
|
||||
}
|
||||
|
||||
// Glob returns the names of all files matching pattern or nil
|
||||
// if there is no matching file. The syntax of pattern is the same
|
||||
// as in Match. The pattern may describe hierarchical names such as
|
||||
// /usr/*/bin/ed (assuming the Separator is '/').
|
||||
//
|
||||
// Glob ignores file system errors such as I/O errors reading directories.
|
||||
// The only possible returned error is ErrBadPattern, when pattern
|
||||
// is malformed.
|
||||
//
|
||||
// Your system path separator is automatically used. This means on
|
||||
// systems where the separator is '\\' (Windows), escaping will be
|
||||
// disabled.
|
||||
//
|
||||
// Note: this is meant as a drop-in replacement for filepath.Glob().
|
||||
//
|
||||
func Glob(pattern string) (matches []string, err error) {
|
||||
patternComponents := splitPathOnSeparator(pattern, os.PathSeparator)
|
||||
if len(patternComponents) == 0 { return nil, nil }
|
||||
|
||||
// On Windows systems, this will return the drive name ('C:'), on others,
|
||||
// it will return an empty string.
|
||||
volumeName := filepath.VolumeName(pattern)
|
||||
|
||||
// If the first pattern component is equal to the volume name, then the
|
||||
// pattern is an absolute path.
|
||||
if patternComponents[0] == volumeName {
|
||||
return doGlob(fmt.Sprintf("%s%s", volumeName, string(os.PathSeparator)), patternComponents[1:], matches)
|
||||
}
|
||||
return doGlob(".", patternComponents, matches)
|
||||
}
|
||||
|
||||
func doGlob(basedir string, components, matches []string) (m []string, e error) {
|
||||
m = matches
|
||||
e = nil
|
||||
|
||||
// figure out how many components we don't need to glob because they're
|
||||
// just straight directory names
|
||||
patLen := len(components)
|
||||
patIdx := 0
|
||||
for ; patIdx < patLen; patIdx++ {
|
||||
if strings.IndexAny(components[patIdx], "*?[{\\") >= 0 { break }
|
||||
}
|
||||
if patIdx > 0 {
|
||||
basedir = filepath.Join(basedir, filepath.Join(components[0:patIdx]...))
|
||||
}
|
||||
|
||||
// Stat will return an error if the file/directory doesn't exist
|
||||
fi, err := os.Lstat(basedir)
|
||||
if err != nil { return }
|
||||
|
||||
// if there are no more components, we've found a match
|
||||
if patIdx >= patLen {
|
||||
m = append(m, basedir)
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise, we need to check each item in the directory...
|
||||
// first, if basedir is a symlink, follow it...
|
||||
if fi.Mode() & os.ModeSymlink != 0 {
|
||||
fi, err = os.Stat(basedir)
|
||||
if err != nil { return }
|
||||
}
|
||||
|
||||
// confirm it's a directory...
|
||||
if !fi.IsDir() { return }
|
||||
|
||||
// read directory
|
||||
dir, err := os.Open(basedir)
|
||||
if err != nil { return }
|
||||
defer dir.Close()
|
||||
|
||||
files, _ := dir.Readdir(-1)
|
||||
lastComponent := patIdx + 1 >= patLen
|
||||
if components[patIdx] == "**" {
|
||||
// if the current component is a doublestar, we'll try depth-first
|
||||
for _, file := range files {
|
||||
// if symlink, we may want to follow
|
||||
if file.Mode() & os.ModeSymlink != 0 {
|
||||
file, err = os.Stat(filepath.Join(basedir, file.Name()))
|
||||
if err != nil { continue }
|
||||
}
|
||||
|
||||
if file.IsDir() {
|
||||
if lastComponent {
|
||||
m = append(m, filepath.Join(basedir, file.Name()))
|
||||
}
|
||||
m, e = doGlob(filepath.Join(basedir, file.Name()), components[patIdx:], m)
|
||||
} else if lastComponent {
|
||||
// if the pattern's last component is a doublestar, we match filenames, too
|
||||
m = append(m, filepath.Join(basedir, file.Name()))
|
||||
}
|
||||
}
|
||||
if lastComponent { return }
|
||||
patIdx++
|
||||
lastComponent = patIdx + 1 >= patLen
|
||||
}
|
||||
|
||||
var match bool
|
||||
for _, file := range files {
|
||||
match, e = matchComponent(components[patIdx], file.Name())
|
||||
if e != nil { return }
|
||||
if match {
|
||||
if lastComponent {
|
||||
m = append(m, filepath.Join(basedir, file.Name()))
|
||||
} else {
|
||||
m, e = doGlob(filepath.Join(basedir, file.Name()), components[patIdx + 1:], m)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func matchComponent(pattern, name string) (bool, error) {
|
||||
patternLen, nameLen := len(pattern), len(name)
|
||||
if patternLen == 0 && nameLen == 0 { return true, nil }
|
||||
if patternLen == 0 { return false, nil }
|
||||
if nameLen == 0 && pattern != "*" { return false, nil }
|
||||
patIdx, nameIdx := 0, 0
|
||||
for ; patIdx < patternLen && nameIdx < nameLen; {
|
||||
patRune, patAdj := utf8.DecodeRuneInString(pattern[patIdx:])
|
||||
nameRune, nameAdj := utf8.DecodeRuneInString(name[nameIdx:])
|
||||
if patRune == '\\' {
|
||||
patIdx += patAdj
|
||||
patRune, patAdj = utf8.DecodeRuneInString(pattern[patIdx:])
|
||||
if patRune == utf8.RuneError {
|
||||
return false, ErrBadPattern
|
||||
} else if patRune == nameRune {
|
||||
patIdx += patAdj
|
||||
nameIdx += nameAdj
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
} else if patRune == '*' {
|
||||
if patIdx += patAdj; patIdx >= patternLen { return true, nil }
|
||||
for ; nameIdx < nameLen; nameIdx += nameAdj {
|
||||
if m, _ := matchComponent(pattern[patIdx:], name[nameIdx:]); m {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
} else if patRune == '[' {
|
||||
patIdx += patAdj
|
||||
endClass := indexRuneWithEscaping(pattern[patIdx:], ']')
|
||||
if endClass == -1 { return false, ErrBadPattern }
|
||||
endClass += patIdx
|
||||
classRunes := []rune(pattern[patIdx:endClass])
|
||||
classRunesLen := len(classRunes)
|
||||
if classRunesLen > 0 {
|
||||
classIdx := 0
|
||||
matchClass := false
|
||||
if classRunes[0] == '^' { classIdx++ }
|
||||
for classIdx < classRunesLen {
|
||||
low := classRunes[classIdx]
|
||||
if low == '-' { return false, ErrBadPattern }
|
||||
classIdx++
|
||||
if low == '\\' {
|
||||
if classIdx < classRunesLen {
|
||||
low = classRunes[classIdx]
|
||||
classIdx++
|
||||
} else {
|
||||
return false, ErrBadPattern
|
||||
}
|
||||
}
|
||||
high := low
|
||||
if classIdx < classRunesLen && classRunes[classIdx] == '-' {
|
||||
if classIdx++; classIdx >= classRunesLen { return false, ErrBadPattern }
|
||||
high = classRunes[classIdx]
|
||||
if high == '-' { return false, ErrBadPattern }
|
||||
classIdx++
|
||||
if high == '\\' {
|
||||
if classIdx < classRunesLen {
|
||||
high = classRunes[classIdx]
|
||||
classIdx++
|
||||
} else {
|
||||
return false, ErrBadPattern
|
||||
}
|
||||
}
|
||||
}
|
||||
if low <= nameRune && nameRune <= high { matchClass = true }
|
||||
}
|
||||
if matchClass == (classRunes[0] == '^') { return false, nil }
|
||||
} else {
|
||||
return false, ErrBadPattern
|
||||
}
|
||||
patIdx = endClass + 1
|
||||
nameIdx += nameAdj
|
||||
} else if patRune == '{' {
|
||||
patIdx += patAdj
|
||||
endOptions := indexRuneWithEscaping(pattern[patIdx:], '}')
|
||||
if endOptions == -1 { return false, ErrBadPattern }
|
||||
endOptions += patIdx
|
||||
options := splitPathOnSeparator(pattern[patIdx:endOptions], ',')
|
||||
patIdx = endOptions + 1
|
||||
for _, o := range options {
|
||||
m, e := matchComponent(o + pattern[patIdx:], name[nameIdx:])
|
||||
if e != nil { return false, e }
|
||||
if m { return true, nil }
|
||||
}
|
||||
return false, nil
|
||||
} else if patRune == '?' || patRune == nameRune {
|
||||
patIdx += patAdj
|
||||
nameIdx += nameAdj
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
if patIdx >= patternLen && nameIdx >= nameLen { return true, nil }
|
||||
if nameIdx >= nameLen && pattern[patIdx:] == "*" || pattern[patIdx:] == "**" { return true, nil }
|
||||
return false, nil
|
||||
}
|
||||
|
@ -0,0 +1,392 @@
|
||||
# Change Log
|
||||
|
||||
**ATTN**: This project uses [semantic versioning](http://semver.org/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.19.1] - 2016-11-21
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixes regression introduced in 1.19.0 where using an `ActionFunc` as
|
||||
the `Action` for a command would cause it to error rather than calling the
|
||||
function. Should not have a affected declarative cases using `func(c
|
||||
*cli.Context) err)`.
|
||||
- Shell completion now handles the case where the user specifies
|
||||
`--generate-bash-completion` immediately after a flag that takes an argument.
|
||||
Previously it call the application with `--generate-bash-completion` as the
|
||||
flag value.
|
||||
|
||||
## [1.19.0] - 2016-11-19
|
||||
### Added
|
||||
- `FlagsByName` was added to make it easy to sort flags (e.g. `sort.Sort(cli.FlagsByName(app.Flags))`)
|
||||
- A `Description` field was added to `App` for a more detailed description of
|
||||
the application (similar to the existing `Description` field on `Command`)
|
||||
- Flag type code generation via `go generate`
|
||||
- Write to stderr and exit 1 if action returns non-nil error
|
||||
- Added support for TOML to the `altsrc` loader
|
||||
- `SkipArgReorder` was added to allow users to skip the argument reordering.
|
||||
This is useful if you want to consider all "flags" after an argument as
|
||||
arguments rather than flags (the default behavior of the stdlib `flag`
|
||||
library). This is backported functionality from the [removal of the flag
|
||||
reordering](https://github.com/urfave/cli/pull/398) in the unreleased version
|
||||
2
|
||||
- For formatted errors (those implementing `ErrorFormatter`), the errors will
|
||||
be formatted during output. Compatible with `pkg/errors`.
|
||||
|
||||
### Changed
|
||||
- Raise minimum tested/supported Go version to 1.2+
|
||||
|
||||
### Fixed
|
||||
- Consider empty environment variables as set (previously environment variables
|
||||
with the equivalent of `""` would be skipped rather than their value used).
|
||||
- Return an error if the value in a given environment variable cannot be parsed
|
||||
as the flag type. Previously these errors were silently swallowed.
|
||||
- Print full error when an invalid flag is specified (which includes the invalid flag)
|
||||
- `App.Writer` defaults to `stdout` when `nil`
|
||||
- If no action is specified on a command or app, the help is now printed instead of `panic`ing
|
||||
- `App.Metadata` is initialized automatically now (previously was `nil` unless initialized)
|
||||
- Correctly show help message if `-h` is provided to a subcommand
|
||||
- `context.(Global)IsSet` now respects environment variables. Previously it
|
||||
would return `false` if a flag was specified in the environment rather than
|
||||
as an argument
|
||||
- Removed deprecation warnings to STDERR to avoid them leaking to the end-user
|
||||
- `altsrc`s import paths were updated to use `gopkg.in/urfave/cli.v1`. This
|
||||
fixes issues that occurred when `gopkg.in/urfave/cli.v1` was imported as well
|
||||
as `altsrc` where Go would complain that the types didn't match
|
||||
|
||||
## [1.18.1] - 2016-08-28
|
||||
### Fixed
|
||||
- Removed deprecation warnings to STDERR to avoid them leaking to the end-user (backported)
|
||||
|
||||
## [1.18.0] - 2016-06-27
|
||||
### Added
|
||||
- `./runtests` test runner with coverage tracking by default
|
||||
- testing on OS X
|
||||
- testing on Windows
|
||||
- `UintFlag`, `Uint64Flag`, and `Int64Flag` types and supporting code
|
||||
|
||||
### Changed
|
||||
- Use spaces for alignment in help/usage output instead of tabs, making the
|
||||
output alignment consistent regardless of tab width
|
||||
|
||||
### Fixed
|
||||
- Printing of command aliases in help text
|
||||
- Printing of visible flags for both struct and struct pointer flags
|
||||
- Display the `help` subcommand when using `CommandCategories`
|
||||
- No longer swallows `panic`s that occur within the `Action`s themselves when
|
||||
detecting the signature of the `Action` field
|
||||
|
||||
## [1.17.1] - 2016-08-28
|
||||
### Fixed
|
||||
- Removed deprecation warnings to STDERR to avoid them leaking to the end-user
|
||||
|
||||
## [1.17.0] - 2016-05-09
|
||||
### Added
|
||||
- Pluggable flag-level help text rendering via `cli.DefaultFlagStringFunc`
|
||||
- `context.GlobalBoolT` was added as an analogue to `context.GlobalBool`
|
||||
- Support for hiding commands by setting `Hidden: true` -- this will hide the
|
||||
commands in help output
|
||||
|
||||
### Changed
|
||||
- `Float64Flag`, `IntFlag`, and `DurationFlag` default values are no longer
|
||||
quoted in help text output.
|
||||
- All flag types now include `(default: {value})` strings following usage when a
|
||||
default value can be (reasonably) detected.
|
||||
- `IntSliceFlag` and `StringSliceFlag` usage strings are now more consistent
|
||||
with non-slice flag types
|
||||
- Apps now exit with a code of 3 if an unknown subcommand is specified
|
||||
(previously they printed "No help topic for...", but still exited 0. This
|
||||
makes it easier to script around apps built using `cli` since they can trust
|
||||
that a 0 exit code indicated a successful execution.
|
||||
- cleanups based on [Go Report Card
|
||||
feedback](https://goreportcard.com/report/github.com/urfave/cli)
|
||||
|
||||
## [1.16.1] - 2016-08-28
|
||||
### Fixed
|
||||
- Removed deprecation warnings to STDERR to avoid them leaking to the end-user
|
||||
|
||||
## [1.16.0] - 2016-05-02
|
||||
### Added
|
||||
- `Hidden` field on all flag struct types to omit from generated help text
|
||||
|
||||
### Changed
|
||||
- `BashCompletionFlag` (`--enable-bash-completion`) is now omitted from
|
||||
generated help text via the `Hidden` field
|
||||
|
||||
### Fixed
|
||||
- handling of error values in `HandleAction` and `HandleExitCoder`
|
||||
|
||||
## [1.15.0] - 2016-04-30
|
||||
### Added
|
||||
- This file!
|
||||
- Support for placeholders in flag usage strings
|
||||
- `App.Metadata` map for arbitrary data/state management
|
||||
- `Set` and `GlobalSet` methods on `*cli.Context` for altering values after
|
||||
parsing.
|
||||
- Support for nested lookup of dot-delimited keys in structures loaded from
|
||||
YAML.
|
||||
|
||||
### Changed
|
||||
- The `App.Action` and `Command.Action` now prefer a return signature of
|
||||
`func(*cli.Context) error`, as defined by `cli.ActionFunc`. If a non-nil
|
||||
`error` is returned, there may be two outcomes:
|
||||
- If the error fulfills `cli.ExitCoder`, then `os.Exit` will be called
|
||||
automatically
|
||||
- Else the error is bubbled up and returned from `App.Run`
|
||||
- Specifying an `Action` with the legacy return signature of
|
||||
`func(*cli.Context)` will produce a deprecation message to stderr
|
||||
- Specifying an `Action` that is not a `func` type will produce a non-zero exit
|
||||
from `App.Run`
|
||||
- Specifying an `Action` func that has an invalid (input) signature will
|
||||
produce a non-zero exit from `App.Run`
|
||||
|
||||
### Deprecated
|
||||
- <a name="deprecated-cli-app-runandexitonerror"></a>
|
||||
`cli.App.RunAndExitOnError`, which should now be done by returning an error
|
||||
that fulfills `cli.ExitCoder` to `cli.App.Run`.
|
||||
- <a name="deprecated-cli-app-action-signature"></a> the legacy signature for
|
||||
`cli.App.Action` of `func(*cli.Context)`, which should now have a return
|
||||
signature of `func(*cli.Context) error`, as defined by `cli.ActionFunc`.
|
||||
|
||||
### Fixed
|
||||
- Added missing `*cli.Context.GlobalFloat64` method
|
||||
|
||||
## [1.14.0] - 2016-04-03 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- Codebeat badge
|
||||
- Support for categorization via `CategorizedHelp` and `Categories` on app.
|
||||
|
||||
### Changed
|
||||
- Use `filepath.Base` instead of `path.Base` in `Name` and `HelpName`.
|
||||
|
||||
### Fixed
|
||||
- Ensure version is not shown in help text when `HideVersion` set.
|
||||
|
||||
## [1.13.0] - 2016-03-06 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- YAML file input support.
|
||||
- `NArg` method on context.
|
||||
|
||||
## [1.12.0] - 2016-02-17 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- Custom usage error handling.
|
||||
- Custom text support in `USAGE` section of help output.
|
||||
- Improved help messages for empty strings.
|
||||
- AppVeyor CI configuration.
|
||||
|
||||
### Changed
|
||||
- Removed `panic` from default help printer func.
|
||||
- De-duping and optimizations.
|
||||
|
||||
### Fixed
|
||||
- Correctly handle `Before`/`After` at command level when no subcommands.
|
||||
- Case of literal `-` argument causing flag reordering.
|
||||
- Environment variable hints on Windows.
|
||||
- Docs updates.
|
||||
|
||||
## [1.11.1] - 2015-12-21 (backfilled 2016-04-25)
|
||||
### Changed
|
||||
- Use `path.Base` in `Name` and `HelpName`
|
||||
- Export `GetName` on flag types.
|
||||
|
||||
### Fixed
|
||||
- Flag parsing when skipping is enabled.
|
||||
- Test output cleanup.
|
||||
- Move completion check to account for empty input case.
|
||||
|
||||
## [1.11.0] - 2015-11-15 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- Destination scan support for flags.
|
||||
- Testing against `tip` in Travis CI config.
|
||||
|
||||
### Changed
|
||||
- Go version in Travis CI config.
|
||||
|
||||
### Fixed
|
||||
- Removed redundant tests.
|
||||
- Use correct example naming in tests.
|
||||
|
||||
## [1.10.2] - 2015-10-29 (backfilled 2016-04-25)
|
||||
### Fixed
|
||||
- Remove unused var in bash completion.
|
||||
|
||||
## [1.10.1] - 2015-10-21 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- Coverage and reference logos in README.
|
||||
|
||||
### Fixed
|
||||
- Use specified values in help and version parsing.
|
||||
- Only display app version and help message once.
|
||||
|
||||
## [1.10.0] - 2015-10-06 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- More tests for existing functionality.
|
||||
- `ArgsUsage` at app and command level for help text flexibility.
|
||||
|
||||
### Fixed
|
||||
- Honor `HideHelp` and `HideVersion` in `App.Run`.
|
||||
- Remove juvenile word from README.
|
||||
|
||||
## [1.9.0] - 2015-09-08 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- `FullName` on command with accompanying help output update.
|
||||
- Set default `$PROG` in bash completion.
|
||||
|
||||
### Changed
|
||||
- Docs formatting.
|
||||
|
||||
### Fixed
|
||||
- Removed self-referential imports in tests.
|
||||
|
||||
## [1.8.0] - 2015-06-30 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- Support for `Copyright` at app level.
|
||||
- `Parent` func at context level to walk up context lineage.
|
||||
|
||||
### Fixed
|
||||
- Global flag processing at top level.
|
||||
|
||||
## [1.7.1] - 2015-06-11 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- Aggregate errors from `Before`/`After` funcs.
|
||||
- Doc comments on flag structs.
|
||||
- Include non-global flags when checking version and help.
|
||||
- Travis CI config updates.
|
||||
|
||||
### Fixed
|
||||
- Ensure slice type flags have non-nil values.
|
||||
- Collect global flags from the full command hierarchy.
|
||||
- Docs prose.
|
||||
|
||||
## [1.7.0] - 2015-05-03 (backfilled 2016-04-25)
|
||||
### Changed
|
||||
- `HelpPrinter` signature includes output writer.
|
||||
|
||||
### Fixed
|
||||
- Specify go 1.1+ in docs.
|
||||
- Set `Writer` when running command as app.
|
||||
|
||||
## [1.6.0] - 2015-03-23 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- Multiple author support.
|
||||
- `NumFlags` at context level.
|
||||
- `Aliases` at command level.
|
||||
|
||||
### Deprecated
|
||||
- `ShortName` at command level.
|
||||
|
||||
### Fixed
|
||||
- Subcommand help output.
|
||||
- Backward compatible support for deprecated `Author` and `Email` fields.
|
||||
- Docs regarding `Names`/`Aliases`.
|
||||
|
||||
## [1.5.0] - 2015-02-20 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- `After` hook func support at app and command level.
|
||||
|
||||
### Fixed
|
||||
- Use parsed context when running command as subcommand.
|
||||
- Docs prose.
|
||||
|
||||
## [1.4.1] - 2015-01-09 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- Support for hiding `-h / --help` flags, but not `help` subcommand.
|
||||
- Stop flag parsing after `--`.
|
||||
|
||||
### Fixed
|
||||
- Help text for generic flags to specify single value.
|
||||
- Use double quotes in output for defaults.
|
||||
- Use `ParseInt` instead of `ParseUint` for int environment var values.
|
||||
- Use `0` as base when parsing int environment var values.
|
||||
|
||||
## [1.4.0] - 2014-12-12 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- Support for environment variable lookup "cascade".
|
||||
- Support for `Stdout` on app for output redirection.
|
||||
|
||||
### Fixed
|
||||
- Print command help instead of app help in `ShowCommandHelp`.
|
||||
|
||||
## [1.3.1] - 2014-11-13 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- Docs and example code updates.
|
||||
|
||||
### Changed
|
||||
- Default `-v / --version` flag made optional.
|
||||
|
||||
## [1.3.0] - 2014-08-10 (backfilled 2016-04-25)
|
||||
### Added
|
||||
- `FlagNames` at context level.
|
||||
- Exposed `VersionPrinter` var for more control over version output.
|
||||
- Zsh completion hook.
|
||||
- `AUTHOR` section in default app help template.
|
||||
- Contribution guidelines.
|
||||
- `DurationFlag` type.
|
||||
|
||||
## [1.2.0] - 2014-08-02
|
||||
### Added
|
||||
- Support for environment variable defaults on flags plus tests.
|
||||
|
||||
## [1.1.0] - 2014-07-15
|
||||
### Added
|
||||
- Bash completion.
|
||||
- Optional hiding of built-in help command.
|
||||
- Optional skipping of flag parsing at command level.
|
||||
- `Author`, `Email`, and `Compiled` metadata on app.
|
||||
- `Before` hook func support at app and command level.
|
||||
- `CommandNotFound` func support at app level.
|
||||
- Command reference available on context.
|
||||
- `GenericFlag` type.
|
||||
- `Float64Flag` type.
|
||||
- `BoolTFlag` type.
|
||||
- `IsSet` flag helper on context.
|
||||
- More flag lookup funcs at context level.
|
||||
- More tests & docs.
|
||||
|
||||
### Changed
|
||||
- Help template updates to account for presence/absence of flags.
|
||||
- Separated subcommand help template.
|
||||
- Exposed `HelpPrinter` var for more control over help output.
|
||||
|
||||
## [1.0.0] - 2013-11-01
|
||||
### Added
|
||||
- `help` flag in default app flag set and each command flag set.
|
||||
- Custom handling of argument parsing errors.
|
||||
- Command lookup by name at app level.
|
||||
- `StringSliceFlag` type and supporting `StringSlice` type.
|
||||
- `IntSliceFlag` type and supporting `IntSlice` type.
|
||||
- Slice type flag lookups by name at context level.
|
||||
- Export of app and command help functions.
|
||||
- More tests & docs.
|
||||
|
||||
## 0.1.0 - 2013-07-22
|
||||
### Added
|
||||
- Initial implementation.
|
||||
|
||||
[Unreleased]: https://github.com/urfave/cli/compare/v1.18.0...HEAD
|
||||
[1.18.0]: https://github.com/urfave/cli/compare/v1.17.0...v1.18.0
|
||||
[1.17.0]: https://github.com/urfave/cli/compare/v1.16.0...v1.17.0
|
||||
[1.16.0]: https://github.com/urfave/cli/compare/v1.15.0...v1.16.0
|
||||
[1.15.0]: https://github.com/urfave/cli/compare/v1.14.0...v1.15.0
|
||||
[1.14.0]: https://github.com/urfave/cli/compare/v1.13.0...v1.14.0
|
||||
[1.13.0]: https://github.com/urfave/cli/compare/v1.12.0...v1.13.0
|
||||
[1.12.0]: https://github.com/urfave/cli/compare/v1.11.1...v1.12.0
|
||||
[1.11.1]: https://github.com/urfave/cli/compare/v1.11.0...v1.11.1
|
||||
[1.11.0]: https://github.com/urfave/cli/compare/v1.10.2...v1.11.0
|
||||
[1.10.2]: https://github.com/urfave/cli/compare/v1.10.1...v1.10.2
|
||||
[1.10.1]: https://github.com/urfave/cli/compare/v1.10.0...v1.10.1
|
||||
[1.10.0]: https://github.com/urfave/cli/compare/v1.9.0...v1.10.0
|
||||
[1.9.0]: https://github.com/urfave/cli/compare/v1.8.0...v1.9.0
|
||||
[1.8.0]: https://github.com/urfave/cli/compare/v1.7.1...v1.8.0
|
||||
[1.7.1]: https://github.com/urfave/cli/compare/v1.7.0...v1.7.1
|
||||
[1.7.0]: https://github.com/urfave/cli/compare/v1.6.0...v1.7.0
|
||||
[1.6.0]: https://github.com/urfave/cli/compare/v1.5.0...v1.6.0
|
||||
[1.5.0]: https://github.com/urfave/cli/compare/v1.4.1...v1.5.0
|
||||
[1.4.1]: https://github.com/urfave/cli/compare/v1.4.0...v1.4.1
|
||||
[1.4.0]: https://github.com/urfave/cli/compare/v1.3.1...v1.4.0
|
||||
[1.3.1]: https://github.com/urfave/cli/compare/v1.3.0...v1.3.1
|
||||
[1.3.0]: https://github.com/urfave/cli/compare/v1.2.0...v1.3.0
|
||||
[1.2.0]: https://github.com/urfave/cli/compare/v1.1.0...v1.2.0
|
||||
[1.1.0]: https://github.com/urfave/cli/compare/v1.0.0...v1.1.0
|
||||
[1.0.0]: https://github.com/urfave/cli/compare/v0.1.0...v1.0.0
|
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Jeremy Saenz & Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,293 @@
|
||||
mode: set
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:19.45,21.2 1 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:25.45,28.2 2 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:32.60,35.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:45.48,47.2 1 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:51.46,54.2 2 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:58.61,61.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:71.57,73.2 1 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:77.49,80.2 2 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:84.64,87.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:97.54,99.2 1 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:103.48,106.2 2 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:110.63,113.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:123.54,125.2 1 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:129.48,132.2 2 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:136.63,139.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:149.48,151.2 1 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:155.46,158.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:162.61,165.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:175.42,177.2 1 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:181.44,184.2 2 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:188.59,191.2 2 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:201.57,203.2 1 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:207.49,210.2 2 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:214.64,217.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:227.63,229.2 1 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:233.51,236.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:240.66,243.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:253.51,255.2 1 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:259.47,262.2 2 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:266.62,269.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:279.66,281.2 1 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:285.52,288.2 2 1
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:292.67,295.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:305.51,307.2 1 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:311.47,314.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:318.62,321.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:331.45,333.2 1 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:337.45,340.2 2 0
|
||||
github.com/urfave/cli/altsrc/flag_generated.go:344.60,347.2 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:21.83,22.61 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:39.2,39.19 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:22.61,24.54 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:35.3,35.53 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:24.54,25.39 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:25.39,27.5 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:27.5,28.62 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:28.62,30.6 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:30.6,32.6 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:35.53,37.4 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:43.58,45.12 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:52.2,53.12 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:61.2,61.15 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:45.12,47.14 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:50.3,50.25 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:47.14,49.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:53.12,55.14 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:58.3,58.25 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:55.14,57.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:65.73,67.12 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:74.2,75.12 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:83.2,83.15 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:67.12,69.14 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:72.3,72.25 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:69.14,71.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:75.12,77.14 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:80.3,80.25 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:77.14,79.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:87.66,89.12 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:96.2,97.12 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:105.2,105.15 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:89.12,91.14 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:94.3,94.25 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:91.14,93.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:97.12,99.14 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:102.3,102.25 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:99.14,101.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:109.64,111.12 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:118.2,119.12 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:127.2,127.16 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:111.12,113.14 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:116.3,116.25 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:113.14,115.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:119.12,121.14 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:124.3,124.25 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:121.14,123.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:131.71,133.13 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:140.2,141.13 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:145.2,146.31 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:156.2,156.25 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:133.13,135.14 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:135.14,137.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:141.13,143.3 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:146.31,149.14 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:153.3,153.49 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:149.14,151.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:160.65,162.13 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:169.2,170.13 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:174.2,175.31 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:185.2,185.22 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:162.13,164.14 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:164.14,166.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:170.13,172.3 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:175.31,178.14 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:182.3,182.40 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:178.14,180.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:189.70,191.12 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:198.2,199.12 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:207.2,207.17 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:191.12,193.14 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:196.3,196.25 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:193.14,195.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:199.12,201.14 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:204.3,204.25 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:201.14,203.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:211.60,213.12 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:220.2,221.12 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:229.2,229.19 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:213.12,215.14 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:218.3,218.25 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:215.14,217.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:221.12,223.14 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:226.3,226.25 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:223.14,225.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:233.61,235.12 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:242.2,243.12 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:251.2,251.18 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:235.12,237.14 2 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:240.3,240.25 1 1
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:237.14,239.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:243.12,245.14 2 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:248.3,248.25 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:245.14,247.4 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:254.88,257.22 3 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:261.2,261.125 1 0
|
||||
github.com/urfave/cli/altsrc/map_input_source.go:257.22,259.3 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:20.79,23.26 3 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:66.2,66.17 1 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:23.26,25.19 2 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:26.21,27.25 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:28.23,29.27 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:30.20,31.29 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:32.21,33.30 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:34.22,35.31 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:36.22,37.31 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:38.22,39.31 1 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:40.21,41.30 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:42.22,43.31 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:44.23,45.32 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:46.23,47.32 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:48.23,49.32 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:50.24,51.37 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:52.24,53.37 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:54.20,55.49 1 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:60.37,61.34 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:62.11,63.63 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:55.49,57.5 1 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:57.5,59.5 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:69.57,70.45 1 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:75.2,75.12 1 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:70.45,72.3 1 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:72.3,74.3 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:83.69,86.64 3 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:89.2,89.52 1 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:86.64,88.3 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:93.108,94.64 1 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:94.64,97.3 2 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:100.74,102.16 2 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:106.2,107.16 2 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:111.2,112.8 2 1
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:102.16,104.3 1 0
|
||||
github.com/urfave/cli/altsrc/toml_file_loader.go:107.16,109.3 1 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:27.69,31.16 4 1
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:35.2,35.48 1 1
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:31.16,33.3 1 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:39.108,40.64 1 1
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:40.64,43.3 2 1
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:46.74,48.16 2 1
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:52.2,53.16 2 1
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:57.2,58.8 2 1
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:48.16,50.3 1 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:53.16,55.3 1 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:61.52,63.16 2 1
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:67.2,67.18 1 1
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:63.16,65.3 1 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:67.18,68.19 1 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:69.24,71.18 2 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:74.4,74.35 1 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:75.11,76.67 1 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:71.18,73.5 1 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:78.3,78.25 1 1
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:78.25,79.70 1 1
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:82.3,82.35 1 1
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:79.70,81.4 1 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:83.3,83.76 1 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:83.76,85.70 1 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:88.3,88.35 1 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:85.70,87.4 1 0
|
||||
github.com/urfave/cli/altsrc/yaml_file_loader.go:89.3,91.3 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:23.114,24.26 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:34.2,34.12 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:24.26,26.13 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:26.13,28.18 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:28.18,30.5 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:40.109,41.42 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:41.42,43.17 2 0
|
||||
github.com/urfave/cli/altsrc/flag.go:47.3,47.61 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:43.17,45.4 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:54.140,55.42 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:55.42,57.17 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:61.3,61.61 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:57.17,59.4 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:66.97,67.18 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:81.2,81.12 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:67.18,68.55 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:68.55,70.18 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:73.4,73.20 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:70.18,72.5 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:73.20,74.40 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:74.40,76.6 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:85.101,86.18 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:103.2,103.12 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:86.18,87.55 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:87.55,89.18 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:92.4,92.20 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:89.18,91.5 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:92.20,94.40 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:94.40,96.31 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:96.31,98.7 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:107.98,108.18 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:125.2,125.12 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:108.18,109.55 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:109.55,111.18 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:114.4,114.20 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:111.18,113.5 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:114.20,116.40 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:116.40,118.31 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:118.31,120.7 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:129.94,130.18 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:143.2,143.12 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:130.18,131.55 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:131.55,133.18 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:136.4,136.13 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:133.18,135.5 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:136.13,137.40 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:137.40,139.6 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:147.95,148.18 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:161.2,161.12 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:148.18,149.55 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:149.55,151.18 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:154.4,154.14 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:151.18,153.5 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:154.14,155.40 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:155.40,157.6 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:165.96,166.18 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:179.2,179.12 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:166.18,167.56 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:167.56,169.18 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:172.4,172.19 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:169.18,171.5 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:172.19,173.40 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:173.40,175.6 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:183.93,184.18 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:197.2,197.12 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:184.18,185.56 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:185.56,187.18 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:190.4,190.17 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:187.18,189.5 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:190.17,191.40 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:191.40,193.6 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:201.98,202.18 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:215.2,215.12 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:202.18,203.56 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:203.56,205.18 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:208.4,208.17 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:205.18,207.5 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:208.17,209.40 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:209.40,211.6 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:219.97,220.18 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:234.2,234.12 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:220.18,221.56 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:221.56,223.18 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:226.4,226.17 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:223.18,225.5 1 0
|
||||
github.com/urfave/cli/altsrc/flag.go:226.17,228.40 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:228.40,230.6 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:237.39,238.53 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:248.2,248.14 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:238.53,240.42 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:240.42,245.4 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:251.40,253.2 1 1
|
||||
github.com/urfave/cli/altsrc/flag.go:255.49,257.29 2 1
|
||||
github.com/urfave/cli/altsrc/flag.go:257.29,260.3 2 1
|
@ -0,0 +1,492 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
changeLogURL = "https://github.com/urfave/cli/blob/master/CHANGELOG.md"
|
||||
appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL)
|
||||
runAndExitOnErrorDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-runandexitonerror", changeLogURL)
|
||||
|
||||
contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you."
|
||||
|
||||
errInvalidActionType = NewExitError("ERROR invalid Action type. "+
|
||||
fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+
|
||||
fmt.Sprintf("See %s", appActionDeprecationURL), 2)
|
||||
)
|
||||
|
||||
// App is the main structure of a cli application. It is recommended that
|
||||
// an app be created with the cli.NewApp() function
|
||||
type App struct {
|
||||
// The name of the program. Defaults to path.Base(os.Args[0])
|
||||
Name string
|
||||
// Full name of command for help, defaults to Name
|
||||
HelpName string
|
||||
// Description of the program.
|
||||
Usage string
|
||||
// Text to override the USAGE section of help
|
||||
UsageText string
|
||||
// Description of the program argument format.
|
||||
ArgsUsage string
|
||||
// Version of the program
|
||||
Version string
|
||||
// Description of the program
|
||||
Description string
|
||||
// List of commands to execute
|
||||
Commands []Command
|
||||
// List of flags to parse
|
||||
Flags []Flag
|
||||
// Boolean to enable bash completion commands
|
||||
EnableBashCompletion bool
|
||||
// Boolean to hide built-in help command
|
||||
HideHelp bool
|
||||
// Boolean to hide built-in version flag and the VERSION section of help
|
||||
HideVersion bool
|
||||
// Populate on app startup, only gettable through method Categories()
|
||||
categories CommandCategories
|
||||
// An action to execute when the bash-completion flag is set
|
||||
BashComplete BashCompleteFunc
|
||||
// An action to execute before any subcommands are run, but after the context is ready
|
||||
// If a non-nil error is returned, no subcommands are run
|
||||
Before BeforeFunc
|
||||
// An action to execute after any subcommands are run, but after the subcommand has finished
|
||||
// It is run even if Action() panics
|
||||
After AfterFunc
|
||||
|
||||
// The action to execute when no subcommands are specified
|
||||
// Expects a `cli.ActionFunc` but will accept the *deprecated* signature of `func(*cli.Context) {}`
|
||||
// *Note*: support for the deprecated `Action` signature will be removed in a future version
|
||||
Action interface{}
|
||||
|
||||
// Execute this function if the proper command cannot be found
|
||||
CommandNotFound CommandNotFoundFunc
|
||||
// Execute this function if an usage error occurs
|
||||
OnUsageError OnUsageErrorFunc
|
||||
// Compilation date
|
||||
Compiled time.Time
|
||||
// List of all authors who contributed
|
||||
Authors []Author
|
||||
// Copyright of the binary if any
|
||||
Copyright string
|
||||
// Name of Author (Note: Use App.Authors, this is deprecated)
|
||||
Author string
|
||||
// Email of Author (Note: Use App.Authors, this is deprecated)
|
||||
Email string
|
||||
// Writer writer to write output to
|
||||
Writer io.Writer
|
||||
// ErrWriter writes error output
|
||||
ErrWriter io.Writer
|
||||
// Other custom info
|
||||
Metadata map[string]interface{}
|
||||
|
||||
didSetup bool
|
||||
}
|
||||
|
||||
// Tries to find out when this binary was compiled.
|
||||
// Returns the current time if it fails to find it.
|
||||
func compileTime() time.Time {
|
||||
info, err := os.Stat(os.Args[0])
|
||||
if err != nil {
|
||||
return time.Now()
|
||||
}
|
||||
return info.ModTime()
|
||||
}
|
||||
|
||||
// NewApp creates a new cli Application with some reasonable defaults for Name,
|
||||
// Usage, Version and Action.
|
||||
func NewApp() *App {
|
||||
return &App{
|
||||
Name: filepath.Base(os.Args[0]),
|
||||
HelpName: filepath.Base(os.Args[0]),
|
||||
Usage: "A new cli application",
|
||||
UsageText: "",
|
||||
Version: "0.0.0",
|
||||
BashComplete: DefaultAppComplete,
|
||||
Action: helpCommand.Action,
|
||||
Compiled: compileTime(),
|
||||
Writer: os.Stdout,
|
||||
}
|
||||
}
|
||||
|
||||
// Setup runs initialization code to ensure all data structures are ready for
|
||||
// `Run` or inspection prior to `Run`. It is internally called by `Run`, but
|
||||
// will return early if setup has already happened.
|
||||
func (a *App) Setup() {
|
||||
if a.didSetup {
|
||||
return
|
||||
}
|
||||
|
||||
a.didSetup = true
|
||||
|
||||
if a.Author != "" || a.Email != "" {
|
||||
a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
|
||||
}
|
||||
|
||||
newCmds := []Command{}
|
||||
for _, c := range a.Commands {
|
||||
if c.HelpName == "" {
|
||||
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
|
||||
}
|
||||
newCmds = append(newCmds, c)
|
||||
}
|
||||
a.Commands = newCmds
|
||||
|
||||
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
||||
a.Commands = append(a.Commands, helpCommand)
|
||||
if (HelpFlag != BoolFlag{}) {
|
||||
a.appendFlag(HelpFlag)
|
||||
}
|
||||
}
|
||||
|
||||
if !a.HideVersion {
|
||||
a.appendFlag(VersionFlag)
|
||||
}
|
||||
|
||||
a.categories = CommandCategories{}
|
||||
for _, command := range a.Commands {
|
||||
a.categories = a.categories.AddCommand(command.Category, command)
|
||||
}
|
||||
sort.Sort(a.categories)
|
||||
|
||||
if a.Metadata == nil {
|
||||
a.Metadata = make(map[string]interface{})
|
||||
}
|
||||
|
||||
if a.Writer == nil {
|
||||
a.Writer = os.Stdout
|
||||
}
|
||||
}
|
||||
|
||||
// Run is the entry point to the cli app. Parses the arguments slice and routes
|
||||
// to the proper flag/args combination
|
||||
func (a *App) Run(arguments []string) (err error) {
|
||||
a.Setup()
|
||||
|
||||
// handle the completion flag separately from the flagset since
|
||||
// completion could be attempted after a flag, but before its value was put
|
||||
// on the command line. this causes the flagset to interpret the completion
|
||||
// flag name as the value of the flag before it which is undesirable
|
||||
// note that we can only do this because the shell autocomplete function
|
||||
// always appends the completion flag at the end of the command
|
||||
shellComplete, arguments := checkShellCompleteFlag(a, arguments)
|
||||
|
||||
// parse flags
|
||||
set, err := flagSet(a.Name, a.Flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
set.SetOutput(ioutil.Discard)
|
||||
err = set.Parse(arguments[1:])
|
||||
nerr := normalizeFlags(a.Flags, set)
|
||||
context := NewContext(a, set, nil)
|
||||
if nerr != nil {
|
||||
fmt.Fprintln(a.Writer, nerr)
|
||||
ShowAppHelp(context)
|
||||
return nerr
|
||||
}
|
||||
context.shellComplete = shellComplete
|
||||
|
||||
if checkCompletions(context) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if a.OnUsageError != nil {
|
||||
err := a.OnUsageError(context, err, false)
|
||||
HandleExitCoder(err)
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
|
||||
ShowAppHelp(context)
|
||||
return err
|
||||
}
|
||||
|
||||
if !a.HideHelp && checkHelp(context) {
|
||||
ShowAppHelp(context)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !a.HideVersion && checkVersion(context) {
|
||||
ShowVersion(context)
|
||||
return nil
|
||||
}
|
||||
|
||||
if a.After != nil {
|
||||
defer func() {
|
||||
if afterErr := a.After(context); afterErr != nil {
|
||||
if err != nil {
|
||||
err = NewMultiError(err, afterErr)
|
||||
} else {
|
||||
err = afterErr
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if a.Before != nil {
|
||||
beforeErr := a.Before(context)
|
||||
if beforeErr != nil {
|
||||
fmt.Fprintf(a.Writer, "%v\n\n", beforeErr)
|
||||
ShowAppHelp(context)
|
||||
HandleExitCoder(beforeErr)
|
||||
err = beforeErr
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
args := context.Args()
|
||||
if args.Present() {
|
||||
name := args.First()
|
||||
c := a.Command(name)
|
||||
if c != nil {
|
||||
return c.Run(context)
|
||||
}
|
||||
}
|
||||
|
||||
if a.Action == nil {
|
||||
a.Action = helpCommand.Action
|
||||
}
|
||||
|
||||
// Run default Action
|
||||
err = HandleAction(a.Action, context)
|
||||
|
||||
HandleExitCoder(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// RunAndExitOnError calls .Run() and exits non-zero if an error was returned
|
||||
//
|
||||
// Deprecated: instead you should return an error that fulfills cli.ExitCoder
|
||||
// to cli.App.Run. This will cause the application to exit with the given eror
|
||||
// code in the cli.ExitCoder
|
||||
func (a *App) RunAndExitOnError() {
|
||||
if err := a.Run(os.Args); err != nil {
|
||||
fmt.Fprintln(a.errWriter(), err)
|
||||
OsExiter(1)
|
||||
}
|
||||
}
|
||||
|
||||
// RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to
|
||||
// generate command-specific flags
|
||||
func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
||||
// append help to commands
|
||||
if len(a.Commands) > 0 {
|
||||
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
||||
a.Commands = append(a.Commands, helpCommand)
|
||||
if (HelpFlag != BoolFlag{}) {
|
||||
a.appendFlag(HelpFlag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newCmds := []Command{}
|
||||
for _, c := range a.Commands {
|
||||
if c.HelpName == "" {
|
||||
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
|
||||
}
|
||||
newCmds = append(newCmds, c)
|
||||
}
|
||||
a.Commands = newCmds
|
||||
|
||||
// parse flags
|
||||
set, err := flagSet(a.Name, a.Flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
set.SetOutput(ioutil.Discard)
|
||||
err = set.Parse(ctx.Args().Tail())
|
||||
nerr := normalizeFlags(a.Flags, set)
|
||||
context := NewContext(a, set, ctx)
|
||||
|
||||
if nerr != nil {
|
||||
fmt.Fprintln(a.Writer, nerr)
|
||||
fmt.Fprintln(a.Writer)
|
||||
if len(a.Commands) > 0 {
|
||||
ShowSubcommandHelp(context)
|
||||
} else {
|
||||
ShowCommandHelp(ctx, context.Args().First())
|
||||
}
|
||||
return nerr
|
||||
}
|
||||
|
||||
if checkCompletions(context) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if a.OnUsageError != nil {
|
||||
err = a.OnUsageError(context, err, true)
|
||||
HandleExitCoder(err)
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
|
||||
ShowSubcommandHelp(context)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(a.Commands) > 0 {
|
||||
if checkSubcommandHelp(context) {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
if checkCommandHelp(ctx, context.Args().First()) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if a.After != nil {
|
||||
defer func() {
|
||||
afterErr := a.After(context)
|
||||
if afterErr != nil {
|
||||
HandleExitCoder(err)
|
||||
if err != nil {
|
||||
err = NewMultiError(err, afterErr)
|
||||
} else {
|
||||
err = afterErr
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if a.Before != nil {
|
||||
beforeErr := a.Before(context)
|
||||
if beforeErr != nil {
|
||||
HandleExitCoder(beforeErr)
|
||||
err = beforeErr
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
args := context.Args()
|
||||
if args.Present() {
|
||||
name := args.First()
|
||||
c := a.Command(name)
|
||||
if c != nil {
|
||||
return c.Run(context)
|
||||
}
|
||||
}
|
||||
|
||||
// Run default Action
|
||||
err = HandleAction(a.Action, context)
|
||||
|
||||
HandleExitCoder(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Command returns the named command on App. Returns nil if the command does not exist
|
||||
func (a *App) Command(name string) *Command {
|
||||
for _, c := range a.Commands {
|
||||
if c.HasName(name) {
|
||||
return &c
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Categories returns a slice containing all the categories with the commands they contain
|
||||
func (a *App) Categories() CommandCategories {
|
||||
return a.categories
|
||||
}
|
||||
|
||||
// VisibleCategories returns a slice of categories and commands that are
|
||||
// Hidden=false
|
||||
func (a *App) VisibleCategories() []*CommandCategory {
|
||||
ret := []*CommandCategory{}
|
||||
for _, category := range a.categories {
|
||||
if visible := func() *CommandCategory {
|
||||
for _, command := range category.Commands {
|
||||
if !command.Hidden {
|
||||
return category
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}(); visible != nil {
|
||||
ret = append(ret, visible)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// VisibleCommands returns a slice of the Commands with Hidden=false
|
||||
func (a *App) VisibleCommands() []Command {
|
||||
ret := []Command{}
|
||||
for _, command := range a.Commands {
|
||||
if !command.Hidden {
|
||||
ret = append(ret, command)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// VisibleFlags returns a slice of the Flags with Hidden=false
|
||||
func (a *App) VisibleFlags() []Flag {
|
||||
return visibleFlags(a.Flags)
|
||||
}
|
||||
|
||||
func (a *App) hasFlag(flag Flag) bool {
|
||||
for _, f := range a.Flags {
|
||||
if flag == f {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *App) errWriter() io.Writer {
|
||||
|
||||
// When the app ErrWriter is nil use the package level one.
|
||||
if a.ErrWriter == nil {
|
||||
return ErrWriter
|
||||
}
|
||||
|
||||
return a.ErrWriter
|
||||
}
|
||||
|
||||
func (a *App) appendFlag(flag Flag) {
|
||||
if !a.hasFlag(flag) {
|
||||
a.Flags = append(a.Flags, flag)
|
||||
}
|
||||
}
|
||||
|
||||
// Author represents someone who has contributed to a cli project.
|
||||
type Author struct {
|
||||
Name string // The Authors name
|
||||
Email string // The Authors email
|
||||
}
|
||||
|
||||
// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
|
||||
func (a Author) String() string {
|
||||
e := ""
|
||||
if a.Email != "" {
|
||||
e = " <" + a.Email + ">"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v%v", a.Name, e)
|
||||
}
|
||||
|
||||
// HandleAction attempts to figure out which Action signature was used. If
|
||||
// it's an ActionFunc or a func with the legacy signature for Action, the func
|
||||
// is run!
|
||||
func HandleAction(action interface{}, context *Context) (err error) {
|
||||
if a, ok := action.(ActionFunc); ok {
|
||||
return a(context)
|
||||
} else if a, ok := action.(func(*Context) error); ok {
|
||||
return a(context)
|
||||
} else if a, ok := action.(func(*Context)); ok { // deprecated function signature
|
||||
a(context)
|
||||
return nil
|
||||
} else {
|
||||
return errInvalidActionType
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@
|
||||
version: "{build}"
|
||||
|
||||
os: Windows Server 2012 R2
|
||||
|
||||
clone_folder: c:\gopath\src\github.com\urfave\cli
|
||||
|
||||
environment:
|
||||
GOPATH: C:\gopath
|
||||
GOVERSION: 1.6
|
||||
PYTHON: C:\Python27-x64
|
||||
PYTHON_VERSION: 2.7.x
|
||||
PYTHON_ARCH: 64
|
||||
|
||||
install:
|
||||
- set PATH=%GOPATH%\bin;C:\go\bin;%PATH%
|
||||
- go version
|
||||
- go env
|
||||
- go get github.com/urfave/gfmrun/...
|
||||
- go get -v -t ./...
|
||||
|
||||
build_script:
|
||||
- python runtests vet
|
||||
- python runtests test
|
||||
- python runtests gfmrun
|
@ -0,0 +1,44 @@
|
||||
package cli
|
||||
|
||||
// CommandCategories is a slice of *CommandCategory.
|
||||
type CommandCategories []*CommandCategory
|
||||
|
||||
// CommandCategory is a category containing commands.
|
||||
type CommandCategory struct {
|
||||
Name string
|
||||
Commands Commands
|
||||
}
|
||||
|
||||
func (c CommandCategories) Less(i, j int) bool {
|
||||
return c[i].Name < c[j].Name
|
||||
}
|
||||
|
||||
func (c CommandCategories) Len() int {
|
||||
return len(c)
|
||||
}
|
||||
|
||||
func (c CommandCategories) Swap(i, j int) {
|
||||
c[i], c[j] = c[j], c[i]
|
||||
}
|
||||
|
||||
// AddCommand adds a command to a category.
|
||||
func (c CommandCategories) AddCommand(category string, command Command) CommandCategories {
|
||||
for _, commandCategory := range c {
|
||||
if commandCategory.Name == category {
|
||||
commandCategory.Commands = append(commandCategory.Commands, command)
|
||||
return c
|
||||
}
|
||||
}
|
||||
return append(c, &CommandCategory{Name: category, Commands: []Command{command}})
|
||||
}
|
||||
|
||||
// VisibleCommands returns a slice of the Commands with Hidden=false
|
||||
func (c *CommandCategory) VisibleCommands() []Command {
|
||||
ret := []Command{}
|
||||
for _, command := range c.Commands {
|
||||
if !command.Hidden {
|
||||
ret = append(ret, command)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
@ -0,0 +1,765 @@
|
||||
mode: set
|
||||
github.com/urfave/cli/app.go:94.30,96.16 2 1
|
||||
github.com/urfave/cli/app.go:99.2,99.23 1 1
|
||||
github.com/urfave/cli/app.go:96.16,98.3 1 1
|
||||
github.com/urfave/cli/app.go:104.20,116.2 1 1
|
||||
github.com/urfave/cli/app.go:121.23,122.16 1 1
|
||||
github.com/urfave/cli/app.go:126.2,128.37 2 1
|
||||
github.com/urfave/cli/app.go:132.2,133.31 2 1
|
||||
github.com/urfave/cli/app.go:139.2,141.55 2 1
|
||||
github.com/urfave/cli/app.go:148.2,148.20 1 1
|
||||
github.com/urfave/cli/app.go:152.2,153.37 2 1
|
||||
github.com/urfave/cli/app.go:156.2,158.23 2 1
|
||||
github.com/urfave/cli/app.go:162.2,162.21 1 1
|
||||
github.com/urfave/cli/app.go:122.16,124.3 1 1
|
||||
github.com/urfave/cli/app.go:128.37,130.3 1 1
|
||||
github.com/urfave/cli/app.go:133.31,134.23 1 1
|
||||
github.com/urfave/cli/app.go:137.3,137.31 1 1
|
||||
github.com/urfave/cli/app.go:134.23,136.4 1 1
|
||||
github.com/urfave/cli/app.go:141.55,143.31 2 1
|
||||
github.com/urfave/cli/app.go:143.31,145.4 1 1
|
||||
github.com/urfave/cli/app.go:148.20,150.3 1 1
|
||||
github.com/urfave/cli/app.go:153.37,155.3 1 1
|
||||
github.com/urfave/cli/app.go:158.23,160.3 1 1
|
||||
github.com/urfave/cli/app.go:162.21,164.3 1 1
|
||||
github.com/urfave/cli/app.go:169.51,182.16 4 1
|
||||
github.com/urfave/cli/app.go:186.2,190.17 5 1
|
||||
github.com/urfave/cli/app.go:195.2,197.31 2 1
|
||||
github.com/urfave/cli/app.go:201.2,201.16 1 1
|
||||
github.com/urfave/cli/app.go:212.2,212.39 1 1
|
||||
github.com/urfave/cli/app.go:217.2,217.45 1 1
|
||||
github.com/urfave/cli/app.go:222.2,222.20 1 1
|
||||
github.com/urfave/cli/app.go:234.2,234.21 1 1
|
||||
github.com/urfave/cli/app.go:245.2,246.20 2 1
|
||||
github.com/urfave/cli/app.go:254.2,254.21 1 1
|
||||
github.com/urfave/cli/app.go:259.2,262.12 3 1
|
||||
github.com/urfave/cli/app.go:182.16,184.3 1 1
|
||||
github.com/urfave/cli/app.go:190.17,194.3 3 0
|
||||
github.com/urfave/cli/app.go:197.31,199.3 1 1
|
||||
github.com/urfave/cli/app.go:201.16,202.28 1 1
|
||||
github.com/urfave/cli/app.go:207.3,209.13 3 1
|
||||
github.com/urfave/cli/app.go:202.28,206.4 3 1
|
||||
github.com/urfave/cli/app.go:212.39,215.3 2 1
|
||||
github.com/urfave/cli/app.go:217.45,220.3 2 1
|
||||
github.com/urfave/cli/app.go:222.20,223.16 1 1
|
||||
github.com/urfave/cli/app.go:223.16,224.53 1 1
|
||||
github.com/urfave/cli/app.go:224.53,225.19 1 1
|
||||
github.com/urfave/cli/app.go:225.19,227.6 1 1
|
||||
github.com/urfave/cli/app.go:227.6,229.6 1 1
|
||||
github.com/urfave/cli/app.go:234.21,236.23 2 1
|
||||
github.com/urfave/cli/app.go:236.23,242.4 5 1
|
||||
github.com/urfave/cli/app.go:246.20,249.15 3 1
|
||||
github.com/urfave/cli/app.go:249.15,251.4 1 1
|
||||
github.com/urfave/cli/app.go:254.21,256.3 1 1
|
||||
github.com/urfave/cli/app.go:270.35,271.39 1 0
|
||||
github.com/urfave/cli/app.go:271.39,274.3 2 0
|
||||
github.com/urfave/cli/app.go:279.57,281.25 1 1
|
||||
github.com/urfave/cli/app.go:290.2,291.31 2 1
|
||||
github.com/urfave/cli/app.go:297.2,301.16 3 1
|
||||
github.com/urfave/cli/app.go:305.2,310.17 5 1
|
||||
github.com/urfave/cli/app.go:321.2,321.31 1 1
|
||||
github.com/urfave/cli/app.go:325.2,325.16 1 1
|
||||
github.com/urfave/cli/app.go:336.2,336.25 1 1
|
||||
github.com/urfave/cli/app.go:346.2,346.20 1 1
|
||||
github.com/urfave/cli/app.go:360.2,360.21 1 1
|
||||
github.com/urfave/cli/app.go:369.2,370.20 2 1
|
||||
github.com/urfave/cli/app.go:379.2,382.12 3 0
|
||||
github.com/urfave/cli/app.go:281.25,282.56 1 1
|
||||
github.com/urfave/cli/app.go:282.56,284.32 2 1
|
||||
github.com/urfave/cli/app.go:284.32,286.5 1 1
|
||||
github.com/urfave/cli/app.go:291.31,292.23 1 1
|
||||
github.com/urfave/cli/app.go:295.3,295.31 1 1
|
||||
github.com/urfave/cli/app.go:292.23,294.4 1 1
|
||||
github.com/urfave/cli/app.go:301.16,303.3 1 0
|
||||
github.com/urfave/cli/app.go:310.17,313.26 3 0
|
||||
github.com/urfave/cli/app.go:318.3,318.14 1 0
|
||||
github.com/urfave/cli/app.go:313.26,315.4 1 0
|
||||
github.com/urfave/cli/app.go:315.4,317.4 1 0
|
||||
github.com/urfave/cli/app.go:321.31,323.3 1 0
|
||||
github.com/urfave/cli/app.go:325.16,326.28 1 1
|
||||
github.com/urfave/cli/app.go:331.3,333.13 3 1
|
||||
github.com/urfave/cli/app.go:326.28,330.4 3 0
|
||||
github.com/urfave/cli/app.go:336.25,337.35 1 1
|
||||
github.com/urfave/cli/app.go:337.35,339.4 1 1
|
||||
github.com/urfave/cli/app.go:340.3,341.52 1 0
|
||||
github.com/urfave/cli/app.go:341.52,343.4 1 0
|
||||
github.com/urfave/cli/app.go:346.20,347.16 1 1
|
||||
github.com/urfave/cli/app.go:347.16,349.23 2 1
|
||||
github.com/urfave/cli/app.go:349.23,351.19 2 1
|
||||
github.com/urfave/cli/app.go:351.19,353.6 1 1
|
||||
github.com/urfave/cli/app.go:353.6,355.6 1 0
|
||||
github.com/urfave/cli/app.go:360.21,362.23 2 1
|
||||
github.com/urfave/cli/app.go:362.23,366.4 3 1
|
||||
github.com/urfave/cli/app.go:370.20,373.15 3 1
|
||||
github.com/urfave/cli/app.go:373.15,375.4 1 1
|
||||
github.com/urfave/cli/app.go:386.45,387.31 1 1
|
||||
github.com/urfave/cli/app.go:393.2,393.12 1 1
|
||||
github.com/urfave/cli/app.go:387.31,388.22 1 1
|
||||
github.com/urfave/cli/app.go:388.22,390.4 1 1
|
||||
github.com/urfave/cli/app.go:397.46,399.2 1 1
|
||||
github.com/urfave/cli/app.go:403.54,405.40 2 1
|
||||
github.com/urfave/cli/app.go:417.2,417.12 1 1
|
||||
github.com/urfave/cli/app.go:405.40,406.41 1 1
|
||||
github.com/urfave/cli/app.go:406.41,407.46 1 1
|
||||
github.com/urfave/cli/app.go:412.4,412.14 1 1
|
||||
github.com/urfave/cli/app.go:407.46,408.24 1 1
|
||||
github.com/urfave/cli/app.go:408.24,410.6 1 1
|
||||
github.com/urfave/cli/app.go:413.23,415.4 1 1
|
||||
github.com/urfave/cli/app.go:421.43,423.37 2 1
|
||||
github.com/urfave/cli/app.go:428.2,428.12 1 1
|
||||
github.com/urfave/cli/app.go:423.37,424.22 1 1
|
||||
github.com/urfave/cli/app.go:424.22,426.4 1 1
|
||||
github.com/urfave/cli/app.go:432.37,434.2 1 1
|
||||
github.com/urfave/cli/app.go:436.39,437.28 1 1
|
||||
github.com/urfave/cli/app.go:443.2,443.14 1 1
|
||||
github.com/urfave/cli/app.go:437.28,438.16 1 1
|
||||
github.com/urfave/cli/app.go:438.16,440.4 1 0
|
||||
github.com/urfave/cli/app.go:446.37,449.24 1 0
|
||||
github.com/urfave/cli/app.go:453.2,453.20 1 0
|
||||
github.com/urfave/cli/app.go:449.24,451.3 1 0
|
||||
github.com/urfave/cli/app.go:456.37,457.22 1 1
|
||||
github.com/urfave/cli/app.go:457.22,459.3 1 1
|
||||
github.com/urfave/cli/app.go:469.33,471.19 2 1
|
||||
github.com/urfave/cli/app.go:475.2,475.39 1 1
|
||||
github.com/urfave/cli/app.go:471.19,473.3 1 1
|
||||
github.com/urfave/cli/app.go:481.69,482.38 1 1
|
||||
github.com/urfave/cli/app.go:482.38,484.3 1 1
|
||||
github.com/urfave/cli/app.go:484.3,484.55 1 1
|
||||
github.com/urfave/cli/app.go:484.55,486.3 1 1
|
||||
github.com/urfave/cli/app.go:486.3,486.49 1 1
|
||||
github.com/urfave/cli/app.go:486.49,489.3 2 0
|
||||
github.com/urfave/cli/app.go:489.3,491.3 1 1
|
||||
github.com/urfave/cli/command.go:66.35,68.2 1 0
|
||||
github.com/urfave/cli/command.go:70.45,72.2 1 0
|
||||
github.com/urfave/cli/command.go:74.40,76.2 1 0
|
||||
github.com/urfave/cli/command.go:80.36,81.30 1 0
|
||||
github.com/urfave/cli/command.go:84.2,84.45 1 0
|
||||
github.com/urfave/cli/command.go:81.30,83.3 1 0
|
||||
github.com/urfave/cli/command.go:91.48,92.28 1 1
|
||||
github.com/urfave/cli/command.go:96.2,96.45 1 1
|
||||
github.com/urfave/cli/command.go:104.2,105.16 2 1
|
||||
github.com/urfave/cli/command.go:108.2,110.23 2 1
|
||||
github.com/urfave/cli/command.go:148.2,149.17 2 1
|
||||
github.com/urfave/cli/command.go:156.2,157.46 2 1
|
||||
github.com/urfave/cli/command.go:161.2,161.16 1 1
|
||||
github.com/urfave/cli/command.go:173.2,173.39 1 1
|
||||
github.com/urfave/cli/command.go:177.2,177.20 1 1
|
||||
github.com/urfave/cli/command.go:191.2,191.21 1 1
|
||||
github.com/urfave/cli/command.go:202.2,202.21 1 1
|
||||
github.com/urfave/cli/command.go:206.2,209.16 3 1
|
||||
github.com/urfave/cli/command.go:212.2,212.12 1 1
|
||||
github.com/urfave/cli/command.go:92.28,94.3 1 1
|
||||
github.com/urfave/cli/command.go:96.45,102.3 1 1
|
||||
github.com/urfave/cli/command.go:105.16,107.3 1 0
|
||||
github.com/urfave/cli/command.go:110.23,112.3 1 1
|
||||
github.com/urfave/cli/command.go:112.3,112.30 1 1
|
||||
github.com/urfave/cli/command.go:112.30,115.38 3 1
|
||||
github.com/urfave/cli/command.go:127.3,127.26 1 1
|
||||
github.com/urfave/cli/command.go:115.38,116.19 1 1
|
||||
github.com/urfave/cli/command.go:116.19,118.10 2 1
|
||||
github.com/urfave/cli/command.go:119.5,119.25 1 1
|
||||
github.com/urfave/cli/command.go:119.25,121.13 1 1
|
||||
github.com/urfave/cli/command.go:122.5,122.66 1 1
|
||||
github.com/urfave/cli/command.go:122.66,124.5 1 1
|
||||
github.com/urfave/cli/command.go:127.26,133.28 5 1
|
||||
github.com/urfave/cli/command.go:140.4,140.53 1 1
|
||||
github.com/urfave/cli/command.go:133.28,136.5 2 1
|
||||
github.com/urfave/cli/command.go:136.5,138.5 1 1
|
||||
github.com/urfave/cli/command.go:141.4,143.4 1 1
|
||||
github.com/urfave/cli/command.go:144.3,146.3 1 1
|
||||
github.com/urfave/cli/command.go:149.17,154.3 4 0
|
||||
github.com/urfave/cli/command.go:157.46,159.3 1 0
|
||||
github.com/urfave/cli/command.go:161.16,162.28 1 1
|
||||
github.com/urfave/cli/command.go:167.3,170.13 4 1
|
||||
github.com/urfave/cli/command.go:162.28,166.4 3 1
|
||||
github.com/urfave/cli/command.go:173.39,175.3 1 1
|
||||
github.com/urfave/cli/command.go:177.20,178.16 1 1
|
||||
github.com/urfave/cli/command.go:178.16,180.23 2 1
|
||||
github.com/urfave/cli/command.go:180.23,182.19 2 1
|
||||
github.com/urfave/cli/command.go:182.19,184.6 1 1
|
||||
github.com/urfave/cli/command.go:184.6,186.6 1 0
|
||||
github.com/urfave/cli/command.go:191.21,193.17 2 1
|
||||
github.com/urfave/cli/command.go:193.17,199.4 5 1
|
||||
github.com/urfave/cli/command.go:202.21,204.3 1 1
|
||||
github.com/urfave/cli/command.go:209.16,211.3 1 0
|
||||
github.com/urfave/cli/command.go:216.35,219.23 2 1
|
||||
github.com/urfave/cli/command.go:223.2,223.36 1 1
|
||||
github.com/urfave/cli/command.go:219.23,221.3 1 0
|
||||
github.com/urfave/cli/command.go:227.44,228.30 1 1
|
||||
github.com/urfave/cli/command.go:233.2,233.14 1 1
|
||||
github.com/urfave/cli/command.go:228.30,229.16 1 1
|
||||
github.com/urfave/cli/command.go:229.16,231.4 1 1
|
||||
github.com/urfave/cli/command.go:236.47,241.22 4 1
|
||||
github.com/urfave/cli/command.go:247.2,268.40 16 1
|
||||
github.com/urfave/cli/command.go:272.2,276.27 3 1
|
||||
github.com/urfave/cli/command.go:281.2,283.21 3 1
|
||||
github.com/urfave/cli/command.go:289.2,289.38 1 1
|
||||
github.com/urfave/cli/command.go:293.2,293.33 1 1
|
||||
github.com/urfave/cli/command.go:241.22,243.3 1 0
|
||||
github.com/urfave/cli/command.go:243.3,245.3 1 1
|
||||
github.com/urfave/cli/command.go:268.40,270.3 1 1
|
||||
github.com/urfave/cli/command.go:276.27,278.3 1 0
|
||||
github.com/urfave/cli/command.go:283.21,285.3 1 1
|
||||
github.com/urfave/cli/command.go:285.3,287.3 1 1
|
||||
github.com/urfave/cli/command.go:289.38,291.3 1 1
|
||||
github.com/urfave/cli/command.go:297.40,299.2 1 1
|
||||
github.com/urfave/cli/help.go:86.33,88.21 2 1
|
||||
github.com/urfave/cli/help.go:92.3,93.13 2 1
|
||||
github.com/urfave/cli/help.go:88.21,90.4 1 1
|
||||
github.com/urfave/cli/help.go:102.33,104.21 2 1
|
||||
github.com/urfave/cli/help.go:108.3,108.31 1 1
|
||||
github.com/urfave/cli/help.go:104.21,106.4 1 1
|
||||
github.com/urfave/cli/help.go:124.36,127.2 2 1
|
||||
github.com/urfave/cli/help.go:130.37,131.41 1 1
|
||||
github.com/urfave/cli/help.go:131.41,132.21 1 1
|
||||
github.com/urfave/cli/help.go:135.3,135.40 1 1
|
||||
github.com/urfave/cli/help.go:132.21,133.12 1 0
|
||||
github.com/urfave/cli/help.go:135.40,137.4 1 1
|
||||
github.com/urfave/cli/help.go:142.58,144.19 1 1
|
||||
github.com/urfave/cli/help.go:149.2,149.37 1 1
|
||||
github.com/urfave/cli/help.go:156.2,156.36 1 1
|
||||
github.com/urfave/cli/help.go:160.2,161.12 2 1
|
||||
github.com/urfave/cli/help.go:144.19,147.3 2 1
|
||||
github.com/urfave/cli/help.go:149.37,150.25 1 1
|
||||
github.com/urfave/cli/help.go:150.25,153.4 2 1
|
||||
github.com/urfave/cli/help.go:156.36,158.3 1 1
|
||||
github.com/urfave/cli/help.go:165.43,167.2 1 1
|
||||
github.com/urfave/cli/help.go:170.30,172.2 1 1
|
||||
github.com/urfave/cli/help.go:174.31,176.2 1 1
|
||||
github.com/urfave/cli/help.go:179.34,181.39 2 1
|
||||
github.com/urfave/cli/help.go:181.39,183.3 1 1
|
||||
github.com/urfave/cli/help.go:187.59,189.39 2 0
|
||||
github.com/urfave/cli/help.go:189.39,191.3 1 0
|
||||
github.com/urfave/cli/help.go:194.63,202.16 5 1
|
||||
github.com/urfave/cli/help.go:210.2,210.11 1 1
|
||||
github.com/urfave/cli/help.go:202.16,205.50 1 0
|
||||
github.com/urfave/cli/help.go:208.3,208.9 1 0
|
||||
github.com/urfave/cli/help.go:205.50,207.4 1 0
|
||||
github.com/urfave/cli/help.go:213.36,215.28 2 1
|
||||
github.com/urfave/cli/help.go:222.2,222.14 1 1
|
||||
github.com/urfave/cli/help.go:215.28,216.48 1 1
|
||||
github.com/urfave/cli/help.go:216.48,217.42 1 1
|
||||
github.com/urfave/cli/help.go:217.42,219.5 1 1
|
||||
github.com/urfave/cli/help.go:225.33,227.25 2 1
|
||||
github.com/urfave/cli/help.go:234.2,234.14 1 1
|
||||
github.com/urfave/cli/help.go:227.25,228.45 1 1
|
||||
github.com/urfave/cli/help.go:228.45,229.42 1 1
|
||||
github.com/urfave/cli/help.go:229.42,231.5 1 1
|
||||
github.com/urfave/cli/help.go:237.53,238.35 1 1
|
||||
github.com/urfave/cli/help.go:243.2,243.14 1 1
|
||||
github.com/urfave/cli/help.go:238.35,241.3 2 1
|
||||
github.com/urfave/cli/help.go:246.43,247.35 1 1
|
||||
github.com/urfave/cli/help.go:252.2,252.14 1 1
|
||||
github.com/urfave/cli/help.go:247.35,250.3 2 1
|
||||
github.com/urfave/cli/help.go:255.74,256.29 1 1
|
||||
github.com/urfave/cli/help.go:260.2,263.45 3 1
|
||||
github.com/urfave/cli/help.go:267.2,267.30 1 1
|
||||
github.com/urfave/cli/help.go:256.29,258.3 1 1
|
||||
github.com/urfave/cli/help.go:263.45,265.3 1 1
|
||||
github.com/urfave/cli/help.go:270.40,271.22 1 1
|
||||
github.com/urfave/cli/help.go:275.2,275.38 1 1
|
||||
github.com/urfave/cli/help.go:283.2,284.13 2 1
|
||||
github.com/urfave/cli/help.go:271.22,273.3 1 1
|
||||
github.com/urfave/cli/help.go:275.38,277.45 2 0
|
||||
github.com/urfave/cli/help.go:277.45,280.4 1 0
|
||||
github.com/urfave/cli/help.go:287.60,288.22 1 1
|
||||
github.com/urfave/cli/help.go:292.2,293.13 2 0
|
||||
github.com/urfave/cli/help.go:288.22,290.3 1 1
|
||||
github.com/urfave/cli/category.go:12.48,14.2 1 1
|
||||
github.com/urfave/cli/category.go:16.38,18.2 1 1
|
||||
github.com/urfave/cli/category.go:20.43,22.2 1 0
|
||||
github.com/urfave/cli/category.go:25.91,26.36 1 1
|
||||
github.com/urfave/cli/category.go:32.2,32.82 1 1
|
||||
github.com/urfave/cli/category.go:26.36,27.39 1 1
|
||||
github.com/urfave/cli/category.go:27.39,30.4 2 1
|
||||
github.com/urfave/cli/category.go:36.55,38.37 2 1
|
||||
github.com/urfave/cli/category.go:43.2,43.12 1 1
|
||||
github.com/urfave/cli/category.go:38.37,39.22 1 1
|
||||
github.com/urfave/cli/category.go:39.22,41.4 1 1
|
||||
github.com/urfave/cli/context.go:26.75,29.22 2 1
|
||||
github.com/urfave/cli/context.go:33.2,33.10 1 1
|
||||
github.com/urfave/cli/context.go:29.22,31.3 1 1
|
||||
github.com/urfave/cli/context.go:37.34,39.2 1 1
|
||||
github.com/urfave/cli/context.go:42.49,44.2 1 1
|
||||
github.com/urfave/cli/context.go:47.55,49.2 1 1
|
||||
github.com/urfave/cli/context.go:52.43,53.23 1 1
|
||||
github.com/urfave/cli/context.go:119.2,119.25 1 1
|
||||
github.com/urfave/cli/context.go:53.23,56.38 2 1
|
||||
github.com/urfave/cli/context.go:60.3,60.41 1 1
|
||||
github.com/urfave/cli/context.go:78.3,79.27 2 1
|
||||
github.com/urfave/cli/context.go:84.3,84.27 1 1
|
||||
github.com/urfave/cli/context.go:56.38,58.4 1 1
|
||||
github.com/urfave/cli/context.go:60.41,61.39 1 1
|
||||
github.com/urfave/cli/context.go:64.4,64.30 1 1
|
||||
github.com/urfave/cli/context.go:61.39,63.5 1 1
|
||||
github.com/urfave/cli/context.go:79.27,80.20 1 1
|
||||
github.com/urfave/cli/context.go:80.20,82.5 1 1
|
||||
github.com/urfave/cli/context.go:84.27,85.44 1 1
|
||||
github.com/urfave/cli/context.go:85.44,86.52 1 1
|
||||
github.com/urfave/cli/context.go:90.5,91.34 2 1
|
||||
github.com/urfave/cli/context.go:95.5,96.32 2 1
|
||||
github.com/urfave/cli/context.go:105.5,106.30 2 1
|
||||
github.com/urfave/cli/context.go:86.52,88.6 1 1
|
||||
github.com/urfave/cli/context.go:91.34,93.6 1 0
|
||||
github.com/urfave/cli/context.go:96.32,97.61 1 1
|
||||
github.com/urfave/cli/context.go:97.61,98.50 1 1
|
||||
github.com/urfave/cli/context.go:98.50,101.8 2 0
|
||||
github.com/urfave/cli/context.go:106.30,107.57 1 1
|
||||
github.com/urfave/cli/context.go:107.57,109.46 2 1
|
||||
github.com/urfave/cli/context.go:109.46,112.8 2 1
|
||||
github.com/urfave/cli/context.go:123.49,125.30 2 1
|
||||
github.com/urfave/cli/context.go:129.2,129.44 1 1
|
||||
github.com/urfave/cli/context.go:134.2,134.14 1 1
|
||||
github.com/urfave/cli/context.go:125.30,127.3 1 1
|
||||
github.com/urfave/cli/context.go:129.44,130.22 1 1
|
||||
github.com/urfave/cli/context.go:130.22,132.4 1 1
|
||||
github.com/urfave/cli/context.go:138.48,139.39 1 0
|
||||
github.com/urfave/cli/context.go:146.2,146.8 1 0
|
||||
github.com/urfave/cli/context.go:139.39,141.21 2 0
|
||||
github.com/urfave/cli/context.go:144.3,144.30 1 0
|
||||
github.com/urfave/cli/context.go:141.21,142.12 1 0
|
||||
github.com/urfave/cli/context.go:150.54,151.35 1 0
|
||||
github.com/urfave/cli/context.go:158.2,158.8 1 0
|
||||
github.com/urfave/cli/context.go:151.35,153.42 2 0
|
||||
github.com/urfave/cli/context.go:156.3,156.30 1 0
|
||||
github.com/urfave/cli/context.go:153.42,154.12 1 0
|
||||
github.com/urfave/cli/context.go:162.37,164.2 1 0
|
||||
github.com/urfave/cli/context.go:167.50,169.2 1 1
|
||||
github.com/urfave/cli/context.go:175.31,178.2 2 1
|
||||
github.com/urfave/cli/context.go:181.30,183.2 1 1
|
||||
github.com/urfave/cli/context.go:186.33,187.16 1 1
|
||||
github.com/urfave/cli/context.go:190.2,190.11 1 0
|
||||
github.com/urfave/cli/context.go:187.16,189.3 1 1
|
||||
github.com/urfave/cli/context.go:194.30,196.2 1 1
|
||||
github.com/urfave/cli/context.go:200.31,201.17 1 1
|
||||
github.com/urfave/cli/context.go:204.2,204.19 1 1
|
||||
github.com/urfave/cli/context.go:201.17,203.3 1 1
|
||||
github.com/urfave/cli/context.go:208.30,210.2 1 1
|
||||
github.com/urfave/cli/context.go:213.40,214.36 1 0
|
||||
github.com/urfave/cli/context.go:217.2,218.12 2 0
|
||||
github.com/urfave/cli/context.go:214.36,216.3 1 0
|
||||
github.com/urfave/cli/context.go:221.43,222.16 1 1
|
||||
github.com/urfave/cli/context.go:226.2,226.6 1 1
|
||||
github.com/urfave/cli/context.go:222.16,224.3 1 0
|
||||
github.com/urfave/cli/context.go:226.6,227.31 1 1
|
||||
github.com/urfave/cli/context.go:230.3,230.26 1 1
|
||||
github.com/urfave/cli/context.go:227.31,229.4 1 1
|
||||
github.com/urfave/cli/context.go:234.67,235.30 1 1
|
||||
github.com/urfave/cli/context.go:238.2,238.44 1 1
|
||||
github.com/urfave/cli/context.go:243.2,243.12 1 1
|
||||
github.com/urfave/cli/context.go:235.30,237.3 1 1
|
||||
github.com/urfave/cli/context.go:238.44,239.46 1 1
|
||||
github.com/urfave/cli/context.go:239.46,241.4 1 1
|
||||
github.com/urfave/cli/context.go:246.62,247.25 1 1
|
||||
github.com/urfave/cli/context.go:248.20,248.20 0 1
|
||||
github.com/urfave/cli/context.go:249.10,250.35 1 1
|
||||
github.com/urfave/cli/context.go:254.60,256.31 2 1
|
||||
github.com/urfave/cli/context.go:259.2,259.26 1 1
|
||||
github.com/urfave/cli/context.go:284.2,284.12 1 1
|
||||
github.com/urfave/cli/context.go:256.31,258.3 1 1
|
||||
github.com/urfave/cli/context.go:259.26,261.22 2 1
|
||||
github.com/urfave/cli/context.go:264.3,265.30 2 1
|
||||
github.com/urfave/cli/context.go:274.3,274.16 1 1
|
||||
github.com/urfave/cli/context.go:277.3,277.30 1 1
|
||||
github.com/urfave/cli/context.go:261.22,262.12 1 1
|
||||
github.com/urfave/cli/context.go:265.30,267.21 2 1
|
||||
github.com/urfave/cli/context.go:267.21,268.18 1 1
|
||||
github.com/urfave/cli/context.go:271.5,271.26 1 1
|
||||
github.com/urfave/cli/context.go:268.18,270.6 1 0
|
||||
github.com/urfave/cli/context.go:274.16,275.12 1 1
|
||||
github.com/urfave/cli/context.go:277.30,279.22 2 1
|
||||
github.com/urfave/cli/context.go:279.22,281.5 1 1
|
||||
github.com/urfave/cli/errors.go:23.45,25.2 1 1
|
||||
github.com/urfave/cli/errors.go:28.36,30.31 2 1
|
||||
github.com/urfave/cli/errors.go:34.2,34.33 1 1
|
||||
github.com/urfave/cli/errors.go:30.31,32.3 1 1
|
||||
github.com/urfave/cli/errors.go:55.65,60.2 1 1
|
||||
github.com/urfave/cli/errors.go:64.37,66.2 1 1
|
||||
github.com/urfave/cli/errors.go:70.37,72.2 1 1
|
||||
github.com/urfave/cli/errors.go:78.33,79.16 1 1
|
||||
github.com/urfave/cli/errors.go:83.2,83.40 1 1
|
||||
github.com/urfave/cli/errors.go:95.2,95.42 1 1
|
||||
github.com/urfave/cli/errors.go:79.16,81.3 1 1
|
||||
github.com/urfave/cli/errors.go:83.40,84.24 1 1
|
||||
github.com/urfave/cli/errors.go:91.3,92.9 2 1
|
||||
github.com/urfave/cli/errors.go:84.24,85.45 1 1
|
||||
github.com/urfave/cli/errors.go:85.45,87.5 1 0
|
||||
github.com/urfave/cli/errors.go:87.5,89.5 1 1
|
||||
github.com/urfave/cli/errors.go:95.42,99.3 3 1
|
||||
github.com/urfave/cli/errors.go:102.48,104.39 2 1
|
||||
github.com/urfave/cli/errors.go:114.2,114.13 1 1
|
||||
github.com/urfave/cli/errors.go:104.39,105.45 1 1
|
||||
github.com/urfave/cli/errors.go:105.45,107.4 1 0
|
||||
github.com/urfave/cli/errors.go:107.4,109.43 2 1
|
||||
github.com/urfave/cli/errors.go:109.43,111.5 1 1
|
||||
github.com/urfave/cli/flag.go:44.32,46.2 1 0
|
||||
github.com/urfave/cli/flag.go:48.42,50.2 1 0
|
||||
github.com/urfave/cli/flag.go:52.37,54.2 1 0
|
||||
github.com/urfave/cli/flag.go:75.64,78.26 2 1
|
||||
github.com/urfave/cli/flag.go:88.2,88.17 1 1
|
||||
github.com/urfave/cli/flag.go:78.26,80.38 1 1
|
||||
github.com/urfave/cli/flag.go:80.38,81.49 1 1
|
||||
github.com/urfave/cli/flag.go:81.49,83.5 1 1
|
||||
github.com/urfave/cli/flag.go:84.4,86.4 1 0
|
||||
github.com/urfave/cli/flag.go:91.49,93.29 2 1
|
||||
github.com/urfave/cli/flag.go:93.29,96.3 2 1
|
||||
github.com/urfave/cli/flag.go:108.47,110.2 1 0
|
||||
github.com/urfave/cli/flag.go:114.62,116.61 2 1
|
||||
github.com/urfave/cli/flag.go:122.2,122.37 1 1
|
||||
github.com/urfave/cli/flag.go:126.2,126.12 1 1
|
||||
github.com/urfave/cli/flag.go:116.61,117.41 1 1
|
||||
github.com/urfave/cli/flag.go:117.41,119.4 1 0
|
||||
github.com/urfave/cli/flag.go:122.37,124.3 1 1
|
||||
github.com/urfave/cli/flag.go:133.47,136.2 2 1
|
||||
github.com/urfave/cli/flag.go:139.39,141.2 1 1
|
||||
github.com/urfave/cli/flag.go:144.40,146.2 1 1
|
||||
github.com/urfave/cli/flag.go:149.41,151.2 1 1
|
||||
github.com/urfave/cli/flag.go:155.51,157.2 1 0
|
||||
github.com/urfave/cli/flag.go:160.66,161.61 1 1
|
||||
github.com/urfave/cli/flag.go:172.2,172.37 1 1
|
||||
github.com/urfave/cli/flag.go:179.2,179.12 1 1
|
||||
github.com/urfave/cli/flag.go:161.61,163.48 2 1
|
||||
github.com/urfave/cli/flag.go:169.3,169.19 1 1
|
||||
github.com/urfave/cli/flag.go:163.48,165.40 2 1
|
||||
github.com/urfave/cli/flag.go:165.40,167.5 1 0
|
||||
github.com/urfave/cli/flag.go:172.37,173.21 1 1
|
||||
github.com/urfave/cli/flag.go:176.3,176.34 1 1
|
||||
github.com/urfave/cli/flag.go:173.21,175.4 1 1
|
||||
github.com/urfave/cli/flag.go:186.44,188.16 2 1
|
||||
github.com/urfave/cli/flag.go:191.2,192.12 2 1
|
||||
github.com/urfave/cli/flag.go:188.16,190.3 1 1
|
||||
github.com/urfave/cli/flag.go:196.36,198.2 1 1
|
||||
github.com/urfave/cli/flag.go:201.34,203.2 1 1
|
||||
github.com/urfave/cli/flag.go:206.38,208.2 1 1
|
||||
github.com/urfave/cli/flag.go:212.48,214.2 1 0
|
||||
github.com/urfave/cli/flag.go:217.63,218.61 1 1
|
||||
github.com/urfave/cli/flag.go:229.2,229.37 1 1
|
||||
github.com/urfave/cli/flag.go:236.2,236.12 1 1
|
||||
github.com/urfave/cli/flag.go:218.61,220.48 2 1
|
||||
github.com/urfave/cli/flag.go:226.3,226.19 1 1
|
||||
github.com/urfave/cli/flag.go:220.48,222.40 2 1
|
||||
github.com/urfave/cli/flag.go:222.40,224.5 1 1
|
||||
github.com/urfave/cli/flag.go:229.37,230.21 1 1
|
||||
github.com/urfave/cli/flag.go:233.3,233.34 1 1
|
||||
github.com/urfave/cli/flag.go:230.21,232.4 1 1
|
||||
github.com/urfave/cli/flag.go:243.46,245.16 2 1
|
||||
github.com/urfave/cli/flag.go:248.2,249.12 2 1
|
||||
github.com/urfave/cli/flag.go:245.16,247.3 1 1
|
||||
github.com/urfave/cli/flag.go:253.38,255.2 1 1
|
||||
github.com/urfave/cli/flag.go:258.38,260.2 1 1
|
||||
github.com/urfave/cli/flag.go:263.40,265.2 1 1
|
||||
github.com/urfave/cli/flag.go:269.50,271.2 1 0
|
||||
github.com/urfave/cli/flag.go:274.65,275.61 1 1
|
||||
github.com/urfave/cli/flag.go:286.2,286.37 1 1
|
||||
github.com/urfave/cli/flag.go:292.2,292.12 1 1
|
||||
github.com/urfave/cli/flag.go:275.61,277.48 2 1
|
||||
github.com/urfave/cli/flag.go:283.3,283.19 1 1
|
||||
github.com/urfave/cli/flag.go:277.48,279.40 2 1
|
||||
github.com/urfave/cli/flag.go:279.40,281.5 1 1
|
||||
github.com/urfave/cli/flag.go:286.37,287.21 1 1
|
||||
github.com/urfave/cli/flag.go:290.3,290.34 1 1
|
||||
github.com/urfave/cli/flag.go:287.21,289.4 1 0
|
||||
github.com/urfave/cli/flag.go:297.44,299.2 1 0
|
||||
github.com/urfave/cli/flag.go:302.59,304.61 2 1
|
||||
github.com/urfave/cli/flag.go:316.2,316.37 1 1
|
||||
github.com/urfave/cli/flag.go:324.2,324.12 1 1
|
||||
github.com/urfave/cli/flag.go:304.61,305.19 1 1
|
||||
github.com/urfave/cli/flag.go:305.19,307.4 1 1
|
||||
github.com/urfave/cli/flag.go:307.4,309.18 2 1
|
||||
github.com/urfave/cli/flag.go:312.4,312.20 1 1
|
||||
github.com/urfave/cli/flag.go:309.18,311.5 1 1
|
||||
github.com/urfave/cli/flag.go:316.37,317.27 1 1
|
||||
github.com/urfave/cli/flag.go:321.3,321.31 1 1
|
||||
github.com/urfave/cli/flag.go:317.27,320.4 2 1
|
||||
github.com/urfave/cli/flag.go:329.45,331.2 1 0
|
||||
github.com/urfave/cli/flag.go:334.60,337.61 2 1
|
||||
github.com/urfave/cli/flag.go:349.2,349.37 1 1
|
||||
github.com/urfave/cli/flag.go:357.2,357.12 1 1
|
||||
github.com/urfave/cli/flag.go:337.61,338.19 1 1
|
||||
github.com/urfave/cli/flag.go:338.19,340.4 1 1
|
||||
github.com/urfave/cli/flag.go:340.4,342.18 2 1
|
||||
github.com/urfave/cli/flag.go:345.4,345.20 1 1
|
||||
github.com/urfave/cli/flag.go:342.18,344.5 1 1
|
||||
github.com/urfave/cli/flag.go:349.37,350.27 1 1
|
||||
github.com/urfave/cli/flag.go:354.3,354.31 1 1
|
||||
github.com/urfave/cli/flag.go:350.27,353.4 2 1
|
||||
github.com/urfave/cli/flag.go:362.46,364.2 1 0
|
||||
github.com/urfave/cli/flag.go:367.61,368.61 1 1
|
||||
github.com/urfave/cli/flag.go:372.2,372.37 1 1
|
||||
github.com/urfave/cli/flag.go:380.2,380.12 1 1
|
||||
github.com/urfave/cli/flag.go:368.61,370.3 1 1
|
||||
github.com/urfave/cli/flag.go:372.37,373.27 1 1
|
||||
github.com/urfave/cli/flag.go:377.3,377.37 1 1
|
||||
github.com/urfave/cli/flag.go:373.27,376.4 2 1
|
||||
github.com/urfave/cli/flag.go:385.43,387.2 1 0
|
||||
github.com/urfave/cli/flag.go:390.58,391.61 1 1
|
||||
github.com/urfave/cli/flag.go:399.2,399.37 1 1
|
||||
github.com/urfave/cli/flag.go:407.2,407.12 1 1
|
||||
github.com/urfave/cli/flag.go:391.61,393.17 2 1
|
||||
github.com/urfave/cli/flag.go:396.3,396.27 1 1
|
||||
github.com/urfave/cli/flag.go:393.17,395.4 1 1
|
||||
github.com/urfave/cli/flag.go:399.37,400.27 1 1
|
||||
github.com/urfave/cli/flag.go:404.3,404.34 1 1
|
||||
github.com/urfave/cli/flag.go:400.27,403.4 2 1
|
||||
github.com/urfave/cli/flag.go:412.45,414.2 1 0
|
||||
github.com/urfave/cli/flag.go:417.60,418.61 1 1
|
||||
github.com/urfave/cli/flag.go:427.2,427.37 1 1
|
||||
github.com/urfave/cli/flag.go:435.2,435.12 1 1
|
||||
github.com/urfave/cli/flag.go:418.61,420.17 2 1
|
||||
github.com/urfave/cli/flag.go:424.3,424.22 1 1
|
||||
github.com/urfave/cli/flag.go:420.17,422.4 1 1
|
||||
github.com/urfave/cli/flag.go:427.37,428.27 1 1
|
||||
github.com/urfave/cli/flag.go:432.3,432.36 1 1
|
||||
github.com/urfave/cli/flag.go:428.27,431.4 2 0
|
||||
github.com/urfave/cli/flag.go:440.44,442.2 1 0
|
||||
github.com/urfave/cli/flag.go:445.59,446.61 1 1
|
||||
github.com/urfave/cli/flag.go:455.2,455.37 1 1
|
||||
github.com/urfave/cli/flag.go:463.2,463.12 1 1
|
||||
github.com/urfave/cli/flag.go:446.61,448.17 2 1
|
||||
github.com/urfave/cli/flag.go:452.3,452.28 1 1
|
||||
github.com/urfave/cli/flag.go:448.17,450.4 1 1
|
||||
github.com/urfave/cli/flag.go:455.37,456.27 1 1
|
||||
github.com/urfave/cli/flag.go:460.3,460.35 1 1
|
||||
github.com/urfave/cli/flag.go:456.27,459.4 2 0
|
||||
github.com/urfave/cli/flag.go:468.46,470.2 1 0
|
||||
github.com/urfave/cli/flag.go:473.61,474.61 1 1
|
||||
github.com/urfave/cli/flag.go:483.2,483.37 1 1
|
||||
github.com/urfave/cli/flag.go:491.2,491.12 1 1
|
||||
github.com/urfave/cli/flag.go:474.61,476.17 2 1
|
||||
github.com/urfave/cli/flag.go:480.3,480.30 1 1
|
||||
github.com/urfave/cli/flag.go:476.17,478.4 1 1
|
||||
github.com/urfave/cli/flag.go:483.37,484.27 1 1
|
||||
github.com/urfave/cli/flag.go:488.3,488.37 1 1
|
||||
github.com/urfave/cli/flag.go:484.27,487.4 2 0
|
||||
github.com/urfave/cli/flag.go:496.48,498.2 1 0
|
||||
github.com/urfave/cli/flag.go:501.63,502.61 1 1
|
||||
github.com/urfave/cli/flag.go:511.2,511.37 1 1
|
||||
github.com/urfave/cli/flag.go:519.2,519.12 1 1
|
||||
github.com/urfave/cli/flag.go:502.61,504.17 2 1
|
||||
github.com/urfave/cli/flag.go:508.3,508.27 1 1
|
||||
github.com/urfave/cli/flag.go:504.17,506.4 1 1
|
||||
github.com/urfave/cli/flag.go:511.37,512.27 1 1
|
||||
github.com/urfave/cli/flag.go:516.3,516.39 1 1
|
||||
github.com/urfave/cli/flag.go:512.27,515.4 2 0
|
||||
github.com/urfave/cli/flag.go:524.47,526.2 1 0
|
||||
github.com/urfave/cli/flag.go:529.62,530.61 1 1
|
||||
github.com/urfave/cli/flag.go:539.2,539.37 1 1
|
||||
github.com/urfave/cli/flag.go:547.2,547.12 1 1
|
||||
github.com/urfave/cli/flag.go:530.61,532.17 2 1
|
||||
github.com/urfave/cli/flag.go:536.3,536.33 1 1
|
||||
github.com/urfave/cli/flag.go:532.17,534.4 1 1
|
||||
github.com/urfave/cli/flag.go:539.37,540.27 1 1
|
||||
github.com/urfave/cli/flag.go:544.3,544.38 1 1
|
||||
github.com/urfave/cli/flag.go:540.27,543.4 2 1
|
||||
github.com/urfave/cli/flag.go:550.37,552.26 2 1
|
||||
github.com/urfave/cli/flag.go:557.2,557.16 1 1
|
||||
github.com/urfave/cli/flag.go:552.26,553.52 1 1
|
||||
github.com/urfave/cli/flag.go:553.52,555.4 1 1
|
||||
github.com/urfave/cli/flag.go:560.45,561.20 1 1
|
||||
github.com/urfave/cli/flag.go:567.2,567.8 1 1
|
||||
github.com/urfave/cli/flag.go:561.20,563.3 1 1
|
||||
github.com/urfave/cli/flag.go:563.3,565.3 1 1
|
||||
github.com/urfave/cli/flag.go:571.50,572.34 1 1
|
||||
github.com/urfave/cli/flag.go:584.2,584.18 1 1
|
||||
github.com/urfave/cli/flag.go:572.34,573.22 1 1
|
||||
github.com/urfave/cli/flag.go:573.22,574.40 1 1
|
||||
github.com/urfave/cli/flag.go:581.4,581.9 1 0
|
||||
github.com/urfave/cli/flag.go:574.40,575.24 1 1
|
||||
github.com/urfave/cli/flag.go:575.24,579.6 3 1
|
||||
github.com/urfave/cli/flag.go:587.57,590.29 3 1
|
||||
github.com/urfave/cli/flag.go:600.2,600.17 1 1
|
||||
github.com/urfave/cli/flag.go:590.29,593.24 3 1
|
||||
github.com/urfave/cli/flag.go:596.3,596.23 1 1
|
||||
github.com/urfave/cli/flag.go:593.24,595.4 1 1
|
||||
github.com/urfave/cli/flag.go:596.23,598.4 1 1
|
||||
github.com/urfave/cli/flag.go:603.45,605.18 2 1
|
||||
github.com/urfave/cli/flag.go:616.2,616.22 1 1
|
||||
github.com/urfave/cli/flag.go:605.18,609.32 4 1
|
||||
github.com/urfave/cli/flag.go:614.3,614.100 1 1
|
||||
github.com/urfave/cli/flag.go:609.32,613.4 3 0
|
||||
github.com/urfave/cli/flag.go:619.48,621.20 2 1
|
||||
github.com/urfave/cli/flag.go:624.2,624.23 1 1
|
||||
github.com/urfave/cli/flag.go:621.20,623.3 1 0
|
||||
github.com/urfave/cli/flag.go:627.38,629.31 2 1
|
||||
github.com/urfave/cli/flag.go:632.2,632.11 1 1
|
||||
github.com/urfave/cli/flag.go:629.31,631.3 1 0
|
||||
github.com/urfave/cli/flag.go:635.35,638.18 2 1
|
||||
github.com/urfave/cli/flag.go:665.2,671.19 5 1
|
||||
github.com/urfave/cli/flag.go:680.2,680.42 1 1
|
||||
github.com/urfave/cli/flag.go:684.2,684.43 1 1
|
||||
github.com/urfave/cli/flag.go:688.2,696.3 2 1
|
||||
github.com/urfave/cli/flag.go:639.20,646.4 1 1
|
||||
github.com/urfave/cli/flag.go:647.22,654.4 1 1
|
||||
github.com/urfave/cli/flag.go:655.23,662.4 1 1
|
||||
github.com/urfave/cli/flag.go:671.19,675.57 3 1
|
||||
github.com/urfave/cli/flag.go:675.57,677.4 1 1
|
||||
github.com/urfave/cli/flag.go:680.42,682.3 1 1
|
||||
github.com/urfave/cli/flag.go:684.43,686.3 1 1
|
||||
github.com/urfave/cli/flag.go:699.51,701.48 2 1
|
||||
github.com/urfave/cli/flag.go:707.2,707.57 1 1
|
||||
github.com/urfave/cli/flag.go:701.48,702.37 1 1
|
||||
github.com/urfave/cli/flag.go:702.37,704.4 1 1
|
||||
github.com/urfave/cli/flag.go:710.55,712.48 2 1
|
||||
github.com/urfave/cli/flag.go:718.2,718.57 1 1
|
||||
github.com/urfave/cli/flag.go:712.48,713.37 1 1
|
||||
github.com/urfave/cli/flag.go:713.37,715.4 1 1
|
||||
github.com/urfave/cli/flag.go:721.57,723.48 2 1
|
||||
github.com/urfave/cli/flag.go:731.2,731.57 1 1
|
||||
github.com/urfave/cli/flag.go:723.48,724.37 1 1
|
||||
github.com/urfave/cli/flag.go:724.37,725.18 1 1
|
||||
github.com/urfave/cli/flag.go:725.18,727.5 1 1
|
||||
github.com/urfave/cli/flag.go:734.74,736.23 2 1
|
||||
github.com/urfave/cli/flag.go:740.2,741.26 2 1
|
||||
github.com/urfave/cli/flag.go:745.2,746.82 2 1
|
||||
github.com/urfave/cli/flag.go:736.23,738.3 1 1
|
||||
github.com/urfave/cli/flag.go:741.26,743.3 1 1
|
||||
github.com/urfave/cli/flag.go:749.70,750.20 1 1
|
||||
github.com/urfave/cli/flag.go:755.2,755.53 1 1
|
||||
github.com/urfave/cli/flag.go:761.2,761.8 1 1
|
||||
github.com/urfave/cli/flag.go:750.20,751.57 1 1
|
||||
github.com/urfave/cli/flag.go:751.57,753.4 1 1
|
||||
github.com/urfave/cli/flag.go:755.53,757.47 2 1
|
||||
github.com/urfave/cli/flag.go:757.47,759.4 1 1
|
||||
github.com/urfave/cli/flag_generated.go:23.35,25.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:28.36,30.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:34.42,36.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:40.48,41.51 1 1
|
||||
github.com/urfave/cli/flag_generated.go:44.2,44.14 1 1
|
||||
github.com/urfave/cli/flag_generated.go:41.51,43.3 1 1
|
||||
github.com/urfave/cli/flag_generated.go:47.54,49.14 2 1
|
||||
github.com/urfave/cli/flag_generated.go:56.2,56.14 1 0
|
||||
github.com/urfave/cli/flag_generated.go:49.14,51.17 2 1
|
||||
github.com/urfave/cli/flag_generated.go:54.3,54.16 1 1
|
||||
github.com/urfave/cli/flag_generated.go:51.17,53.4 1 0
|
||||
github.com/urfave/cli/flag_generated.go:71.36,73.2 1 0
|
||||
github.com/urfave/cli/flag_generated.go:76.37,78.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:82.43,84.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:88.49,89.51 1 1
|
||||
github.com/urfave/cli/flag_generated.go:92.2,92.14 1 1
|
||||
github.com/urfave/cli/flag_generated.go:89.51,91.3 1 1
|
||||
github.com/urfave/cli/flag_generated.go:95.55,97.14 2 1
|
||||
github.com/urfave/cli/flag_generated.go:104.2,104.14 1 0
|
||||
github.com/urfave/cli/flag_generated.go:97.14,99.17 2 1
|
||||
github.com/urfave/cli/flag_generated.go:102.3,102.16 1 1
|
||||
github.com/urfave/cli/flag_generated.go:99.17,101.4 1 0
|
||||
github.com/urfave/cli/flag_generated.go:120.39,122.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:125.40,127.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:131.55,133.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:137.61,138.51 1 0
|
||||
github.com/urfave/cli/flag_generated.go:141.2,141.10 1 0
|
||||
github.com/urfave/cli/flag_generated.go:138.51,140.3 1 0
|
||||
github.com/urfave/cli/flag_generated.go:144.67,146.14 2 1
|
||||
github.com/urfave/cli/flag_generated.go:153.2,153.10 1 0
|
||||
github.com/urfave/cli/flag_generated.go:146.14,148.17 2 1
|
||||
github.com/urfave/cli/flag_generated.go:151.3,151.16 1 1
|
||||
github.com/urfave/cli/flag_generated.go:148.17,150.4 1 0
|
||||
github.com/urfave/cli/flag_generated.go:169.38,171.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:174.39,176.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:180.48,182.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:186.54,187.51 1 1
|
||||
github.com/urfave/cli/flag_generated.go:190.2,190.10 1 1
|
||||
github.com/urfave/cli/flag_generated.go:187.51,189.3 1 1
|
||||
github.com/urfave/cli/flag_generated.go:193.60,195.14 2 1
|
||||
github.com/urfave/cli/flag_generated.go:202.2,202.10 1 0
|
||||
github.com/urfave/cli/flag_generated.go:195.14,197.17 2 1
|
||||
github.com/urfave/cli/flag_generated.go:200.3,200.16 1 1
|
||||
github.com/urfave/cli/flag_generated.go:197.17,199.4 1 0
|
||||
github.com/urfave/cli/flag_generated.go:217.38,219.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:222.39,224.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:228.52,230.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:234.58,235.51 1 0
|
||||
github.com/urfave/cli/flag_generated.go:238.2,238.12 1 0
|
||||
github.com/urfave/cli/flag_generated.go:235.51,237.3 1 0
|
||||
github.com/urfave/cli/flag_generated.go:241.64,243.14 2 1
|
||||
github.com/urfave/cli/flag_generated.go:250.2,250.12 1 0
|
||||
github.com/urfave/cli/flag_generated.go:243.14,245.17 2 1
|
||||
github.com/urfave/cli/flag_generated.go:248.3,248.16 1 1
|
||||
github.com/urfave/cli/flag_generated.go:245.17,247.4 1 0
|
||||
github.com/urfave/cli/flag_generated.go:266.36,268.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:271.37,273.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:277.44,279.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:283.50,284.51 1 1
|
||||
github.com/urfave/cli/flag_generated.go:287.2,287.10 1 1
|
||||
github.com/urfave/cli/flag_generated.go:284.51,286.3 1 1
|
||||
github.com/urfave/cli/flag_generated.go:290.56,292.14 2 1
|
||||
github.com/urfave/cli/flag_generated.go:299.2,299.10 1 0
|
||||
github.com/urfave/cli/flag_generated.go:292.14,294.17 2 1
|
||||
github.com/urfave/cli/flag_generated.go:297.3,297.16 1 1
|
||||
github.com/urfave/cli/flag_generated.go:294.17,296.4 1 0
|
||||
github.com/urfave/cli/flag_generated.go:315.34,317.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:320.35,322.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:326.40,328.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:332.46,333.51 1 1
|
||||
github.com/urfave/cli/flag_generated.go:336.2,336.10 1 1
|
||||
github.com/urfave/cli/flag_generated.go:333.51,335.3 1 1
|
||||
github.com/urfave/cli/flag_generated.go:339.52,341.14 2 1
|
||||
github.com/urfave/cli/flag_generated.go:348.2,348.10 1 0
|
||||
github.com/urfave/cli/flag_generated.go:341.14,343.17 2 1
|
||||
github.com/urfave/cli/flag_generated.go:346.3,346.21 1 1
|
||||
github.com/urfave/cli/flag_generated.go:343.17,345.4 1 0
|
||||
github.com/urfave/cli/flag_generated.go:363.39,365.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:368.40,370.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:374.47,376.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:380.53,381.51 1 0
|
||||
github.com/urfave/cli/flag_generated.go:384.2,384.12 1 0
|
||||
github.com/urfave/cli/flag_generated.go:381.51,383.3 1 0
|
||||
github.com/urfave/cli/flag_generated.go:387.59,389.14 2 1
|
||||
github.com/urfave/cli/flag_generated.go:396.2,396.12 1 0
|
||||
github.com/urfave/cli/flag_generated.go:389.14,391.17 2 1
|
||||
github.com/urfave/cli/flag_generated.go:394.3,394.16 1 1
|
||||
github.com/urfave/cli/flag_generated.go:391.17,393.4 1 0
|
||||
github.com/urfave/cli/flag_generated.go:411.41,413.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:416.42,418.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:422.51,424.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:428.57,429.51 1 0
|
||||
github.com/urfave/cli/flag_generated.go:432.2,432.12 1 0
|
||||
github.com/urfave/cli/flag_generated.go:429.51,431.3 1 0
|
||||
github.com/urfave/cli/flag_generated.go:435.63,437.14 2 1
|
||||
github.com/urfave/cli/flag_generated.go:444.2,444.12 1 0
|
||||
github.com/urfave/cli/flag_generated.go:437.14,439.17 2 1
|
||||
github.com/urfave/cli/flag_generated.go:442.3,442.16 1 1
|
||||
github.com/urfave/cli/flag_generated.go:439.17,441.4 1 0
|
||||
github.com/urfave/cli/flag_generated.go:460.37,462.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:465.38,467.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:471.46,473.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:477.52,478.51 1 1
|
||||
github.com/urfave/cli/flag_generated.go:481.2,481.11 1 0
|
||||
github.com/urfave/cli/flag_generated.go:478.51,480.3 1 1
|
||||
github.com/urfave/cli/flag_generated.go:484.58,486.14 2 1
|
||||
github.com/urfave/cli/flag_generated.go:493.2,493.11 1 1
|
||||
github.com/urfave/cli/flag_generated.go:486.14,488.17 2 1
|
||||
github.com/urfave/cli/flag_generated.go:491.3,491.16 1 1
|
||||
github.com/urfave/cli/flag_generated.go:488.17,490.4 1 0
|
||||
github.com/urfave/cli/flag_generated.go:508.42,510.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:513.43,515.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:519.53,521.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:525.59,526.51 1 0
|
||||
github.com/urfave/cli/flag_generated.go:529.2,529.12 1 0
|
||||
github.com/urfave/cli/flag_generated.go:526.51,528.3 1 0
|
||||
github.com/urfave/cli/flag_generated.go:532.65,534.14 2 1
|
||||
github.com/urfave/cli/flag_generated.go:541.2,541.12 1 0
|
||||
github.com/urfave/cli/flag_generated.go:534.14,536.17 2 1
|
||||
github.com/urfave/cli/flag_generated.go:539.3,539.16 1 1
|
||||
github.com/urfave/cli/flag_generated.go:536.17,538.4 1 0
|
||||
github.com/urfave/cli/flag_generated.go:557.37,559.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:562.38,564.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:568.46,570.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:574.52,575.51 1 1
|
||||
github.com/urfave/cli/flag_generated.go:578.2,578.10 1 0
|
||||
github.com/urfave/cli/flag_generated.go:575.51,577.3 1 1
|
||||
github.com/urfave/cli/flag_generated.go:581.58,583.14 2 1
|
||||
github.com/urfave/cli/flag_generated.go:590.2,590.10 1 0
|
||||
github.com/urfave/cli/flag_generated.go:583.14,585.17 2 1
|
||||
github.com/urfave/cli/flag_generated.go:588.3,588.16 1 1
|
||||
github.com/urfave/cli/flag_generated.go:585.17,587.4 1 0
|
||||
github.com/urfave/cli/flag_generated.go:606.35,608.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:611.36,613.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:617.42,619.2 1 1
|
||||
github.com/urfave/cli/flag_generated.go:623.48,624.51 1 1
|
||||
github.com/urfave/cli/flag_generated.go:627.2,627.10 1 0
|
||||
github.com/urfave/cli/flag_generated.go:624.51,626.3 1 1
|
||||
github.com/urfave/cli/flag_generated.go:630.54,632.14 2 1
|
||||
github.com/urfave/cli/flag_generated.go:639.2,639.10 1 0
|
||||
github.com/urfave/cli/flag_generated.go:632.14,634.17 2 1
|
||||
github.com/urfave/cli/flag_generated.go:637.3,637.22 1 1
|
||||
github.com/urfave/cli/flag_generated.go:634.17,636.4 1 0
|
@ -0,0 +1,21 @@
|
||||
// Package cli provides a minimal framework for creating and organizing command line
|
||||
// Go applications. cli is designed to be easy to understand and write, the most simple
|
||||
// cli application can be written as follows:
|
||||
// func main() {
|
||||
// cli.NewApp().Run(os.Args)
|
||||
// }
|
||||
//
|
||||
// Of course this application does not do much, so let's make this an actual application:
|
||||
// func main() {
|
||||
// app := cli.NewApp()
|
||||
// app.Name = "greet"
|
||||
// app.Usage = "say a greeting"
|
||||
// app.Action = func(c *cli.Context) error {
|
||||
// println("Greetings")
|
||||
// }
|
||||
//
|
||||
// app.Run(os.Args)
|
||||
// }
|
||||
package cli
|
||||
|
||||
//go:generate python ./generate-flag-types cli -i flag-types.json -o flag_generated.go
|
@ -0,0 +1,299 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Command is a subcommand for a cli.App.
|
||||
type Command struct {
|
||||
// The name of the command
|
||||
Name string
|
||||
// short name of the command. Typically one character (deprecated, use `Aliases`)
|
||||
ShortName string
|
||||
// A list of aliases for the command
|
||||
Aliases []string
|
||||
// A short description of the usage of this command
|
||||
Usage string
|
||||
// Custom text to show on USAGE section of help
|
||||
UsageText string
|
||||
// A longer explanation of how the command works
|
||||
Description string
|
||||
// A short description of the arguments of this command
|
||||
ArgsUsage string
|
||||
// The category the command is part of
|
||||
Category string
|
||||
// The function to call when checking for bash command completions
|
||||
BashComplete BashCompleteFunc
|
||||
// An action to execute before any sub-subcommands are run, but after the context is ready
|
||||
// If a non-nil error is returned, no sub-subcommands are run
|
||||
Before BeforeFunc
|
||||
// An action to execute after any subcommands are run, but after the subcommand has finished
|
||||
// It is run even if Action() panics
|
||||
After AfterFunc
|
||||
// The function to call when this command is invoked
|
||||
Action interface{}
|
||||
// TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind
|
||||
// of deprecation period has passed, maybe?
|
||||
|
||||
// Execute this function if a usage error occurs.
|
||||
OnUsageError OnUsageErrorFunc
|
||||
// List of child commands
|
||||
Subcommands Commands
|
||||
// List of flags to parse
|
||||
Flags []Flag
|
||||
// Treat all flags as normal arguments if true
|
||||
SkipFlagParsing bool
|
||||
// Skip argument reordering which attempts to move flags before arguments,
|
||||
// but only works if all flags appear after all arguments. This behavior was
|
||||
// removed n version 2 since it only works under specific conditions so we
|
||||
// backport here by exposing it as an option for compatibility.
|
||||
SkipArgReorder bool
|
||||
// Boolean to hide built-in help command
|
||||
HideHelp bool
|
||||
// Boolean to hide this command from help or completion
|
||||
Hidden bool
|
||||
|
||||
// Full name of command for help, defaults to full command name, including parent commands.
|
||||
HelpName string
|
||||
commandNamePath []string
|
||||
}
|
||||
|
||||
type CommandsByName []Command
|
||||
|
||||
func (c CommandsByName) Len() int {
|
||||
return len(c)
|
||||
}
|
||||
|
||||
func (c CommandsByName) Less(i, j int) bool {
|
||||
return c[i].Name < c[j].Name
|
||||
}
|
||||
|
||||
func (c CommandsByName) Swap(i, j int) {
|
||||
c[i], c[j] = c[j], c[i]
|
||||
}
|
||||
|
||||
// FullName returns the full name of the command.
|
||||
// For subcommands this ensures that parent commands are part of the command path
|
||||
func (c Command) FullName() string {
|
||||
if c.commandNamePath == nil {
|
||||
return c.Name
|
||||
}
|
||||
return strings.Join(c.commandNamePath, " ")
|
||||
}
|
||||
|
||||
// Commands is a slice of Command
|
||||
type Commands []Command
|
||||
|
||||
// Run invokes the command given the context, parses ctx.Args() to generate command-specific flags
|
||||
func (c Command) Run(ctx *Context) (err error) {
|
||||
if len(c.Subcommands) > 0 {
|
||||
return c.startApp(ctx)
|
||||
}
|
||||
|
||||
if !c.HideHelp && (HelpFlag != BoolFlag{}) {
|
||||
// append help to flags
|
||||
c.Flags = append(
|
||||
c.Flags,
|
||||
HelpFlag,
|
||||
)
|
||||
}
|
||||
|
||||
set, err := flagSet(c.Name, c.Flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
set.SetOutput(ioutil.Discard)
|
||||
|
||||
if c.SkipFlagParsing {
|
||||
err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...))
|
||||
} else if !c.SkipArgReorder {
|
||||
firstFlagIndex := -1
|
||||
terminatorIndex := -1
|
||||
for index, arg := range ctx.Args() {
|
||||
if arg == "--" {
|
||||
terminatorIndex = index
|
||||
break
|
||||
} else if arg == "-" {
|
||||
// Do nothing. A dash alone is not really a flag.
|
||||
continue
|
||||
} else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
|
||||
firstFlagIndex = index
|
||||
}
|
||||
}
|
||||
|
||||
if firstFlagIndex > -1 {
|
||||
args := ctx.Args()
|
||||
regularArgs := make([]string, len(args[1:firstFlagIndex]))
|
||||
copy(regularArgs, args[1:firstFlagIndex])
|
||||
|
||||
var flagArgs []string
|
||||
if terminatorIndex > -1 {
|
||||
flagArgs = args[firstFlagIndex:terminatorIndex]
|
||||
regularArgs = append(regularArgs, args[terminatorIndex:]...)
|
||||
} else {
|
||||
flagArgs = args[firstFlagIndex:]
|
||||
}
|
||||
|
||||
err = set.Parse(append(flagArgs, regularArgs...))
|
||||
} else {
|
||||
err = set.Parse(ctx.Args().Tail())
|
||||
}
|
||||
} else {
|
||||
err = set.Parse(ctx.Args().Tail())
|
||||
}
|
||||
|
||||
nerr := normalizeFlags(c.Flags, set)
|
||||
if nerr != nil {
|
||||
fmt.Fprintln(ctx.App.Writer, nerr)
|
||||
fmt.Fprintln(ctx.App.Writer)
|
||||
ShowCommandHelp(ctx, c.Name)
|
||||
return nerr
|
||||
}
|
||||
|
||||
context := NewContext(ctx.App, set, ctx)
|
||||
if checkCommandCompletions(context, c.Name) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if c.OnUsageError != nil {
|
||||
err := c.OnUsageError(ctx, err, false)
|
||||
HandleExitCoder(err)
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(ctx.App.Writer, "Incorrect Usage:", err.Error())
|
||||
fmt.Fprintln(ctx.App.Writer)
|
||||
ShowCommandHelp(ctx, c.Name)
|
||||
return err
|
||||
}
|
||||
|
||||
if checkCommandHelp(context, c.Name) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.After != nil {
|
||||
defer func() {
|
||||
afterErr := c.After(context)
|
||||
if afterErr != nil {
|
||||
HandleExitCoder(err)
|
||||
if err != nil {
|
||||
err = NewMultiError(err, afterErr)
|
||||
} else {
|
||||
err = afterErr
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if c.Before != nil {
|
||||
err = c.Before(context)
|
||||
if err != nil {
|
||||
fmt.Fprintln(ctx.App.Writer, err)
|
||||
fmt.Fprintln(ctx.App.Writer)
|
||||
ShowCommandHelp(ctx, c.Name)
|
||||
HandleExitCoder(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if c.Action == nil {
|
||||
c.Action = helpSubcommand.Action
|
||||
}
|
||||
|
||||
context.Command = c
|
||||
err = HandleAction(c.Action, context)
|
||||
|
||||
if err != nil {
|
||||
HandleExitCoder(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Names returns the names including short names and aliases.
|
||||
func (c Command) Names() []string {
|
||||
names := []string{c.Name}
|
||||
|
||||
if c.ShortName != "" {
|
||||
names = append(names, c.ShortName)
|
||||
}
|
||||
|
||||
return append(names, c.Aliases...)
|
||||
}
|
||||
|
||||
// HasName returns true if Command.Name or Command.ShortName matches given name
|
||||
func (c Command) HasName(name string) bool {
|
||||
for _, n := range c.Names() {
|
||||
if n == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c Command) startApp(ctx *Context) error {
|
||||
app := NewApp()
|
||||
app.Metadata = ctx.App.Metadata
|
||||
// set the name and usage
|
||||
app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
|
||||
if c.HelpName == "" {
|
||||
app.HelpName = c.HelpName
|
||||
} else {
|
||||
app.HelpName = app.Name
|
||||
}
|
||||
|
||||
app.Usage = c.Usage
|
||||
app.Description = c.Description
|
||||
app.ArgsUsage = c.ArgsUsage
|
||||
|
||||
// set CommandNotFound
|
||||
app.CommandNotFound = ctx.App.CommandNotFound
|
||||
|
||||
// set the flags and commands
|
||||
app.Commands = c.Subcommands
|
||||
app.Flags = c.Flags
|
||||
app.HideHelp = c.HideHelp
|
||||
|
||||
app.Version = ctx.App.Version
|
||||
app.HideVersion = ctx.App.HideVersion
|
||||
app.Compiled = ctx.App.Compiled
|
||||
app.Author = ctx.App.Author
|
||||
app.Email = ctx.App.Email
|
||||
app.Writer = ctx.App.Writer
|
||||
app.ErrWriter = ctx.App.ErrWriter
|
||||
|
||||
app.categories = CommandCategories{}
|
||||
for _, command := range c.Subcommands {
|
||||
app.categories = app.categories.AddCommand(command.Category, command)
|
||||
}
|
||||
|
||||
sort.Sort(app.categories)
|
||||
|
||||
// bash completion
|
||||
app.EnableBashCompletion = ctx.App.EnableBashCompletion
|
||||
if c.BashComplete != nil {
|
||||
app.BashComplete = c.BashComplete
|
||||
}
|
||||
|
||||
// set the actions
|
||||
app.Before = c.Before
|
||||
app.After = c.After
|
||||
if c.Action != nil {
|
||||
app.Action = c.Action
|
||||
} else {
|
||||
app.Action = helpSubcommand.Action
|
||||
}
|
||||
|
||||
for index, cc := range app.Commands {
|
||||
app.Commands[index].commandNamePath = []string{c.Name, cc.Name}
|
||||
}
|
||||
|
||||
return app.RunAsSubcommand(ctx)
|
||||
}
|
||||
|
||||
// VisibleFlags returns a slice of the Flags with Hidden=false
|
||||
func (c Command) VisibleFlags() []Flag {
|
||||
return visibleFlags(c.Flags)
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCommandFlagParsing(t *testing.T) {
|
||||
cases := []struct {
|
||||
testArgs []string
|
||||
skipFlagParsing bool
|
||||
skipArgReorder bool
|
||||
expectedErr error
|
||||
}{
|
||||
// Test normal "not ignoring flags" flow
|
||||
{[]string{"test-cmd", "blah", "blah", "-break"}, false, false, errors.New("flag provided but not defined: -break")},
|
||||
|
||||
// Test no arg reorder
|
||||
{[]string{"test-cmd", "blah", "blah", "-break"}, false, true, nil},
|
||||
|
||||
{[]string{"test-cmd", "blah", "blah"}, true, false, nil}, // Test SkipFlagParsing without any args that look like flags
|
||||
{[]string{"test-cmd", "blah", "-break"}, true, false, nil}, // Test SkipFlagParsing with random flag arg
|
||||
{[]string{"test-cmd", "blah", "-help"}, true, false, nil}, // Test SkipFlagParsing with "special" help flag arg
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
app := NewApp()
|
||||
app.Writer = ioutil.Discard
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Parse(c.testArgs)
|
||||
|
||||
context := NewContext(app, set, nil)
|
||||
|
||||
command := Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(_ *Context) error { return nil },
|
||||
SkipFlagParsing: c.skipFlagParsing,
|
||||
SkipArgReorder: c.skipArgReorder,
|
||||
}
|
||||
|
||||
err := command.Run(context)
|
||||
|
||||
expect(t, err, c.expectedErr)
|
||||
expect(t, []string(context.Args()), c.testArgs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
|
||||
app := NewApp()
|
||||
app.Commands = []Command{
|
||||
{
|
||||
Name: "bar",
|
||||
Before: func(c *Context) error {
|
||||
return fmt.Errorf("before error")
|
||||
},
|
||||
After: func(c *Context) error {
|
||||
return fmt.Errorf("after error")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := app.Run([]string{"foo", "bar"})
|
||||
if err == nil {
|
||||
t.Fatalf("expected to receive error from Run, got none")
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), "before error") {
|
||||
t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "after error") {
|
||||
t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommand_Run_BeforeSavesMetadata(t *testing.T) {
|
||||
var receivedMsgFromAction string
|
||||
var receivedMsgFromAfter string
|
||||
|
||||
app := NewApp()
|
||||
app.Commands = []Command{
|
||||
{
|
||||
Name: "bar",
|
||||
Before: func(c *Context) error {
|
||||
c.App.Metadata["msg"] = "hello world"
|
||||
return nil
|
||||
},
|
||||
Action: func(c *Context) error {
|
||||
msg, ok := c.App.Metadata["msg"]
|
||||
if !ok {
|
||||
return errors.New("msg not found")
|
||||
}
|
||||
receivedMsgFromAction = msg.(string)
|
||||
return nil
|
||||
},
|
||||
After: func(c *Context) error {
|
||||
msg, ok := c.App.Metadata["msg"]
|
||||
if !ok {
|
||||
return errors.New("msg not found")
|
||||
}
|
||||
receivedMsgFromAfter = msg.(string)
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := app.Run([]string{"foo", "bar"})
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error from Run, got %s", err)
|
||||
}
|
||||
|
||||
expectedMsg := "hello world"
|
||||
|
||||
if receivedMsgFromAction != expectedMsg {
|
||||
t.Fatalf("expected msg from Action to match. Given: %q\nExpected: %q",
|
||||
receivedMsgFromAction, expectedMsg)
|
||||
}
|
||||
if receivedMsgFromAfter != expectedMsg {
|
||||
t.Fatalf("expected msg from After to match. Given: %q\nExpected: %q",
|
||||
receivedMsgFromAction, expectedMsg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) {
|
||||
app := NewApp()
|
||||
app.Commands = []Command{
|
||||
{
|
||||
Name: "bar",
|
||||
Flags: []Flag{
|
||||
IntFlag{Name: "flag"},
|
||||
},
|
||||
OnUsageError: func(c *Context, err error, _ bool) error {
|
||||
if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") {
|
||||
t.Errorf("Expect an invalid value error, but got \"%v\"", err)
|
||||
}
|
||||
return errors.New("intercepted: " + err.Error())
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := app.Run([]string{"foo", "bar", "--flag=wrong"})
|
||||
if err == nil {
|
||||
t.Fatalf("expected to receive error from Run, got none")
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(err.Error(), "intercepted: invalid value") {
|
||||
t.Errorf("Expect an intercepted error, but got \"%v\"", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommand_Run_SubcommandsCanUseErrWriter(t *testing.T) {
|
||||
app := NewApp()
|
||||
app.ErrWriter = ioutil.Discard
|
||||
app.Commands = []Command{
|
||||
{
|
||||
Name: "bar",
|
||||
Usage: "this is for testing",
|
||||
Subcommands: []Command{
|
||||
{
|
||||
Name: "baz",
|
||||
Usage: "this is for testing",
|
||||
Action: func(c *Context) error {
|
||||
if c.App.ErrWriter != ioutil.Discard {
|
||||
return fmt.Errorf("ErrWriter not passed")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := app.Run([]string{"foo", "bar", "baz"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
@ -0,0 +1,285 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Context is a type that is passed through to
|
||||
// each Handler action in a cli application. Context
|
||||
// can be used to retrieve context-specific Args and
|
||||
// parsed command-line options.
|
||||
type Context struct {
|
||||
App *App
|
||||
Command Command
|
||||
shellComplete bool
|
||||
flagSet *flag.FlagSet
|
||||
setFlags map[string]bool
|
||||
parentContext *Context
|
||||
}
|
||||
|
||||
// NewContext creates a new context. For use in when invoking an App or Command action.
|
||||
func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
|
||||
c := &Context{App: app, flagSet: set, parentContext: parentCtx}
|
||||
|
||||
if parentCtx != nil {
|
||||
c.shellComplete = parentCtx.shellComplete
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// NumFlags returns the number of flags set
|
||||
func (c *Context) NumFlags() int {
|
||||
return c.flagSet.NFlag()
|
||||
}
|
||||
|
||||
// Set sets a context flag to a value.
|
||||
func (c *Context) Set(name, value string) error {
|
||||
return c.flagSet.Set(name, value)
|
||||
}
|
||||
|
||||
// GlobalSet sets a context flag to a value on the global flagset
|
||||
func (c *Context) GlobalSet(name, value string) error {
|
||||
return globalContext(c).flagSet.Set(name, value)
|
||||
}
|
||||
|
||||
// IsSet determines if the flag was actually set
|
||||
func (c *Context) IsSet(name string) bool {
|
||||
if c.setFlags == nil {
|
||||
c.setFlags = make(map[string]bool)
|
||||
|
||||
c.flagSet.Visit(func(f *flag.Flag) {
|
||||
c.setFlags[f.Name] = true
|
||||
})
|
||||
|
||||
c.flagSet.VisitAll(func(f *flag.Flag) {
|
||||
if _, ok := c.setFlags[f.Name]; ok {
|
||||
return
|
||||
}
|
||||
c.setFlags[f.Name] = false
|
||||
})
|
||||
|
||||
// XXX hack to support IsSet for flags with EnvVar
|
||||
//
|
||||
// There isn't an easy way to do this with the current implementation since
|
||||
// whether a flag was set via an environment variable is very difficult to
|
||||
// determine here. Instead, we intend to introduce a backwards incompatible
|
||||
// change in version 2 to add `IsSet` to the Flag interface to push the
|
||||
// responsibility closer to where the information required to determine
|
||||
// whether a flag is set by non-standard means such as environment
|
||||
// variables is avaliable.
|
||||
//
|
||||
// See https://github.com/urfave/cli/issues/294 for additional discussion
|
||||
flags := c.Command.Flags
|
||||
if c.Command.Name == "" { // cannot == Command{} since it contains slice types
|
||||
if c.App != nil {
|
||||
flags = c.App.Flags
|
||||
}
|
||||
}
|
||||
for _, f := range flags {
|
||||
eachName(f.GetName(), func(name string) {
|
||||
if isSet, ok := c.setFlags[name]; isSet || !ok {
|
||||
return
|
||||
}
|
||||
|
||||
val := reflect.ValueOf(f)
|
||||
if val.Kind() == reflect.Ptr {
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
filePathValue := val.FieldByName("FilePath")
|
||||
if filePathValue.IsValid() {
|
||||
eachName(filePathValue.String(), func(filePath string) {
|
||||
if _, err := os.Stat(filePath); err == nil {
|
||||
c.setFlags[name] = true
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
envVarValue := val.FieldByName("EnvVar")
|
||||
if envVarValue.IsValid() {
|
||||
eachName(envVarValue.String(), func(envVar string) {
|
||||
envVar = strings.TrimSpace(envVar)
|
||||
if _, ok := syscall.Getenv(envVar); ok {
|
||||
c.setFlags[name] = true
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return c.setFlags[name]
|
||||
}
|
||||
|
||||
// GlobalIsSet determines if the global flag was actually set
|
||||
func (c *Context) GlobalIsSet(name string) bool {
|
||||
ctx := c
|
||||
if ctx.parentContext != nil {
|
||||
ctx = ctx.parentContext
|
||||
}
|
||||
|
||||
for ; ctx != nil; ctx = ctx.parentContext {
|
||||
if ctx.IsSet(name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// FlagNames returns a slice of flag names used in this context.
|
||||
func (c *Context) FlagNames() (names []string) {
|
||||
for _, flag := range c.Command.Flags {
|
||||
name := strings.Split(flag.GetName(), ",")[0]
|
||||
if name == "help" {
|
||||
continue
|
||||
}
|
||||
names = append(names, name)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GlobalFlagNames returns a slice of global flag names used by the app.
|
||||
func (c *Context) GlobalFlagNames() (names []string) {
|
||||
for _, flag := range c.App.Flags {
|
||||
name := strings.Split(flag.GetName(), ",")[0]
|
||||
if name == "help" || name == "version" {
|
||||
continue
|
||||
}
|
||||
names = append(names, name)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Parent returns the parent context, if any
|
||||
func (c *Context) Parent() *Context {
|
||||
return c.parentContext
|
||||
}
|
||||
|
||||
// value returns the value of the flag coressponding to `name`
|
||||
func (c *Context) value(name string) interface{} {
|
||||
return c.flagSet.Lookup(name).Value.(flag.Getter).Get()
|
||||
}
|
||||
|
||||
// Args contains apps console arguments
|
||||
type Args []string
|
||||
|
||||
// Args returns the command line arguments associated with the context.
|
||||
func (c *Context) Args() Args {
|
||||
args := Args(c.flagSet.Args())
|
||||
return args
|
||||
}
|
||||
|
||||
// NArg returns the number of the command line arguments.
|
||||
func (c *Context) NArg() int {
|
||||
return len(c.Args())
|
||||
}
|
||||
|
||||
// Get returns the nth argument, or else a blank string
|
||||
func (a Args) Get(n int) string {
|
||||
if len(a) > n {
|
||||
return a[n]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// First returns the first argument, or else a blank string
|
||||
func (a Args) First() string {
|
||||
return a.Get(0)
|
||||
}
|
||||
|
||||
// Tail returns the rest of the arguments (not the first one)
|
||||
// or else an empty string slice
|
||||
func (a Args) Tail() []string {
|
||||
if len(a) >= 2 {
|
||||
return []string(a)[1:]
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// Present checks if there are any arguments present
|
||||
func (a Args) Present() bool {
|
||||
return len(a) != 0
|
||||
}
|
||||
|
||||
// Swap swaps arguments at the given indexes
|
||||
func (a Args) Swap(from, to int) error {
|
||||
if from >= len(a) || to >= len(a) {
|
||||
return errors.New("index out of range")
|
||||
}
|
||||
a[from], a[to] = a[to], a[from]
|
||||
return nil
|
||||
}
|
||||
|
||||
func globalContext(ctx *Context) *Context {
|
||||
if ctx == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for {
|
||||
if ctx.parentContext == nil {
|
||||
return ctx
|
||||
}
|
||||
ctx = ctx.parentContext
|
||||
}
|
||||
}
|
||||
|
||||
func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet {
|
||||
if ctx.parentContext != nil {
|
||||
ctx = ctx.parentContext
|
||||
}
|
||||
for ; ctx != nil; ctx = ctx.parentContext {
|
||||
if f := ctx.flagSet.Lookup(name); f != nil {
|
||||
return ctx.flagSet
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
|
||||
switch ff.Value.(type) {
|
||||
case *StringSlice:
|
||||
default:
|
||||
set.Set(name, ff.Value.String())
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
|
||||
visited := make(map[string]bool)
|
||||
set.Visit(func(f *flag.Flag) {
|
||||
visited[f.Name] = true
|
||||
})
|
||||
for _, f := range flags {
|
||||
parts := strings.Split(f.GetName(), ",")
|
||||
if len(parts) == 1 {
|
||||
continue
|
||||
}
|
||||
var ff *flag.Flag
|
||||
for _, name := range parts {
|
||||
name = strings.Trim(name, " ")
|
||||
if visited[name] {
|
||||
if ff != nil {
|
||||
return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
|
||||
}
|
||||
ff = set.Lookup(name)
|
||||
}
|
||||
}
|
||||
if ff == nil {
|
||||
continue
|
||||
}
|
||||
for _, name := range parts {
|
||||
name = strings.Trim(name, " ")
|
||||
if !visited[name] {
|
||||
copyFlag(name, ff, set)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -0,0 +1,399 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNewContext(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Int("myflag", 12, "doc")
|
||||
set.Int64("myflagInt64", int64(12), "doc")
|
||||
set.Uint("myflagUint", uint(93), "doc")
|
||||
set.Uint64("myflagUint64", uint64(93), "doc")
|
||||
set.Float64("myflag64", float64(17), "doc")
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.Int("myflag", 42, "doc")
|
||||
globalSet.Int64("myflagInt64", int64(42), "doc")
|
||||
globalSet.Uint("myflagUint", uint(33), "doc")
|
||||
globalSet.Uint64("myflagUint64", uint64(33), "doc")
|
||||
globalSet.Float64("myflag64", float64(47), "doc")
|
||||
globalCtx := NewContext(nil, globalSet, nil)
|
||||
command := Command{Name: "mycommand"}
|
||||
c := NewContext(nil, set, globalCtx)
|
||||
c.Command = command
|
||||
expect(t, c.Int("myflag"), 12)
|
||||
expect(t, c.Int64("myflagInt64"), int64(12))
|
||||
expect(t, c.Uint("myflagUint"), uint(93))
|
||||
expect(t, c.Uint64("myflagUint64"), uint64(93))
|
||||
expect(t, c.Float64("myflag64"), float64(17))
|
||||
expect(t, c.GlobalInt("myflag"), 42)
|
||||
expect(t, c.GlobalInt64("myflagInt64"), int64(42))
|
||||
expect(t, c.GlobalUint("myflagUint"), uint(33))
|
||||
expect(t, c.GlobalUint64("myflagUint64"), uint64(33))
|
||||
expect(t, c.GlobalFloat64("myflag64"), float64(47))
|
||||
expect(t, c.Command.Name, "mycommand")
|
||||
}
|
||||
|
||||
func TestContext_Int(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Int("myflag", 12, "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.Int("myflag"), 12)
|
||||
}
|
||||
|
||||
func TestContext_Int64(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Int64("myflagInt64", 12, "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.Int64("myflagInt64"), int64(12))
|
||||
}
|
||||
|
||||
func TestContext_Uint(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Uint("myflagUint", uint(13), "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.Uint("myflagUint"), uint(13))
|
||||
}
|
||||
|
||||
func TestContext_Uint64(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Uint64("myflagUint64", uint64(9), "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.Uint64("myflagUint64"), uint64(9))
|
||||
}
|
||||
|
||||
func TestContext_GlobalInt(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Int("myflag", 12, "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.GlobalInt("myflag"), 12)
|
||||
expect(t, c.GlobalInt("nope"), 0)
|
||||
}
|
||||
|
||||
func TestContext_GlobalInt64(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Int64("myflagInt64", 12, "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.GlobalInt64("myflagInt64"), int64(12))
|
||||
expect(t, c.GlobalInt64("nope"), int64(0))
|
||||
}
|
||||
|
||||
func TestContext_Float64(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Float64("myflag", float64(17), "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.Float64("myflag"), float64(17))
|
||||
}
|
||||
|
||||
func TestContext_GlobalFloat64(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Float64("myflag", float64(17), "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.GlobalFloat64("myflag"), float64(17))
|
||||
expect(t, c.GlobalFloat64("nope"), float64(0))
|
||||
}
|
||||
|
||||
func TestContext_Duration(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Duration("myflag", time.Duration(12*time.Second), "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.Duration("myflag"), time.Duration(12*time.Second))
|
||||
}
|
||||
|
||||
func TestContext_String(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("myflag", "hello world", "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.String("myflag"), "hello world")
|
||||
}
|
||||
|
||||
func TestContext_Bool(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.Bool("myflag"), false)
|
||||
}
|
||||
|
||||
func TestContext_BoolT(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", true, "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.BoolT("myflag"), true)
|
||||
}
|
||||
|
||||
func TestContext_GlobalBool(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
|
||||
globalSet := flag.NewFlagSet("test-global", 0)
|
||||
globalSet.Bool("myflag", false, "doc")
|
||||
globalCtx := NewContext(nil, globalSet, nil)
|
||||
|
||||
c := NewContext(nil, set, globalCtx)
|
||||
expect(t, c.GlobalBool("myflag"), false)
|
||||
expect(t, c.GlobalBool("nope"), false)
|
||||
}
|
||||
|
||||
func TestContext_GlobalBoolT(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
|
||||
globalSet := flag.NewFlagSet("test-global", 0)
|
||||
globalSet.Bool("myflag", true, "doc")
|
||||
globalCtx := NewContext(nil, globalSet, nil)
|
||||
|
||||
c := NewContext(nil, set, globalCtx)
|
||||
expect(t, c.GlobalBoolT("myflag"), true)
|
||||
expect(t, c.GlobalBoolT("nope"), false)
|
||||
}
|
||||
|
||||
func TestContext_Args(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
set.Parse([]string{"--myflag", "bat", "baz"})
|
||||
expect(t, len(c.Args()), 2)
|
||||
expect(t, c.Bool("myflag"), true)
|
||||
}
|
||||
|
||||
func TestContext_NArg(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
set.Parse([]string{"--myflag", "bat", "baz"})
|
||||
expect(t, c.NArg(), 2)
|
||||
}
|
||||
|
||||
func TestContext_IsSet(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
set.String("otherflag", "hello world", "doc")
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.Bool("myflagGlobal", true, "doc")
|
||||
globalCtx := NewContext(nil, globalSet, nil)
|
||||
c := NewContext(nil, set, globalCtx)
|
||||
set.Parse([]string{"--myflag", "bat", "baz"})
|
||||
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
|
||||
expect(t, c.IsSet("myflag"), true)
|
||||
expect(t, c.IsSet("otherflag"), false)
|
||||
expect(t, c.IsSet("bogusflag"), false)
|
||||
expect(t, c.IsSet("myflagGlobal"), false)
|
||||
}
|
||||
|
||||
// XXX Corresponds to hack in context.IsSet for flags with EnvVar field
|
||||
// Should be moved to `flag_test` in v2
|
||||
func TestContext_IsSet_fromEnv(t *testing.T) {
|
||||
var (
|
||||
timeoutIsSet, tIsSet bool
|
||||
noEnvVarIsSet, nIsSet bool
|
||||
passwordIsSet, pIsSet bool
|
||||
unparsableIsSet, uIsSet bool
|
||||
)
|
||||
|
||||
clearenv()
|
||||
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
|
||||
os.Setenv("APP_PASSWORD", "")
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
|
||||
StringFlag{Name: "password, p", EnvVar: "APP_PASSWORD"},
|
||||
Float64Flag{Name: "unparsable, u", EnvVar: "APP_UNPARSABLE"},
|
||||
Float64Flag{Name: "no-env-var, n"},
|
||||
},
|
||||
Action: func(ctx *Context) error {
|
||||
timeoutIsSet = ctx.IsSet("timeout")
|
||||
tIsSet = ctx.IsSet("t")
|
||||
passwordIsSet = ctx.IsSet("password")
|
||||
pIsSet = ctx.IsSet("p")
|
||||
unparsableIsSet = ctx.IsSet("unparsable")
|
||||
uIsSet = ctx.IsSet("u")
|
||||
noEnvVarIsSet = ctx.IsSet("no-env-var")
|
||||
nIsSet = ctx.IsSet("n")
|
||||
return nil
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
expect(t, timeoutIsSet, true)
|
||||
expect(t, tIsSet, true)
|
||||
expect(t, passwordIsSet, true)
|
||||
expect(t, pIsSet, true)
|
||||
expect(t, noEnvVarIsSet, false)
|
||||
expect(t, nIsSet, false)
|
||||
|
||||
os.Setenv("APP_UNPARSABLE", "foobar")
|
||||
a.Run([]string{"run"})
|
||||
expect(t, unparsableIsSet, false)
|
||||
expect(t, uIsSet, false)
|
||||
}
|
||||
|
||||
func TestContext_GlobalIsSet(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
set.String("otherflag", "hello world", "doc")
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.Bool("myflagGlobal", true, "doc")
|
||||
globalSet.Bool("myflagGlobalUnset", true, "doc")
|
||||
globalCtx := NewContext(nil, globalSet, nil)
|
||||
c := NewContext(nil, set, globalCtx)
|
||||
set.Parse([]string{"--myflag", "bat", "baz"})
|
||||
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
|
||||
expect(t, c.GlobalIsSet("myflag"), false)
|
||||
expect(t, c.GlobalIsSet("otherflag"), false)
|
||||
expect(t, c.GlobalIsSet("bogusflag"), false)
|
||||
expect(t, c.GlobalIsSet("myflagGlobal"), true)
|
||||
expect(t, c.GlobalIsSet("myflagGlobalUnset"), false)
|
||||
expect(t, c.GlobalIsSet("bogusGlobal"), false)
|
||||
}
|
||||
|
||||
// XXX Corresponds to hack in context.IsSet for flags with EnvVar field
|
||||
// Should be moved to `flag_test` in v2
|
||||
func TestContext_GlobalIsSet_fromEnv(t *testing.T) {
|
||||
var (
|
||||
timeoutIsSet, tIsSet bool
|
||||
noEnvVarIsSet, nIsSet bool
|
||||
passwordIsSet, pIsSet bool
|
||||
unparsableIsSet, uIsSet bool
|
||||
)
|
||||
|
||||
clearenv()
|
||||
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
|
||||
os.Setenv("APP_PASSWORD", "")
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
|
||||
StringFlag{Name: "password, p", EnvVar: "APP_PASSWORD"},
|
||||
Float64Flag{Name: "no-env-var, n"},
|
||||
Float64Flag{Name: "unparsable, u", EnvVar: "APP_UNPARSABLE"},
|
||||
},
|
||||
Commands: []Command{
|
||||
{
|
||||
Name: "hello",
|
||||
Action: func(ctx *Context) error {
|
||||
timeoutIsSet = ctx.GlobalIsSet("timeout")
|
||||
tIsSet = ctx.GlobalIsSet("t")
|
||||
passwordIsSet = ctx.GlobalIsSet("password")
|
||||
pIsSet = ctx.GlobalIsSet("p")
|
||||
unparsableIsSet = ctx.GlobalIsSet("unparsable")
|
||||
uIsSet = ctx.GlobalIsSet("u")
|
||||
noEnvVarIsSet = ctx.GlobalIsSet("no-env-var")
|
||||
nIsSet = ctx.GlobalIsSet("n")
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := a.Run([]string{"run", "hello"}); err != nil {
|
||||
t.Logf("error running Run(): %+v", err)
|
||||
}
|
||||
expect(t, timeoutIsSet, true)
|
||||
expect(t, tIsSet, true)
|
||||
expect(t, passwordIsSet, true)
|
||||
expect(t, pIsSet, true)
|
||||
expect(t, noEnvVarIsSet, false)
|
||||
expect(t, nIsSet, false)
|
||||
|
||||
os.Setenv("APP_UNPARSABLE", "foobar")
|
||||
if err := a.Run([]string{"run"}); err != nil {
|
||||
t.Logf("error running Run(): %+v", err)
|
||||
}
|
||||
expect(t, unparsableIsSet, false)
|
||||
expect(t, uIsSet, false)
|
||||
}
|
||||
|
||||
func TestContext_NumFlags(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
set.String("otherflag", "hello world", "doc")
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.Bool("myflagGlobal", true, "doc")
|
||||
globalCtx := NewContext(nil, globalSet, nil)
|
||||
c := NewContext(nil, set, globalCtx)
|
||||
set.Parse([]string{"--myflag", "--otherflag=foo"})
|
||||
globalSet.Parse([]string{"--myflagGlobal"})
|
||||
expect(t, c.NumFlags(), 2)
|
||||
}
|
||||
|
||||
func TestContext_GlobalFlag(t *testing.T) {
|
||||
var globalFlag string
|
||||
var globalFlagSet bool
|
||||
app := NewApp()
|
||||
app.Flags = []Flag{
|
||||
StringFlag{Name: "global, g", Usage: "global"},
|
||||
}
|
||||
app.Action = func(c *Context) error {
|
||||
globalFlag = c.GlobalString("global")
|
||||
globalFlagSet = c.GlobalIsSet("global")
|
||||
return nil
|
||||
}
|
||||
app.Run([]string{"command", "-g", "foo"})
|
||||
expect(t, globalFlag, "foo")
|
||||
expect(t, globalFlagSet, true)
|
||||
|
||||
}
|
||||
|
||||
func TestContext_GlobalFlagsInSubcommands(t *testing.T) {
|
||||
subcommandRun := false
|
||||
parentFlag := false
|
||||
app := NewApp()
|
||||
|
||||
app.Flags = []Flag{
|
||||
BoolFlag{Name: "debug, d", Usage: "Enable debugging"},
|
||||
}
|
||||
|
||||
app.Commands = []Command{
|
||||
{
|
||||
Name: "foo",
|
||||
Flags: []Flag{
|
||||
BoolFlag{Name: "parent, p", Usage: "Parent flag"},
|
||||
},
|
||||
Subcommands: []Command{
|
||||
{
|
||||
Name: "bar",
|
||||
Action: func(c *Context) error {
|
||||
if c.GlobalBool("debug") {
|
||||
subcommandRun = true
|
||||
}
|
||||
if c.GlobalBool("parent") {
|
||||
parentFlag = true
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run([]string{"command", "-d", "foo", "-p", "bar"})
|
||||
|
||||
expect(t, subcommandRun, true)
|
||||
expect(t, parentFlag, true)
|
||||
}
|
||||
|
||||
func TestContext_Set(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Int("int", 5, "an int")
|
||||
c := NewContext(nil, set, nil)
|
||||
|
||||
c.Set("int", "1")
|
||||
expect(t, c.Int("int"), 1)
|
||||
}
|
||||
|
||||
func TestContext_GlobalSet(t *testing.T) {
|
||||
gSet := flag.NewFlagSet("test", 0)
|
||||
gSet.Int("int", 5, "an int")
|
||||
|
||||
set := flag.NewFlagSet("sub", 0)
|
||||
set.Int("int", 3, "an int")
|
||||
|
||||
pc := NewContext(nil, gSet, nil)
|
||||
c := NewContext(nil, set, pc)
|
||||
|
||||
c.Set("int", "1")
|
||||
expect(t, c.Int("int"), 1)
|
||||
expect(t, c.GlobalInt("int"), 5)
|
||||
|
||||
c.GlobalSet("int", "1")
|
||||
expect(t, c.Int("int"), 1)
|
||||
expect(t, c.GlobalInt("int"), 1)
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// OsExiter is the function used when the app exits. If not set defaults to os.Exit.
|
||||
var OsExiter = os.Exit
|
||||
|
||||
// ErrWriter is used to write errors to the user. This can be anything
|
||||
// implementing the io.Writer interface and defaults to os.Stderr.
|
||||
var ErrWriter io.Writer = os.Stderr
|
||||
|
||||
// MultiError is an error that wraps multiple errors.
|
||||
type MultiError struct {
|
||||
Errors []error
|
||||
}
|
||||
|
||||
// NewMultiError creates a new MultiError. Pass in one or more errors.
|
||||
func NewMultiError(err ...error) MultiError {
|
||||
return MultiError{Errors: err}
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (m MultiError) Error() string {
|
||||
errs := make([]string, len(m.Errors))
|
||||
for i, err := range m.Errors {
|
||||
errs[i] = err.Error()
|
||||
}
|
||||
|
||||
return strings.Join(errs, "\n")
|
||||
}
|
||||
|
||||
type ErrorFormatter interface {
|
||||
Format(s fmt.State, verb rune)
|
||||
}
|
||||
|
||||
// ExitCoder is the interface checked by `App` and `Command` for a custom exit
|
||||
// code
|
||||
type ExitCoder interface {
|
||||
error
|
||||
ExitCode() int
|
||||
}
|
||||
|
||||
// ExitError fulfills both the builtin `error` interface and `ExitCoder`
|
||||
type ExitError struct {
|
||||
exitCode int
|
||||
message interface{}
|
||||
}
|
||||
|
||||
// NewExitError makes a new *ExitError
|
||||
func NewExitError(message interface{}, exitCode int) *ExitError {
|
||||
return &ExitError{
|
||||
exitCode: exitCode,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// Error returns the string message, fulfilling the interface required by
|
||||
// `error`
|
||||
func (ee *ExitError) Error() string {
|
||||
return fmt.Sprintf("%v", ee.message)
|
||||
}
|
||||
|
||||
// ExitCode returns the exit code, fulfilling the interface required by
|
||||
// `ExitCoder`
|
||||
func (ee *ExitError) ExitCode() int {
|
||||
return ee.exitCode
|
||||
}
|
||||
|
||||
// HandleExitCoder checks if the error fulfills the ExitCoder interface, and if
|
||||
// so prints the error to stderr (if it is non-empty) and calls OsExiter with the
|
||||
// given exit code. If the given error is a MultiError, then this func is
|
||||
// called on all members of the Errors slice and calls OsExiter with the last exit code.
|
||||
func HandleExitCoder(err error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if exitErr, ok := err.(ExitCoder); ok {
|
||||
if err.Error() != "" {
|
||||
if _, ok := exitErr.(ErrorFormatter); ok {
|
||||
fmt.Fprintf(ErrWriter, "%+v\n", err)
|
||||
} else {
|
||||
fmt.Fprintln(ErrWriter, err)
|
||||
}
|
||||
}
|
||||
OsExiter(exitErr.ExitCode())
|
||||
return
|
||||
}
|
||||
|
||||
if multiErr, ok := err.(MultiError); ok {
|
||||
code := handleMultiError(multiErr)
|
||||
OsExiter(code)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func handleMultiError(multiErr MultiError) int {
|
||||
code := 1
|
||||
for _, merr := range multiErr.Errors {
|
||||
if multiErr2, ok := merr.(MultiError); ok {
|
||||
code = handleMultiError(multiErr2)
|
||||
} else {
|
||||
fmt.Fprintln(ErrWriter, merr)
|
||||
if exitErr, ok := merr.(ExitCoder); ok {
|
||||
code = exitErr.ExitCode()
|
||||
}
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHandleExitCoder_nil(t *testing.T) {
|
||||
exitCode := 0
|
||||
called := false
|
||||
|
||||
OsExiter = func(rc int) {
|
||||
if !called {
|
||||
exitCode = rc
|
||||
called = true
|
||||
}
|
||||
}
|
||||
|
||||
defer func() { OsExiter = fakeOsExiter }()
|
||||
|
||||
HandleExitCoder(nil)
|
||||
|
||||
expect(t, exitCode, 0)
|
||||
expect(t, called, false)
|
||||
}
|
||||
|
||||
func TestHandleExitCoder_ExitCoder(t *testing.T) {
|
||||
exitCode := 0
|
||||
called := false
|
||||
|
||||
OsExiter = func(rc int) {
|
||||
if !called {
|
||||
exitCode = rc
|
||||
called = true
|
||||
}
|
||||
}
|
||||
|
||||
defer func() { OsExiter = fakeOsExiter }()
|
||||
|
||||
HandleExitCoder(NewExitError("galactic perimeter breach", 9))
|
||||
|
||||
expect(t, exitCode, 9)
|
||||
expect(t, called, true)
|
||||
}
|
||||
|
||||
func TestHandleExitCoder_MultiErrorWithExitCoder(t *testing.T) {
|
||||
exitCode := 0
|
||||
called := false
|
||||
|
||||
OsExiter = func(rc int) {
|
||||
if !called {
|
||||
exitCode = rc
|
||||
called = true
|
||||
}
|
||||
}
|
||||
|
||||
defer func() { OsExiter = fakeOsExiter }()
|
||||
|
||||
exitErr := NewExitError("galactic perimeter breach", 9)
|
||||
exitErr2 := NewExitError("last ExitCoder", 11)
|
||||
err := NewMultiError(errors.New("wowsa"), errors.New("egad"), exitErr, exitErr2)
|
||||
HandleExitCoder(err)
|
||||
|
||||
expect(t, exitCode, 11)
|
||||
expect(t, called, true)
|
||||
}
|
||||
|
||||
// make a stub to not import pkg/errors
|
||||
type ErrorWithFormat struct {
|
||||
error
|
||||
}
|
||||
|
||||
func NewErrorWithFormat(m string) *ErrorWithFormat {
|
||||
return &ErrorWithFormat{error: errors.New(m)}
|
||||
}
|
||||
|
||||
func (f *ErrorWithFormat) Format(s fmt.State, verb rune) {
|
||||
fmt.Fprintf(s, "This the format: %v", f.error)
|
||||
}
|
||||
|
||||
func TestHandleExitCoder_ErrorWithFormat(t *testing.T) {
|
||||
called := false
|
||||
|
||||
OsExiter = func(rc int) {
|
||||
if !called {
|
||||
called = true
|
||||
}
|
||||
}
|
||||
ErrWriter = &bytes.Buffer{}
|
||||
|
||||
defer func() {
|
||||
OsExiter = fakeOsExiter
|
||||
ErrWriter = fakeErrWriter
|
||||
}()
|
||||
|
||||
err := NewExitError(NewErrorWithFormat("I am formatted"), 1)
|
||||
HandleExitCoder(err)
|
||||
|
||||
expect(t, called, true)
|
||||
expect(t, ErrWriter.(*bytes.Buffer).String(), "This the format: I am formatted\n")
|
||||
}
|
||||
|
||||
func TestHandleExitCoder_MultiErrorWithFormat(t *testing.T) {
|
||||
called := false
|
||||
|
||||
OsExiter = func(rc int) {
|
||||
if !called {
|
||||
called = true
|
||||
}
|
||||
}
|
||||
ErrWriter = &bytes.Buffer{}
|
||||
|
||||
defer func() { OsExiter = fakeOsExiter }()
|
||||
|
||||
err := NewMultiError(NewErrorWithFormat("err1"), NewErrorWithFormat("err2"))
|
||||
HandleExitCoder(err)
|
||||
|
||||
expect(t, called, true)
|
||||
expect(t, ErrWriter.(*bytes.Buffer).String(), "This the format: err1\nThis the format: err2\n")
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
[
|
||||
{
|
||||
"name": "Bool",
|
||||
"type": "bool",
|
||||
"value": false,
|
||||
"context_default": "false",
|
||||
"parser": "strconv.ParseBool(f.Value.String())"
|
||||
},
|
||||
{
|
||||
"name": "BoolT",
|
||||
"type": "bool",
|
||||
"value": false,
|
||||
"doctail": " that is true by default",
|
||||
"context_default": "false",
|
||||
"parser": "strconv.ParseBool(f.Value.String())"
|
||||
},
|
||||
{
|
||||
"name": "Duration",
|
||||
"type": "time.Duration",
|
||||
"doctail": " (see https://golang.org/pkg/time/#ParseDuration)",
|
||||
"context_default": "0",
|
||||
"parser": "time.ParseDuration(f.Value.String())"
|
||||
},
|
||||
{
|
||||
"name": "Float64",
|
||||
"type": "float64",
|
||||
"context_default": "0",
|
||||
"parser": "strconv.ParseFloat(f.Value.String(), 64)"
|
||||
},
|
||||
{
|
||||
"name": "Generic",
|
||||
"type": "Generic",
|
||||
"dest": false,
|
||||
"context_default": "nil",
|
||||
"context_type": "interface{}"
|
||||
},
|
||||
{
|
||||
"name": "Int64",
|
||||
"type": "int64",
|
||||
"context_default": "0",
|
||||
"parser": "strconv.ParseInt(f.Value.String(), 0, 64)"
|
||||
},
|
||||
{
|
||||
"name": "Int",
|
||||
"type": "int",
|
||||
"context_default": "0",
|
||||
"parser": "strconv.ParseInt(f.Value.String(), 0, 64)",
|
||||
"parser_cast": "int(parsed)"
|
||||
},
|
||||
{
|
||||
"name": "IntSlice",
|
||||
"type": "*IntSlice",
|
||||
"dest": false,
|
||||
"context_default": "nil",
|
||||
"context_type": "[]int",
|
||||
"parser": "(f.Value.(*IntSlice)).Value(), error(nil)"
|
||||
},
|
||||
{
|
||||
"name": "Int64Slice",
|
||||
"type": "*Int64Slice",
|
||||
"dest": false,
|
||||
"context_default": "nil",
|
||||
"context_type": "[]int64",
|
||||
"parser": "(f.Value.(*Int64Slice)).Value(), error(nil)"
|
||||
},
|
||||
{
|
||||
"name": "String",
|
||||
"type": "string",
|
||||
"context_default": "\"\"",
|
||||
"parser": "f.Value.String(), error(nil)"
|
||||
},
|
||||
{
|
||||
"name": "StringSlice",
|
||||
"type": "*StringSlice",
|
||||
"dest": false,
|
||||
"context_default": "nil",
|
||||
"context_type": "[]string",
|
||||
"parser": "(f.Value.(*StringSlice)).Value(), error(nil)"
|
||||
},
|
||||
{
|
||||
"name": "Uint64",
|
||||
"type": "uint64",
|
||||
"context_default": "0",
|
||||
"parser": "strconv.ParseUint(f.Value.String(), 0, 64)"
|
||||
},
|
||||
{
|
||||
"name": "Uint",
|
||||
"type": "uint",
|
||||
"context_default": "0",
|
||||
"parser": "strconv.ParseUint(f.Value.String(), 0, 64)",
|
||||
"parser_cast": "uint(parsed)"
|
||||
}
|
||||
]
|
@ -0,0 +1,762 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
const defaultPlaceholder = "value"
|
||||
|
||||
// BashCompletionFlag enables bash-completion for all commands and subcommands
|
||||
var BashCompletionFlag = BoolFlag{
|
||||
Name: "generate-bash-completion",
|
||||
Hidden: true,
|
||||
}
|
||||
|
||||
// VersionFlag prints the version for the application
|
||||
var VersionFlag = BoolFlag{
|
||||
Name: "version, v",
|
||||
Usage: "print the version",
|
||||
}
|
||||
|
||||
// HelpFlag prints the help for all commands and subcommands
|
||||
// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand
|
||||
// unless HideHelp is set to true)
|
||||
var HelpFlag = BoolFlag{
|
||||
Name: "help, h",
|
||||
Usage: "show help",
|
||||
}
|
||||
|
||||
// FlagStringer converts a flag definition to a string. This is used by help
|
||||
// to display a flag.
|
||||
var FlagStringer FlagStringFunc = stringifyFlag
|
||||
|
||||
// FlagsByName is a slice of Flag.
|
||||
type FlagsByName []Flag
|
||||
|
||||
func (f FlagsByName) Len() int {
|
||||
return len(f)
|
||||
}
|
||||
|
||||
func (f FlagsByName) Less(i, j int) bool {
|
||||
return f[i].GetName() < f[j].GetName()
|
||||
}
|
||||
|
||||
func (f FlagsByName) Swap(i, j int) {
|
||||
f[i], f[j] = f[j], f[i]
|
||||
}
|
||||
|
||||
// Flag is a common interface related to parsing flags in cli.
|
||||
// For more advanced flag parsing techniques, it is recommended that
|
||||
// this interface be implemented.
|
||||
type Flag interface {
|
||||
fmt.Stringer
|
||||
// Apply Flag settings to the given flag set
|
||||
Apply(*flag.FlagSet)
|
||||
GetName() string
|
||||
}
|
||||
|
||||
// errorableFlag is an interface that allows us to return errors during apply
|
||||
// it allows flags defined in this library to return errors in a fashion backwards compatible
|
||||
// TODO remove in v2 and modify the existing Flag interface to return errors
|
||||
type errorableFlag interface {
|
||||
Flag
|
||||
|
||||
ApplyWithError(*flag.FlagSet) error
|
||||
}
|
||||
|
||||
func flagSet(name string, flags []Flag) (*flag.FlagSet, error) {
|
||||
set := flag.NewFlagSet(name, flag.ContinueOnError)
|
||||
|
||||
for _, f := range flags {
|
||||
//TODO remove in v2 when errorableFlag is removed
|
||||
if ef, ok := f.(errorableFlag); ok {
|
||||
if err := ef.ApplyWithError(set); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
f.Apply(set)
|
||||
}
|
||||
}
|
||||
return set, nil
|
||||
}
|
||||
|
||||
func eachName(longName string, fn func(string)) {
|
||||
parts := strings.Split(longName, ",")
|
||||
for _, name := range parts {
|
||||
name = strings.Trim(name, " ")
|
||||
fn(name)
|
||||
}
|
||||
}
|
||||
|
||||
// Generic is a generic parseable type identified by a specific flag
|
||||
type Generic interface {
|
||||
Set(value string) error
|
||||
String() string
|
||||
}
|
||||
|
||||
// Apply takes the flagset and calls Set on the generic flag with the value
|
||||
// provided by the user for parsing by the flag
|
||||
// Ignores parsing errors
|
||||
func (f GenericFlag) Apply(set *flag.FlagSet) {
|
||||
f.ApplyWithError(set)
|
||||
}
|
||||
|
||||
// ApplyWithError takes the flagset and calls Set on the generic flag with the value
|
||||
// provided by the user for parsing by the flag
|
||||
func (f GenericFlag) ApplyWithError(set *flag.FlagSet) error {
|
||||
val := f.Value
|
||||
if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
|
||||
if err := val.Set(envVal); err != nil {
|
||||
return fmt.Errorf("could not parse %s as value for flag %s: %s", envVal, f.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
set.Var(f.Value, name, f.Usage)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// StringSlice is an opaque type for []string to satisfy flag.Value and flag.Getter
|
||||
type StringSlice []string
|
||||
|
||||
// Set appends the string value to the list of values
|
||||
func (f *StringSlice) Set(value string) error {
|
||||
*f = append(*f, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *StringSlice) String() string {
|
||||
return fmt.Sprintf("%s", *f)
|
||||
}
|
||||
|
||||
// Value returns the slice of strings set by this flag
|
||||
func (f *StringSlice) Value() []string {
|
||||
return *f
|
||||
}
|
||||
|
||||
// Get returns the slice of strings set by this flag
|
||||
func (f *StringSlice) Get() interface{} {
|
||||
return *f
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
// Ignores errors
|
||||
func (f StringSliceFlag) Apply(set *flag.FlagSet) {
|
||||
f.ApplyWithError(set)
|
||||
}
|
||||
|
||||
// ApplyWithError populates the flag given the flag set and environment
|
||||
func (f StringSliceFlag) ApplyWithError(set *flag.FlagSet) error {
|
||||
if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
|
||||
newVal := &StringSlice{}
|
||||
for _, s := range strings.Split(envVal, ",") {
|
||||
s = strings.TrimSpace(s)
|
||||
if err := newVal.Set(s); err != nil {
|
||||
return fmt.Errorf("could not parse %s as string value for flag %s: %s", envVal, f.Name, err)
|
||||
}
|
||||
}
|
||||
f.Value = newVal
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
if f.Value == nil {
|
||||
f.Value = &StringSlice{}
|
||||
}
|
||||
set.Var(f.Value, name, f.Usage)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IntSlice is an opaque type for []int to satisfy flag.Value and flag.Getter
|
||||
type IntSlice []int
|
||||
|
||||
// Set parses the value into an integer and appends it to the list of values
|
||||
func (f *IntSlice) Set(value string) error {
|
||||
tmp, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*f = append(*f, tmp)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *IntSlice) String() string {
|
||||
return fmt.Sprintf("%#v", *f)
|
||||
}
|
||||
|
||||
// Value returns the slice of ints set by this flag
|
||||
func (f *IntSlice) Value() []int {
|
||||
return *f
|
||||
}
|
||||
|
||||
// Get returns the slice of ints set by this flag
|
||||
func (f *IntSlice) Get() interface{} {
|
||||
return *f
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
// Ignores errors
|
||||
func (f IntSliceFlag) Apply(set *flag.FlagSet) {
|
||||
f.ApplyWithError(set)
|
||||
}
|
||||
|
||||
// ApplyWithError populates the flag given the flag set and environment
|
||||
func (f IntSliceFlag) ApplyWithError(set *flag.FlagSet) error {
|
||||
if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
|
||||
newVal := &IntSlice{}
|
||||
for _, s := range strings.Split(envVal, ",") {
|
||||
s = strings.TrimSpace(s)
|
||||
if err := newVal.Set(s); err != nil {
|
||||
return fmt.Errorf("could not parse %s as int slice value for flag %s: %s", envVal, f.Name, err)
|
||||
}
|
||||
}
|
||||
f.Value = newVal
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
if f.Value == nil {
|
||||
f.Value = &IntSlice{}
|
||||
}
|
||||
set.Var(f.Value, name, f.Usage)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Int64Slice is an opaque type for []int to satisfy flag.Value and flag.Getter
|
||||
type Int64Slice []int64
|
||||
|
||||
// Set parses the value into an integer and appends it to the list of values
|
||||
func (f *Int64Slice) Set(value string) error {
|
||||
tmp, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*f = append(*f, tmp)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value (for usage defaults)
|
||||
func (f *Int64Slice) String() string {
|
||||
return fmt.Sprintf("%#v", *f)
|
||||
}
|
||||
|
||||
// Value returns the slice of ints set by this flag
|
||||
func (f *Int64Slice) Value() []int64 {
|
||||
return *f
|
||||
}
|
||||
|
||||
// Get returns the slice of ints set by this flag
|
||||
func (f *Int64Slice) Get() interface{} {
|
||||
return *f
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
// Ignores errors
|
||||
func (f Int64SliceFlag) Apply(set *flag.FlagSet) {
|
||||
f.ApplyWithError(set)
|
||||
}
|
||||
|
||||
// ApplyWithError populates the flag given the flag set and environment
|
||||
func (f Int64SliceFlag) ApplyWithError(set *flag.FlagSet) error {
|
||||
if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
|
||||
newVal := &Int64Slice{}
|
||||
for _, s := range strings.Split(envVal, ",") {
|
||||
s = strings.TrimSpace(s)
|
||||
if err := newVal.Set(s); err != nil {
|
||||
return fmt.Errorf("could not parse %s as int64 slice value for flag %s: %s", envVal, f.Name, err)
|
||||
}
|
||||
}
|
||||
f.Value = newVal
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
if f.Value == nil {
|
||||
f.Value = &Int64Slice{}
|
||||
}
|
||||
set.Var(f.Value, name, f.Usage)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
// Ignores errors
|
||||
func (f BoolFlag) Apply(set *flag.FlagSet) {
|
||||
f.ApplyWithError(set)
|
||||
}
|
||||
|
||||
// ApplyWithError populates the flag given the flag set and environment
|
||||
func (f BoolFlag) ApplyWithError(set *flag.FlagSet) error {
|
||||
val := false
|
||||
if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
|
||||
if envVal == "" {
|
||||
val = false
|
||||
} else {
|
||||
envValBool, err := strconv.ParseBool(envVal)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err)
|
||||
}
|
||||
val = envValBool
|
||||
}
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
if f.Destination != nil {
|
||||
set.BoolVar(f.Destination, name, val, f.Usage)
|
||||
return
|
||||
}
|
||||
set.Bool(name, val, f.Usage)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
// Ignores errors
|
||||
func (f BoolTFlag) Apply(set *flag.FlagSet) {
|
||||
f.ApplyWithError(set)
|
||||
}
|
||||
|
||||
// ApplyWithError populates the flag given the flag set and environment
|
||||
func (f BoolTFlag) ApplyWithError(set *flag.FlagSet) error {
|
||||
val := true
|
||||
|
||||
if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
|
||||
if envVal == "" {
|
||||
val = false
|
||||
} else {
|
||||
envValBool, err := strconv.ParseBool(envVal)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err)
|
||||
}
|
||||
val = envValBool
|
||||
}
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
if f.Destination != nil {
|
||||
set.BoolVar(f.Destination, name, val, f.Usage)
|
||||
return
|
||||
}
|
||||
set.Bool(name, val, f.Usage)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
// Ignores errors
|
||||
func (f StringFlag) Apply(set *flag.FlagSet) {
|
||||
f.ApplyWithError(set)
|
||||
}
|
||||
|
||||
// ApplyWithError populates the flag given the flag set and environment
|
||||
func (f StringFlag) ApplyWithError(set *flag.FlagSet) error {
|
||||
if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
|
||||
f.Value = envVal
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
if f.Destination != nil {
|
||||
set.StringVar(f.Destination, name, f.Value, f.Usage)
|
||||
return
|
||||
}
|
||||
set.String(name, f.Value, f.Usage)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
// Ignores errors
|
||||
func (f IntFlag) Apply(set *flag.FlagSet) {
|
||||
f.ApplyWithError(set)
|
||||
}
|
||||
|
||||
// ApplyWithError populates the flag given the flag set and environment
|
||||
func (f IntFlag) ApplyWithError(set *flag.FlagSet) error {
|
||||
if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
|
||||
envValInt, err := strconv.ParseInt(envVal, 0, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err)
|
||||
}
|
||||
f.Value = int(envValInt)
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
if f.Destination != nil {
|
||||
set.IntVar(f.Destination, name, f.Value, f.Usage)
|
||||
return
|
||||
}
|
||||
set.Int(name, f.Value, f.Usage)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
// Ignores errors
|
||||
func (f Int64Flag) Apply(set *flag.FlagSet) {
|
||||
f.ApplyWithError(set)
|
||||
}
|
||||
|
||||
// ApplyWithError populates the flag given the flag set and environment
|
||||
func (f Int64Flag) ApplyWithError(set *flag.FlagSet) error {
|
||||
if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
|
||||
envValInt, err := strconv.ParseInt(envVal, 0, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err)
|
||||
}
|
||||
|
||||
f.Value = envValInt
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
if f.Destination != nil {
|
||||
set.Int64Var(f.Destination, name, f.Value, f.Usage)
|
||||
return
|
||||
}
|
||||
set.Int64(name, f.Value, f.Usage)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
// Ignores errors
|
||||
func (f UintFlag) Apply(set *flag.FlagSet) {
|
||||
f.ApplyWithError(set)
|
||||
}
|
||||
|
||||
// ApplyWithError populates the flag given the flag set and environment
|
||||
func (f UintFlag) ApplyWithError(set *flag.FlagSet) error {
|
||||
if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
|
||||
envValInt, err := strconv.ParseUint(envVal, 0, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse %s as uint value for flag %s: %s", envVal, f.Name, err)
|
||||
}
|
||||
|
||||
f.Value = uint(envValInt)
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
if f.Destination != nil {
|
||||
set.UintVar(f.Destination, name, f.Value, f.Usage)
|
||||
return
|
||||
}
|
||||
set.Uint(name, f.Value, f.Usage)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
// Ignores errors
|
||||
func (f Uint64Flag) Apply(set *flag.FlagSet) {
|
||||
f.ApplyWithError(set)
|
||||
}
|
||||
|
||||
// ApplyWithError populates the flag given the flag set and environment
|
||||
func (f Uint64Flag) ApplyWithError(set *flag.FlagSet) error {
|
||||
if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
|
||||
envValInt, err := strconv.ParseUint(envVal, 0, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse %s as uint64 value for flag %s: %s", envVal, f.Name, err)
|
||||
}
|
||||
|
||||
f.Value = uint64(envValInt)
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
if f.Destination != nil {
|
||||
set.Uint64Var(f.Destination, name, f.Value, f.Usage)
|
||||
return
|
||||
}
|
||||
set.Uint64(name, f.Value, f.Usage)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
// Ignores errors
|
||||
func (f DurationFlag) Apply(set *flag.FlagSet) {
|
||||
f.ApplyWithError(set)
|
||||
}
|
||||
|
||||
// ApplyWithError populates the flag given the flag set and environment
|
||||
func (f DurationFlag) ApplyWithError(set *flag.FlagSet) error {
|
||||
if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
|
||||
envValDuration, err := time.ParseDuration(envVal)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse %s as duration for flag %s: %s", envVal, f.Name, err)
|
||||
}
|
||||
|
||||
f.Value = envValDuration
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
if f.Destination != nil {
|
||||
set.DurationVar(f.Destination, name, f.Value, f.Usage)
|
||||
return
|
||||
}
|
||||
set.Duration(name, f.Value, f.Usage)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
// Ignores errors
|
||||
func (f Float64Flag) Apply(set *flag.FlagSet) {
|
||||
f.ApplyWithError(set)
|
||||
}
|
||||
|
||||
// ApplyWithError populates the flag given the flag set and environment
|
||||
func (f Float64Flag) ApplyWithError(set *flag.FlagSet) error {
|
||||
if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
|
||||
envValFloat, err := strconv.ParseFloat(envVal, 10)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse %s as float64 value for flag %s: %s", envVal, f.Name, err)
|
||||
}
|
||||
|
||||
f.Value = float64(envValFloat)
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
if f.Destination != nil {
|
||||
set.Float64Var(f.Destination, name, f.Value, f.Usage)
|
||||
return
|
||||
}
|
||||
set.Float64(name, f.Value, f.Usage)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func visibleFlags(fl []Flag) []Flag {
|
||||
visible := []Flag{}
|
||||
for _, flag := range fl {
|
||||
if !flagValue(flag).FieldByName("Hidden").Bool() {
|
||||
visible = append(visible, flag)
|
||||
}
|
||||
}
|
||||
return visible
|
||||
}
|
||||
|
||||
func prefixFor(name string) (prefix string) {
|
||||
if len(name) == 1 {
|
||||
prefix = "-"
|
||||
} else {
|
||||
prefix = "--"
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Returns the placeholder, if any, and the unquoted usage string.
|
||||
func unquoteUsage(usage string) (string, string) {
|
||||
for i := 0; i < len(usage); i++ {
|
||||
if usage[i] == '`' {
|
||||
for j := i + 1; j < len(usage); j++ {
|
||||
if usage[j] == '`' {
|
||||
name := usage[i+1 : j]
|
||||
usage = usage[:i] + name + usage[j+1:]
|
||||
return name, usage
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return "", usage
|
||||
}
|
||||
|
||||
func prefixedNames(fullName, placeholder string) string {
|
||||
var prefixed string
|
||||
parts := strings.Split(fullName, ",")
|
||||
for i, name := range parts {
|
||||
name = strings.Trim(name, " ")
|
||||
prefixed += prefixFor(name) + name
|
||||
if placeholder != "" {
|
||||
prefixed += " " + placeholder
|
||||
}
|
||||
if i < len(parts)-1 {
|
||||
prefixed += ", "
|
||||
}
|
||||
}
|
||||
return prefixed
|
||||
}
|
||||
|
||||
func withEnvHint(envVar, str string) string {
|
||||
envText := ""
|
||||
if envVar != "" {
|
||||
prefix := "$"
|
||||
suffix := ""
|
||||
sep := ", $"
|
||||
if runtime.GOOS == "windows" {
|
||||
prefix = "%"
|
||||
suffix = "%"
|
||||
sep = "%, %"
|
||||
}
|
||||
envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(strings.Split(envVar, ","), sep), suffix)
|
||||
}
|
||||
return str + envText
|
||||
}
|
||||
|
||||
func withFileHint(filePath, str string) string {
|
||||
fileText := ""
|
||||
if filePath != "" {
|
||||
fileText = fmt.Sprintf(" [%s]", filePath)
|
||||
}
|
||||
return str + fileText
|
||||
}
|
||||
|
||||
func flagValue(f Flag) reflect.Value {
|
||||
fv := reflect.ValueOf(f)
|
||||
for fv.Kind() == reflect.Ptr {
|
||||
fv = reflect.Indirect(fv)
|
||||
}
|
||||
return fv
|
||||
}
|
||||
|
||||
func stringifyFlag(f Flag) string {
|
||||
fv := flagValue(f)
|
||||
|
||||
switch f.(type) {
|
||||
case IntSliceFlag:
|
||||
return withFileHint(
|
||||
fv.FieldByName("FilePath").String(),
|
||||
withEnvHint(
|
||||
fv.FieldByName("EnvVar").String(),
|
||||
stringifyIntSliceFlag(f.(IntSliceFlag)),
|
||||
),
|
||||
)
|
||||
case Int64SliceFlag:
|
||||
return withFileHint(
|
||||
fv.FieldByName("FilePath").String(),
|
||||
withEnvHint(
|
||||
fv.FieldByName("EnvVar").String(),
|
||||
stringifyInt64SliceFlag(f.(Int64SliceFlag)),
|
||||
),
|
||||
)
|
||||
case StringSliceFlag:
|
||||
return withFileHint(
|
||||
fv.FieldByName("FilePath").String(),
|
||||
withEnvHint(
|
||||
fv.FieldByName("EnvVar").String(),
|
||||
stringifyStringSliceFlag(f.(StringSliceFlag)),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String())
|
||||
|
||||
needsPlaceholder := false
|
||||
defaultValueString := ""
|
||||
val := fv.FieldByName("Value")
|
||||
|
||||
if val.IsValid() {
|
||||
needsPlaceholder = true
|
||||
defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface())
|
||||
|
||||
if val.Kind() == reflect.String && val.String() != "" {
|
||||
defaultValueString = fmt.Sprintf(" (default: %q)", val.String())
|
||||
}
|
||||
}
|
||||
|
||||
if defaultValueString == " (default: )" {
|
||||
defaultValueString = ""
|
||||
}
|
||||
|
||||
if needsPlaceholder && placeholder == "" {
|
||||
placeholder = defaultPlaceholder
|
||||
}
|
||||
|
||||
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultValueString))
|
||||
|
||||
return withFileHint(
|
||||
fv.FieldByName("FilePath").String(),
|
||||
withEnvHint(
|
||||
fv.FieldByName("EnvVar").String(),
|
||||
fmt.Sprintf("%s\t%s", prefixedNames(fv.FieldByName("Name").String(), placeholder), usageWithDefault),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func stringifyIntSliceFlag(f IntSliceFlag) string {
|
||||
defaultVals := []string{}
|
||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
||||
for _, i := range f.Value.Value() {
|
||||
defaultVals = append(defaultVals, fmt.Sprintf("%d", i))
|
||||
}
|
||||
}
|
||||
|
||||
return stringifySliceFlag(f.Usage, f.Name, defaultVals)
|
||||
}
|
||||
|
||||
func stringifyInt64SliceFlag(f Int64SliceFlag) string {
|
||||
defaultVals := []string{}
|
||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
||||
for _, i := range f.Value.Value() {
|
||||
defaultVals = append(defaultVals, fmt.Sprintf("%d", i))
|
||||
}
|
||||
}
|
||||
|
||||
return stringifySliceFlag(f.Usage, f.Name, defaultVals)
|
||||
}
|
||||
|
||||
func stringifyStringSliceFlag(f StringSliceFlag) string {
|
||||
defaultVals := []string{}
|
||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
||||
for _, s := range f.Value.Value() {
|
||||
if len(s) > 0 {
|
||||
defaultVals = append(defaultVals, fmt.Sprintf("%q", s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stringifySliceFlag(f.Usage, f.Name, defaultVals)
|
||||
}
|
||||
|
||||
func stringifySliceFlag(usage, name string, defaultVals []string) string {
|
||||
placeholder, usage := unquoteUsage(usage)
|
||||
if placeholder == "" {
|
||||
placeholder = defaultPlaceholder
|
||||
}
|
||||
|
||||
defaultVal := ""
|
||||
if len(defaultVals) > 0 {
|
||||
defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", "))
|
||||
}
|
||||
|
||||
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal))
|
||||
return fmt.Sprintf("%s\t%s", prefixedNames(name, placeholder), usageWithDefault)
|
||||
}
|
||||
|
||||
func flagFromFileEnv(filePath, envName string) (val string, ok bool) {
|
||||
if filePath != "" {
|
||||
if data, err := ioutil.ReadFile(filePath); err == nil {
|
||||
return string(data), true
|
||||
}
|
||||
}
|
||||
for _, envVar := range strings.Split(envName, ",") {
|
||||
envVar = strings.TrimSpace(envVar)
|
||||
if envVal, ok := syscall.Getenv(envVar); ok {
|
||||
return envVal, true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
@ -0,0 +1,640 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// WARNING: This file is generated!
|
||||
|
||||
// BoolFlag is a flag with type bool
|
||||
type BoolFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
FilePath string
|
||||
Hidden bool
|
||||
Destination *bool
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f BoolFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// GetName returns the name of the flag
|
||||
func (f BoolFlag) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// Bool looks up the value of a local BoolFlag, returns
|
||||
// false if not found
|
||||
func (c *Context) Bool(name string) bool {
|
||||
return lookupBool(name, c.flagSet)
|
||||
}
|
||||
|
||||
// GlobalBool looks up the value of a global BoolFlag, returns
|
||||
// false if not found
|
||||
func (c *Context) GlobalBool(name string) bool {
|
||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||
return lookupBool(name, fs)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func lookupBool(name string, set *flag.FlagSet) bool {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := strconv.ParseBool(f.Value.String())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// BoolTFlag is a flag with type bool that is true by default
|
||||
type BoolTFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
FilePath string
|
||||
Hidden bool
|
||||
Destination *bool
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f BoolTFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// GetName returns the name of the flag
|
||||
func (f BoolTFlag) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// BoolT looks up the value of a local BoolTFlag, returns
|
||||
// false if not found
|
||||
func (c *Context) BoolT(name string) bool {
|
||||
return lookupBoolT(name, c.flagSet)
|
||||
}
|
||||
|
||||
// GlobalBoolT looks up the value of a global BoolTFlag, returns
|
||||
// false if not found
|
||||
func (c *Context) GlobalBoolT(name string) bool {
|
||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||
return lookupBoolT(name, fs)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func lookupBoolT(name string, set *flag.FlagSet) bool {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := strconv.ParseBool(f.Value.String())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration)
|
||||
type DurationFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
FilePath string
|
||||
Hidden bool
|
||||
Value time.Duration
|
||||
Destination *time.Duration
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f DurationFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// GetName returns the name of the flag
|
||||
func (f DurationFlag) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// Duration looks up the value of a local DurationFlag, returns
|
||||
// 0 if not found
|
||||
func (c *Context) Duration(name string) time.Duration {
|
||||
return lookupDuration(name, c.flagSet)
|
||||
}
|
||||
|
||||
// GlobalDuration looks up the value of a global DurationFlag, returns
|
||||
// 0 if not found
|
||||
func (c *Context) GlobalDuration(name string) time.Duration {
|
||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||
return lookupDuration(name, fs)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func lookupDuration(name string, set *flag.FlagSet) time.Duration {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := time.ParseDuration(f.Value.String())
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Float64Flag is a flag with type float64
|
||||
type Float64Flag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
FilePath string
|
||||
Hidden bool
|
||||
Value float64
|
||||
Destination *float64
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f Float64Flag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// GetName returns the name of the flag
|
||||
func (f Float64Flag) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// Float64 looks up the value of a local Float64Flag, returns
|
||||
// 0 if not found
|
||||
func (c *Context) Float64(name string) float64 {
|
||||
return lookupFloat64(name, c.flagSet)
|
||||
}
|
||||
|
||||
// GlobalFloat64 looks up the value of a global Float64Flag, returns
|
||||
// 0 if not found
|
||||
func (c *Context) GlobalFloat64(name string) float64 {
|
||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||
return lookupFloat64(name, fs)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func lookupFloat64(name string, set *flag.FlagSet) float64 {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := strconv.ParseFloat(f.Value.String(), 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// GenericFlag is a flag with type Generic
|
||||
type GenericFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
FilePath string
|
||||
Hidden bool
|
||||
Value Generic
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f GenericFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// GetName returns the name of the flag
|
||||
func (f GenericFlag) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// Generic looks up the value of a local GenericFlag, returns
|
||||
// nil if not found
|
||||
func (c *Context) Generic(name string) interface{} {
|
||||
return lookupGeneric(name, c.flagSet)
|
||||
}
|
||||
|
||||
// GlobalGeneric looks up the value of a global GenericFlag, returns
|
||||
// nil if not found
|
||||
func (c *Context) GlobalGeneric(name string) interface{} {
|
||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||
return lookupGeneric(name, fs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func lookupGeneric(name string, set *flag.FlagSet) interface{} {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := f.Value, error(nil)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Int64Flag is a flag with type int64
|
||||
type Int64Flag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
FilePath string
|
||||
Hidden bool
|
||||
Value int64
|
||||
Destination *int64
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f Int64Flag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// GetName returns the name of the flag
|
||||
func (f Int64Flag) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// Int64 looks up the value of a local Int64Flag, returns
|
||||
// 0 if not found
|
||||
func (c *Context) Int64(name string) int64 {
|
||||
return lookupInt64(name, c.flagSet)
|
||||
}
|
||||
|
||||
// GlobalInt64 looks up the value of a global Int64Flag, returns
|
||||
// 0 if not found
|
||||
func (c *Context) GlobalInt64(name string) int64 {
|
||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||
return lookupInt64(name, fs)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func lookupInt64(name string, set *flag.FlagSet) int64 {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := strconv.ParseInt(f.Value.String(), 0, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// IntFlag is a flag with type int
|
||||
type IntFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
FilePath string
|
||||
Hidden bool
|
||||
Value int
|
||||
Destination *int
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f IntFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// GetName returns the name of the flag
|
||||
func (f IntFlag) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// Int looks up the value of a local IntFlag, returns
|
||||
// 0 if not found
|
||||
func (c *Context) Int(name string) int {
|
||||
return lookupInt(name, c.flagSet)
|
||||
}
|
||||
|
||||
// GlobalInt looks up the value of a global IntFlag, returns
|
||||
// 0 if not found
|
||||
func (c *Context) GlobalInt(name string) int {
|
||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||
return lookupInt(name, fs)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func lookupInt(name string, set *flag.FlagSet) int {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := strconv.ParseInt(f.Value.String(), 0, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return int(parsed)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// IntSliceFlag is a flag with type *IntSlice
|
||||
type IntSliceFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
FilePath string
|
||||
Hidden bool
|
||||
Value *IntSlice
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f IntSliceFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// GetName returns the name of the flag
|
||||
func (f IntSliceFlag) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// IntSlice looks up the value of a local IntSliceFlag, returns
|
||||
// nil if not found
|
||||
func (c *Context) IntSlice(name string) []int {
|
||||
return lookupIntSlice(name, c.flagSet)
|
||||
}
|
||||
|
||||
// GlobalIntSlice looks up the value of a global IntSliceFlag, returns
|
||||
// nil if not found
|
||||
func (c *Context) GlobalIntSlice(name string) []int {
|
||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||
return lookupIntSlice(name, fs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func lookupIntSlice(name string, set *flag.FlagSet) []int {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := (f.Value.(*IntSlice)).Value(), error(nil)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Int64SliceFlag is a flag with type *Int64Slice
|
||||
type Int64SliceFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
FilePath string
|
||||
Hidden bool
|
||||
Value *Int64Slice
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f Int64SliceFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// GetName returns the name of the flag
|
||||
func (f Int64SliceFlag) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// Int64Slice looks up the value of a local Int64SliceFlag, returns
|
||||
// nil if not found
|
||||
func (c *Context) Int64Slice(name string) []int64 {
|
||||
return lookupInt64Slice(name, c.flagSet)
|
||||
}
|
||||
|
||||
// GlobalInt64Slice looks up the value of a global Int64SliceFlag, returns
|
||||
// nil if not found
|
||||
func (c *Context) GlobalInt64Slice(name string) []int64 {
|
||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||
return lookupInt64Slice(name, fs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func lookupInt64Slice(name string, set *flag.FlagSet) []int64 {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := (f.Value.(*Int64Slice)).Value(), error(nil)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StringFlag is a flag with type string
|
||||
type StringFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
FilePath string
|
||||
Hidden bool
|
||||
Value string
|
||||
Destination *string
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f StringFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// GetName returns the name of the flag
|
||||
func (f StringFlag) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// String looks up the value of a local StringFlag, returns
|
||||
// "" if not found
|
||||
func (c *Context) String(name string) string {
|
||||
return lookupString(name, c.flagSet)
|
||||
}
|
||||
|
||||
// GlobalString looks up the value of a global StringFlag, returns
|
||||
// "" if not found
|
||||
func (c *Context) GlobalString(name string) string {
|
||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||
return lookupString(name, fs)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func lookupString(name string, set *flag.FlagSet) string {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := f.Value.String(), error(nil)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// StringSliceFlag is a flag with type *StringSlice
|
||||
type StringSliceFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
FilePath string
|
||||
Hidden bool
|
||||
Value *StringSlice
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f StringSliceFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// GetName returns the name of the flag
|
||||
func (f StringSliceFlag) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// StringSlice looks up the value of a local StringSliceFlag, returns
|
||||
// nil if not found
|
||||
func (c *Context) StringSlice(name string) []string {
|
||||
return lookupStringSlice(name, c.flagSet)
|
||||
}
|
||||
|
||||
// GlobalStringSlice looks up the value of a global StringSliceFlag, returns
|
||||
// nil if not found
|
||||
func (c *Context) GlobalStringSlice(name string) []string {
|
||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||
return lookupStringSlice(name, fs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func lookupStringSlice(name string, set *flag.FlagSet) []string {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := (f.Value.(*StringSlice)).Value(), error(nil)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Uint64Flag is a flag with type uint64
|
||||
type Uint64Flag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
FilePath string
|
||||
Hidden bool
|
||||
Value uint64
|
||||
Destination *uint64
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f Uint64Flag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// GetName returns the name of the flag
|
||||
func (f Uint64Flag) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// Uint64 looks up the value of a local Uint64Flag, returns
|
||||
// 0 if not found
|
||||
func (c *Context) Uint64(name string) uint64 {
|
||||
return lookupUint64(name, c.flagSet)
|
||||
}
|
||||
|
||||
// GlobalUint64 looks up the value of a global Uint64Flag, returns
|
||||
// 0 if not found
|
||||
func (c *Context) GlobalUint64(name string) uint64 {
|
||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||
return lookupUint64(name, fs)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func lookupUint64(name string, set *flag.FlagSet) uint64 {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := strconv.ParseUint(f.Value.String(), 0, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// UintFlag is a flag with type uint
|
||||
type UintFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
FilePath string
|
||||
Hidden bool
|
||||
Value uint
|
||||
Destination *uint
|
||||
}
|
||||
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f UintFlag) String() string {
|
||||
return FlagStringer(f)
|
||||
}
|
||||
|
||||
// GetName returns the name of the flag
|
||||
func (f UintFlag) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// Uint looks up the value of a local UintFlag, returns
|
||||
// 0 if not found
|
||||
func (c *Context) Uint(name string) uint {
|
||||
return lookupUint(name, c.flagSet)
|
||||
}
|
||||
|
||||
// GlobalUint looks up the value of a global UintFlag, returns
|
||||
// 0 if not found
|
||||
func (c *Context) GlobalUint(name string) uint {
|
||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||
return lookupUint(name, fs)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func lookupUint(name string, set *flag.FlagSet) uint {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
parsed, err := strconv.ParseUint(f.Value.String(), 0, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return uint(parsed)
|
||||
}
|
||||
return 0
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,28 @@
|
||||
package cli
|
||||
|
||||
// BashCompleteFunc is an action to execute when the bash-completion flag is set
|
||||
type BashCompleteFunc func(*Context)
|
||||
|
||||
// BeforeFunc is an action to execute before any subcommands are run, but after
|
||||
// the context is ready if a non-nil error is returned, no subcommands are run
|
||||
type BeforeFunc func(*Context) error
|
||||
|
||||
// AfterFunc is an action to execute after any subcommands are run, but after the
|
||||
// subcommand has finished it is run even if Action() panics
|
||||
type AfterFunc func(*Context) error
|
||||
|
||||
// ActionFunc is the action to execute when no subcommands are specified
|
||||
type ActionFunc func(*Context) error
|
||||
|
||||
// CommandNotFoundFunc is executed if the proper command cannot be found
|
||||
type CommandNotFoundFunc func(*Context, string)
|
||||
|
||||
// OnUsageErrorFunc is executed if an usage error occurs. This is useful for displaying
|
||||
// customized usage error messages. This function is able to replace the
|
||||
// original error messages. If this function is not set, the "Incorrect usage"
|
||||
// is displayed and the execution is interrupted.
|
||||
type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error
|
||||
|
||||
// FlagStringFunc is used by the help generation to display a flag, which is
|
||||
// expected to be a single line.
|
||||
type FlagStringFunc func(Flag) string
|
@ -0,0 +1,256 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
The flag types that ship with the cli library have many things in common, and
|
||||
so we can take advantage of the `go generate` command to create much of the
|
||||
source code from a list of definitions. These definitions attempt to cover
|
||||
the parts that vary between flag types, and should evolve as needed.
|
||||
|
||||
An example of the minimum definition needed is:
|
||||
|
||||
{
|
||||
"name": "SomeType",
|
||||
"type": "sometype",
|
||||
"context_default": "nil"
|
||||
}
|
||||
|
||||
In this example, the code generated for the `cli` package will include a type
|
||||
named `SomeTypeFlag` that is expected to wrap a value of type `sometype`.
|
||||
Fetching values by name via `*cli.Context` will default to a value of `nil`.
|
||||
|
||||
A more complete, albeit somewhat redundant, example showing all available
|
||||
definition keys is:
|
||||
|
||||
{
|
||||
"name": "VeryMuchType",
|
||||
"type": "*VeryMuchType",
|
||||
"value": true,
|
||||
"dest": false,
|
||||
"doctail": " which really only wraps a []float64, oh well!",
|
||||
"context_type": "[]float64",
|
||||
"context_default": "nil",
|
||||
"parser": "parseVeryMuchType(f.Value.String())",
|
||||
"parser_cast": "[]float64(parsed)"
|
||||
}
|
||||
|
||||
The meaning of each field is as follows:
|
||||
|
||||
name (string) - The type "name", which will be suffixed with
|
||||
`Flag` when generating the type definition
|
||||
for `cli` and the wrapper type for `altsrc`
|
||||
type (string) - The type that the generated `Flag` type for `cli`
|
||||
is expected to "contain" as its `.Value` member
|
||||
value (bool) - Should the generated `cli` type have a `Value`
|
||||
member?
|
||||
dest (bool) - Should the generated `cli` type support a
|
||||
destination pointer?
|
||||
doctail (string) - Additional docs for the `cli` flag type comment
|
||||
context_type (string) - The literal type used in the `*cli.Context`
|
||||
reader func signature
|
||||
context_default (string) - The literal value used as the default by the
|
||||
`*cli.Context` reader funcs when no value is
|
||||
present
|
||||
parser (string) - Literal code used to parse the flag `f`,
|
||||
expected to have a return signature of
|
||||
(value, error)
|
||||
parser_cast (string) - Literal code used to cast the `parsed` value
|
||||
returned from the `parser` code
|
||||
"""
|
||||
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import textwrap
|
||||
|
||||
|
||||
class _FancyFormatter(argparse.ArgumentDefaultsHelpFormatter,
|
||||
argparse.RawDescriptionHelpFormatter):
|
||||
pass
|
||||
|
||||
|
||||
def main(sysargs=sys.argv[:]):
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Generate flag type code!',
|
||||
formatter_class=_FancyFormatter)
|
||||
parser.add_argument(
|
||||
'package',
|
||||
type=str, default='cli', choices=_WRITEFUNCS.keys(),
|
||||
help='Package for which flag types will be generated'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-i', '--in-json',
|
||||
type=argparse.FileType('r'),
|
||||
default=sys.stdin,
|
||||
help='Input JSON file which defines each type to be generated'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-o', '--out-go',
|
||||
type=argparse.FileType('w'),
|
||||
default=sys.stdout,
|
||||
help='Output file/stream to which generated source will be written'
|
||||
)
|
||||
parser.epilog = __doc__
|
||||
|
||||
args = parser.parse_args(sysargs[1:])
|
||||
_generate_flag_types(_WRITEFUNCS[args.package], args.out_go, args.in_json)
|
||||
return 0
|
||||
|
||||
|
||||
def _generate_flag_types(writefunc, output_go, input_json):
|
||||
types = json.load(input_json)
|
||||
|
||||
tmp = tempfile.NamedTemporaryFile(suffix='.go', delete=False)
|
||||
writefunc(tmp, types)
|
||||
tmp.close()
|
||||
|
||||
new_content = subprocess.check_output(
|
||||
['goimports', tmp.name]
|
||||
).decode('utf-8')
|
||||
|
||||
print(new_content, file=output_go, end='')
|
||||
output_go.flush()
|
||||
os.remove(tmp.name)
|
||||
|
||||
|
||||
def _set_typedef_defaults(typedef):
|
||||
typedef.setdefault('doctail', '')
|
||||
typedef.setdefault('context_type', typedef['type'])
|
||||
typedef.setdefault('dest', True)
|
||||
typedef.setdefault('value', True)
|
||||
typedef.setdefault('parser', 'f.Value, error(nil)')
|
||||
typedef.setdefault('parser_cast', 'parsed')
|
||||
|
||||
|
||||
def _write_cli_flag_types(outfile, types):
|
||||
_fwrite(outfile, """\
|
||||
package cli
|
||||
|
||||
// WARNING: This file is generated!
|
||||
|
||||
""")
|
||||
|
||||
for typedef in types:
|
||||
_set_typedef_defaults(typedef)
|
||||
|
||||
_fwrite(outfile, """\
|
||||
// {name}Flag is a flag with type {type}{doctail}
|
||||
type {name}Flag struct {{
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
FilePath string
|
||||
Hidden bool
|
||||
""".format(**typedef))
|
||||
|
||||
if typedef['value']:
|
||||
_fwrite(outfile, """\
|
||||
Value {type}
|
||||
""".format(**typedef))
|
||||
|
||||
if typedef['dest']:
|
||||
_fwrite(outfile, """\
|
||||
Destination *{type}
|
||||
""".format(**typedef))
|
||||
|
||||
_fwrite(outfile, "\n}\n\n")
|
||||
|
||||
_fwrite(outfile, """\
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f {name}Flag) String() string {{
|
||||
return FlagStringer(f)
|
||||
}}
|
||||
|
||||
// GetName returns the name of the flag
|
||||
func (f {name}Flag) GetName() string {{
|
||||
return f.Name
|
||||
}}
|
||||
|
||||
// {name} looks up the value of a local {name}Flag, returns
|
||||
// {context_default} if not found
|
||||
func (c *Context) {name}(name string) {context_type} {{
|
||||
return lookup{name}(name, c.flagSet)
|
||||
}}
|
||||
|
||||
// Global{name} looks up the value of a global {name}Flag, returns
|
||||
// {context_default} if not found
|
||||
func (c *Context) Global{name}(name string) {context_type} {{
|
||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {{
|
||||
return lookup{name}(name, fs)
|
||||
}}
|
||||
return {context_default}
|
||||
}}
|
||||
|
||||
func lookup{name}(name string, set *flag.FlagSet) {context_type} {{
|
||||
f := set.Lookup(name)
|
||||
if f != nil {{
|
||||
parsed, err := {parser}
|
||||
if err != nil {{
|
||||
return {context_default}
|
||||
}}
|
||||
return {parser_cast}
|
||||
}}
|
||||
return {context_default}
|
||||
}}
|
||||
""".format(**typedef))
|
||||
|
||||
|
||||
def _write_altsrc_flag_types(outfile, types):
|
||||
_fwrite(outfile, """\
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
// WARNING: This file is generated!
|
||||
|
||||
""")
|
||||
|
||||
for typedef in types:
|
||||
_set_typedef_defaults(typedef)
|
||||
|
||||
_fwrite(outfile, """\
|
||||
// {name}Flag is the flag type that wraps cli.{name}Flag to allow
|
||||
// for other values to be specified
|
||||
type {name}Flag struct {{
|
||||
cli.{name}Flag
|
||||
set *flag.FlagSet
|
||||
}}
|
||||
|
||||
// New{name}Flag creates a new {name}Flag
|
||||
func New{name}Flag(fl cli.{name}Flag) *{name}Flag {{
|
||||
return &{name}Flag{{{name}Flag: fl, set: nil}}
|
||||
}}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls the
|
||||
// wrapped {name}Flag.Apply
|
||||
func (f *{name}Flag) Apply(set *flag.FlagSet) {{
|
||||
f.set = set
|
||||
f.{name}Flag.Apply(set)
|
||||
}}
|
||||
|
||||
// ApplyWithError saves the flagSet for later usage calls, then calls the
|
||||
// wrapped {name}Flag.ApplyWithError
|
||||
func (f *{name}Flag) ApplyWithError(set *flag.FlagSet) error {{
|
||||
f.set = set
|
||||
return f.{name}Flag.ApplyWithError(set)
|
||||
}}
|
||||
""".format(**typedef))
|
||||
|
||||
|
||||
def _fwrite(outfile, text):
|
||||
print(textwrap.dedent(text), end='', file=outfile)
|
||||
|
||||
|
||||
_WRITEFUNCS = {
|
||||
'cli': _write_cli_flag_types,
|
||||
'altsrc': _write_altsrc_flag_types
|
||||
}
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -0,0 +1,294 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// AppHelpTemplate is the text template for the Default help topic.
|
||||
// cli.go uses text/template to render templates. You can
|
||||
// render custom help text by setting this variable.
|
||||
var AppHelpTemplate = `NAME:
|
||||
{{.Name}}{{if .Usage}} - {{.Usage}}{{end}}
|
||||
|
||||
USAGE:
|
||||
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}
|
||||
|
||||
VERSION:
|
||||
{{.Version}}{{end}}{{end}}{{if .Description}}
|
||||
|
||||
DESCRIPTION:
|
||||
{{.Description}}{{end}}{{if len .Authors}}
|
||||
|
||||
AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}:
|
||||
{{range $index, $author := .Authors}}{{if $index}}
|
||||
{{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}}
|
||||
|
||||
COMMANDS:{{range .VisibleCategories}}{{if .Name}}
|
||||
{{.Name}}:{{end}}{{range .VisibleCommands}}
|
||||
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
{{range $index, $option := .VisibleFlags}}{{if $index}}
|
||||
{{end}}{{$option}}{{end}}{{end}}{{if .Copyright}}
|
||||
|
||||
COPYRIGHT:
|
||||
{{.Copyright}}{{end}}
|
||||
`
|
||||
|
||||
// CommandHelpTemplate is the text template for the command help topic.
|
||||
// cli.go uses text/template to render templates. You can
|
||||
// render custom help text by setting this variable.
|
||||
var CommandHelpTemplate = `NAME:
|
||||
{{.HelpName}} - {{.Usage}}
|
||||
|
||||
USAGE:
|
||||
{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Category}}
|
||||
|
||||
CATEGORY:
|
||||
{{.Category}}{{end}}{{if .Description}}
|
||||
|
||||
DESCRIPTION:
|
||||
{{.Description}}{{end}}{{if .VisibleFlags}}
|
||||
|
||||
OPTIONS:
|
||||
{{range .VisibleFlags}}{{.}}
|
||||
{{end}}{{end}}
|
||||
`
|
||||
|
||||
// SubcommandHelpTemplate is the text template for the subcommand help topic.
|
||||
// cli.go uses text/template to render templates. You can
|
||||
// render custom help text by setting this variable.
|
||||
var SubcommandHelpTemplate = `NAME:
|
||||
{{.HelpName}} - {{if .Description}}{{.Description}}{{else}}{{.Usage}}{{end}}
|
||||
|
||||
USAGE:
|
||||
{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
|
||||
|
||||
COMMANDS:{{range .VisibleCategories}}{{if .Name}}
|
||||
{{.Name}}:{{end}}{{range .VisibleCommands}}
|
||||
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}
|
||||
{{end}}{{if .VisibleFlags}}
|
||||
OPTIONS:
|
||||
{{range .VisibleFlags}}{{.}}
|
||||
{{end}}{{end}}
|
||||
`
|
||||
|
||||
var helpCommand = Command{
|
||||
Name: "help",
|
||||
Aliases: []string{"h"},
|
||||
Usage: "Shows a list of commands or help for one command",
|
||||
ArgsUsage: "[command]",
|
||||
Action: func(c *Context) error {
|
||||
args := c.Args()
|
||||
if args.Present() {
|
||||
return ShowCommandHelp(c, args.First())
|
||||
}
|
||||
|
||||
ShowAppHelp(c)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var helpSubcommand = Command{
|
||||
Name: "help",
|
||||
Aliases: []string{"h"},
|
||||
Usage: "Shows a list of commands or help for one command",
|
||||
ArgsUsage: "[command]",
|
||||
Action: func(c *Context) error {
|
||||
args := c.Args()
|
||||
if args.Present() {
|
||||
return ShowCommandHelp(c, args.First())
|
||||
}
|
||||
|
||||
return ShowSubcommandHelp(c)
|
||||
},
|
||||
}
|
||||
|
||||
// Prints help for the App or Command
|
||||
type helpPrinter func(w io.Writer, templ string, data interface{})
|
||||
|
||||
// HelpPrinter is a function that writes the help output. If not set a default
|
||||
// is used. The function signature is:
|
||||
// func(w io.Writer, templ string, data interface{})
|
||||
var HelpPrinter helpPrinter = printHelp
|
||||
|
||||
// VersionPrinter prints the version for the App
|
||||
var VersionPrinter = printVersion
|
||||
|
||||
// ShowAppHelp is an action that displays the help.
|
||||
func ShowAppHelp(c *Context) error {
|
||||
HelpPrinter(c.App.Writer, AppHelpTemplate, c.App)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultAppComplete prints the list of subcommands as the default app completion method
|
||||
func DefaultAppComplete(c *Context) {
|
||||
for _, command := range c.App.Commands {
|
||||
if command.Hidden {
|
||||
continue
|
||||
}
|
||||
for _, name := range command.Names() {
|
||||
fmt.Fprintln(c.App.Writer, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ShowCommandHelp prints help for the given command
|
||||
func ShowCommandHelp(ctx *Context, command string) error {
|
||||
// show the subcommand help for a command with subcommands
|
||||
if command == "" {
|
||||
HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, c := range ctx.App.Commands {
|
||||
if c.HasName(command) {
|
||||
HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.App.CommandNotFound == nil {
|
||||
return NewExitError(fmt.Sprintf("No help topic for '%v'", command), 3)
|
||||
}
|
||||
|
||||
ctx.App.CommandNotFound(ctx, command)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ShowSubcommandHelp prints help for the given subcommand
|
||||
func ShowSubcommandHelp(c *Context) error {
|
||||
return ShowCommandHelp(c, c.Command.Name)
|
||||
}
|
||||
|
||||
// ShowVersion prints the version number of the App
|
||||
func ShowVersion(c *Context) {
|
||||
VersionPrinter(c)
|
||||
}
|
||||
|
||||
func printVersion(c *Context) {
|
||||
fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version)
|
||||
}
|
||||
|
||||
// ShowCompletions prints the lists of commands within a given context
|
||||
func ShowCompletions(c *Context) {
|
||||
a := c.App
|
||||
if a != nil && a.BashComplete != nil {
|
||||
a.BashComplete(c)
|
||||
}
|
||||
}
|
||||
|
||||
// ShowCommandCompletions prints the custom completions for a given command
|
||||
func ShowCommandCompletions(ctx *Context, command string) {
|
||||
c := ctx.App.Command(command)
|
||||
if c != nil && c.BashComplete != nil {
|
||||
c.BashComplete(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func printHelp(out io.Writer, templ string, data interface{}) {
|
||||
funcMap := template.FuncMap{
|
||||
"join": strings.Join,
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0)
|
||||
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
|
||||
err := t.Execute(w, data)
|
||||
if err != nil {
|
||||
// If the writer is closed, t.Execute will fail, and there's nothing
|
||||
// we can do to recover.
|
||||
if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" {
|
||||
fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
w.Flush()
|
||||
}
|
||||
|
||||
func checkVersion(c *Context) bool {
|
||||
found := false
|
||||
if VersionFlag.Name != "" {
|
||||
eachName(VersionFlag.Name, func(name string) {
|
||||
if c.GlobalBool(name) || c.Bool(name) {
|
||||
found = true
|
||||
}
|
||||
})
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
func checkHelp(c *Context) bool {
|
||||
found := false
|
||||
if HelpFlag.Name != "" {
|
||||
eachName(HelpFlag.Name, func(name string) {
|
||||
if c.GlobalBool(name) || c.Bool(name) {
|
||||
found = true
|
||||
}
|
||||
})
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
func checkCommandHelp(c *Context, name string) bool {
|
||||
if c.Bool("h") || c.Bool("help") {
|
||||
ShowCommandHelp(c, name)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func checkSubcommandHelp(c *Context) bool {
|
||||
if c.Bool("h") || c.Bool("help") {
|
||||
ShowSubcommandHelp(c)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) {
|
||||
if !a.EnableBashCompletion {
|
||||
return false, arguments
|
||||
}
|
||||
|
||||
pos := len(arguments) - 1
|
||||
lastArg := arguments[pos]
|
||||
|
||||
if lastArg != "--"+BashCompletionFlag.Name {
|
||||
return false, arguments
|
||||
}
|
||||
|
||||
return true, arguments[:pos]
|
||||
}
|
||||
|
||||
func checkCompletions(c *Context) bool {
|
||||
if !c.shellComplete {
|
||||
return false
|
||||
}
|
||||
|
||||
if args := c.Args(); args.Present() {
|
||||
name := args.First()
|
||||
if cmd := c.App.Command(name); cmd != nil {
|
||||
// let the command handle the completion
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
ShowCompletions(c)
|
||||
return true
|
||||
}
|
||||
|
||||
func checkCommandCompletions(c *Context, name string) bool {
|
||||
if !c.shellComplete {
|
||||
return false
|
||||
}
|
||||
|
||||
ShowCommandCompletions(c, name)
|
||||
return true
|
||||
}
|
@ -0,0 +1,289 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_ShowAppHelp_NoAuthor(t *testing.T) {
|
||||
output := new(bytes.Buffer)
|
||||
app := NewApp()
|
||||
app.Writer = output
|
||||
|
||||
c := NewContext(app, nil, nil)
|
||||
|
||||
ShowAppHelp(c)
|
||||
|
||||
if bytes.Index(output.Bytes(), []byte("AUTHOR(S):")) != -1 {
|
||||
t.Errorf("expected\n%snot to include %s", output.String(), "AUTHOR(S):")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ShowAppHelp_NoVersion(t *testing.T) {
|
||||
output := new(bytes.Buffer)
|
||||
app := NewApp()
|
||||
app.Writer = output
|
||||
|
||||
app.Version = ""
|
||||
|
||||
c := NewContext(app, nil, nil)
|
||||
|
||||
ShowAppHelp(c)
|
||||
|
||||
if bytes.Index(output.Bytes(), []byte("VERSION:")) != -1 {
|
||||
t.Errorf("expected\n%snot to include %s", output.String(), "VERSION:")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ShowAppHelp_HideVersion(t *testing.T) {
|
||||
output := new(bytes.Buffer)
|
||||
app := NewApp()
|
||||
app.Writer = output
|
||||
|
||||
app.HideVersion = true
|
||||
|
||||
c := NewContext(app, nil, nil)
|
||||
|
||||
ShowAppHelp(c)
|
||||
|
||||
if bytes.Index(output.Bytes(), []byte("VERSION:")) != -1 {
|
||||
t.Errorf("expected\n%snot to include %s", output.String(), "VERSION:")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Help_Custom_Flags(t *testing.T) {
|
||||
oldFlag := HelpFlag
|
||||
defer func() {
|
||||
HelpFlag = oldFlag
|
||||
}()
|
||||
|
||||
HelpFlag = BoolFlag{
|
||||
Name: "help, x",
|
||||
Usage: "show help",
|
||||
}
|
||||
|
||||
app := App{
|
||||
Flags: []Flag{
|
||||
BoolFlag{Name: "foo, h"},
|
||||
},
|
||||
Action: func(ctx *Context) error {
|
||||
if ctx.Bool("h") != true {
|
||||
t.Errorf("custom help flag not set")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
output := new(bytes.Buffer)
|
||||
app.Writer = output
|
||||
app.Run([]string{"test", "-h"})
|
||||
if output.Len() > 0 {
|
||||
t.Errorf("unexpected output: %s", output.String())
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Version_Custom_Flags(t *testing.T) {
|
||||
oldFlag := VersionFlag
|
||||
defer func() {
|
||||
VersionFlag = oldFlag
|
||||
}()
|
||||
|
||||
VersionFlag = BoolFlag{
|
||||
Name: "version, V",
|
||||
Usage: "show version",
|
||||
}
|
||||
|
||||
app := App{
|
||||
Flags: []Flag{
|
||||
BoolFlag{Name: "foo, v"},
|
||||
},
|
||||
Action: func(ctx *Context) error {
|
||||
if ctx.Bool("v") != true {
|
||||
t.Errorf("custom version flag not set")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
output := new(bytes.Buffer)
|
||||
app.Writer = output
|
||||
app.Run([]string{"test", "-v"})
|
||||
if output.Len() > 0 {
|
||||
t.Errorf("unexpected output: %s", output.String())
|
||||
}
|
||||
}
|
||||
|
||||
func Test_helpCommand_Action_ErrorIfNoTopic(t *testing.T) {
|
||||
app := NewApp()
|
||||
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Parse([]string{"foo"})
|
||||
|
||||
c := NewContext(app, set, nil)
|
||||
|
||||
err := helpCommand.Action.(func(*Context) error)(c)
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("expected error from helpCommand.Action(), but got nil")
|
||||
}
|
||||
|
||||
exitErr, ok := err.(*ExitError)
|
||||
if !ok {
|
||||
t.Fatalf("expected ExitError from helpCommand.Action(), but instead got: %v", err.Error())
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
|
||||
t.Fatalf("expected an unknown help topic error, but got: %v", exitErr.Error())
|
||||
}
|
||||
|
||||
if exitErr.exitCode != 3 {
|
||||
t.Fatalf("expected exit value = 3, got %d instead", exitErr.exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_helpCommand_InHelpOutput(t *testing.T) {
|
||||
app := NewApp()
|
||||
output := &bytes.Buffer{}
|
||||
app.Writer = output
|
||||
app.Run([]string{"test", "--help"})
|
||||
|
||||
s := output.String()
|
||||
|
||||
if strings.Contains(s, "\nCOMMANDS:\nGLOBAL OPTIONS:\n") {
|
||||
t.Fatalf("empty COMMANDS section detected: %q", s)
|
||||
}
|
||||
|
||||
if !strings.Contains(s, "help, h") {
|
||||
t.Fatalf("missing \"help, h\": %q", s)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) {
|
||||
app := NewApp()
|
||||
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Parse([]string{"foo"})
|
||||
|
||||
c := NewContext(app, set, nil)
|
||||
|
||||
err := helpSubcommand.Action.(func(*Context) error)(c)
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("expected error from helpCommand.Action(), but got nil")
|
||||
}
|
||||
|
||||
exitErr, ok := err.(*ExitError)
|
||||
if !ok {
|
||||
t.Fatalf("expected ExitError from helpCommand.Action(), but instead got: %v", err.Error())
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
|
||||
t.Fatalf("expected an unknown help topic error, but got: %v", exitErr.Error())
|
||||
}
|
||||
|
||||
if exitErr.exitCode != 3 {
|
||||
t.Fatalf("expected exit value = 3, got %d instead", exitErr.exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShowAppHelp_CommandAliases(t *testing.T) {
|
||||
app := &App{
|
||||
Commands: []Command{
|
||||
{
|
||||
Name: "frobbly",
|
||||
Aliases: []string{"fr", "frob"},
|
||||
Action: func(ctx *Context) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
output := &bytes.Buffer{}
|
||||
app.Writer = output
|
||||
app.Run([]string{"foo", "--help"})
|
||||
|
||||
if !strings.Contains(output.String(), "frobbly, fr, frob") {
|
||||
t.Errorf("expected output to include all command aliases; got: %q", output.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestShowCommandHelp_CommandAliases(t *testing.T) {
|
||||
app := &App{
|
||||
Commands: []Command{
|
||||
{
|
||||
Name: "frobbly",
|
||||
Aliases: []string{"fr", "frob", "bork"},
|
||||
Action: func(ctx *Context) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
output := &bytes.Buffer{}
|
||||
app.Writer = output
|
||||
app.Run([]string{"foo", "help", "fr"})
|
||||
|
||||
if !strings.Contains(output.String(), "frobbly") {
|
||||
t.Errorf("expected output to include command name; got: %q", output.String())
|
||||
}
|
||||
|
||||
if strings.Contains(output.String(), "bork") {
|
||||
t.Errorf("expected output to exclude command aliases; got: %q", output.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestShowSubcommandHelp_CommandAliases(t *testing.T) {
|
||||
app := &App{
|
||||
Commands: []Command{
|
||||
{
|
||||
Name: "frobbly",
|
||||
Aliases: []string{"fr", "frob", "bork"},
|
||||
Action: func(ctx *Context) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
output := &bytes.Buffer{}
|
||||
app.Writer = output
|
||||
app.Run([]string{"foo", "help"})
|
||||
|
||||
if !strings.Contains(output.String(), "frobbly, fr, frob, bork") {
|
||||
t.Errorf("expected output to include all command aliases; got: %q", output.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestShowAppHelp_HiddenCommand(t *testing.T) {
|
||||
app := &App{
|
||||
Commands: []Command{
|
||||
{
|
||||
Name: "frobbly",
|
||||
Action: func(ctx *Context) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "secretfrob",
|
||||
Hidden: true,
|
||||
Action: func(ctx *Context) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
output := &bytes.Buffer{}
|
||||
app.Writer = output
|
||||
app.Run([]string{"app", "--help"})
|
||||
|
||||
if strings.Contains(output.String(), "secretfrob") {
|
||||
t.Errorf("expected output to exclude \"secretfrob\"; got: %q", output.String())
|
||||
}
|
||||
|
||||
if !strings.Contains(output.String(), "frobbly") {
|
||||
t.Errorf("expected output to include \"frobbly\"; got: %q", output.String())
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
wd, _ = os.Getwd()
|
||||
)
|
||||
|
||||
func expect(t *testing.T, a interface{}, b interface{}) {
|
||||
_, fn, line, _ := runtime.Caller(1)
|
||||
fn = strings.Replace(fn, wd+"/", "", -1)
|
||||
|
||||
if !reflect.DeepEqual(a, b) {
|
||||
t.Errorf("(%s:%d) Expected %v (type %v) - Got %v (type %v)", fn, line, b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||
}
|
||||
}
|
||||
|
||||
func refute(t *testing.T, a interface{}, b interface{}) {
|
||||
if reflect.DeepEqual(a, b) {
|
||||
t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
||||
package cli
|
||||
|
||||
import "os"
|
||||
|
||||
func clearenv() {
|
||||
os.Clearenv()
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// os.Clearenv() doesn't actually unset variables on Windows
|
||||
// See: https://github.com/golang/go/issues/17902
|
||||
func clearenv() {
|
||||
for _, s := range os.Environ() {
|
||||
for j := 1; j < len(s); j++ {
|
||||
if s[j] == '=' {
|
||||
keyp, _ := syscall.UTF16PtrFromString(s[0:j])
|
||||
syscall.SetEnvironmentVariable(keyp, nil)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from subprocess import check_call, check_output
|
||||
|
||||
|
||||
PACKAGE_NAME = os.environ.get(
|
||||
'CLI_PACKAGE_NAME', 'github.com/urfave/cli'
|
||||
)
|
||||
|
||||
|
||||
def main(sysargs=sys.argv[:]):
|
||||
targets = {
|
||||
'vet': _vet,
|
||||
'test': _test,
|
||||
'gfmrun': _gfmrun,
|
||||
'toc': _toc,
|
||||
'gen': _gen,
|
||||
}
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'target', nargs='?', choices=tuple(targets.keys()), default='test'
|
||||
)
|
||||
args = parser.parse_args(sysargs[1:])
|
||||
|
||||
targets[args.target]()
|
||||
return 0
|
||||
|
||||
|
||||
def _test():
|
||||
if check_output('go version'.split()).split()[2] < 'go1.2':
|
||||
_run('go test -v .')
|
||||
return
|
||||
|
||||
coverprofiles = []
|
||||
for subpackage in ['', 'altsrc']:
|
||||
coverprofile = 'cli.coverprofile'
|
||||
if subpackage != '':
|
||||
coverprofile = '{}.coverprofile'.format(subpackage)
|
||||
|
||||
coverprofiles.append(coverprofile)
|
||||
|
||||
_run('go test -v'.split() + [
|
||||
'-coverprofile={}'.format(coverprofile),
|
||||
('{}/{}'.format(PACKAGE_NAME, subpackage)).rstrip('/')
|
||||
])
|
||||
|
||||
combined_name = _combine_coverprofiles(coverprofiles)
|
||||
_run('go tool cover -func={}'.format(combined_name))
|
||||
os.remove(combined_name)
|
||||
|
||||
|
||||
def _gfmrun():
|
||||
go_version = check_output('go version'.split()).split()[2]
|
||||
if go_version < 'go1.3':
|
||||
print('runtests: skip on {}'.format(go_version), file=sys.stderr)
|
||||
return
|
||||
_run(['gfmrun', '-c', str(_gfmrun_count()), '-s', 'README.md'])
|
||||
|
||||
|
||||
def _vet():
|
||||
_run('go vet ./...')
|
||||
|
||||
|
||||
def _toc():
|
||||
_run('node_modules/.bin/markdown-toc -i README.md')
|
||||
_run('git diff --exit-code')
|
||||
|
||||
|
||||
def _gen():
|
||||
go_version = check_output('go version'.split()).split()[2]
|
||||
if go_version < 'go1.5':
|
||||
print('runtests: skip on {}'.format(go_version), file=sys.stderr)
|
||||
return
|
||||
|
||||
_run('go generate ./...')
|
||||
_run('git diff --exit-code')
|
||||
|
||||
|
||||
def _run(command):
|
||||
if hasattr(command, 'split'):
|
||||
command = command.split()
|
||||
print('runtests: {}'.format(' '.join(command)), file=sys.stderr)
|
||||
check_call(command)
|
||||
|
||||
|
||||
def _gfmrun_count():
|
||||
with open('README.md') as infile:
|
||||
lines = infile.read().splitlines()
|
||||
return len(filter(_is_go_runnable, lines))
|
||||
|
||||
|
||||
def _is_go_runnable(line):
|
||||
return line.startswith('package main')
|
||||
|
||||
|
||||
def _combine_coverprofiles(coverprofiles):
|
||||
combined = tempfile.NamedTemporaryFile(
|
||||
suffix='.coverprofile', delete=False
|
||||
)
|
||||
combined.write('mode: set\n')
|
||||
|
||||
for coverprofile in coverprofiles:
|
||||
with open(coverprofile, 'r') as infile:
|
||||
for line in infile.readlines():
|
||||
if not line.startswith('mode: '):
|
||||
combined.write(line)
|
||||
|
||||
combined.flush()
|
||||
name = combined.name
|
||||
combined.close()
|
||||
return name
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -0,0 +1,19 @@
|
||||
{
|
||||
"comment": "",
|
||||
"ignore": "",
|
||||
"package": [
|
||||
{
|
||||
"checksumSHA1": "j+7FNCvlU+kWXWywAGJK+lG2NmY=",
|
||||
"path": "github.com/bmatcuk/doublestar",
|
||||
"revision": "dd6a6f0a8cdfaaa88b08cf26cf1bc7d69003ee13",
|
||||
"revisionTime": "2016-09-23T20:37:36Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "3+RMLD39TCF3btCAoW8o6s6xNlo=",
|
||||
"path": "github.com/urfave/cli",
|
||||
"revision": "420da9fff3724cc19afe25bef61aeabd5b81e9f7",
|
||||
"revisionTime": "2017-04-10T14:45:51Z"
|
||||
}
|
||||
],
|
||||
"rootPath": "github.com/bradrydzewski/togo"
|
||||
}
|
Loading…
Reference in New Issue