chore(cli): upgrade urfave/cli to v2 version (#85)

chore(cli): upgrade urfave/cli to v2 version

Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
appleboy 2020-01-04 17:44:25 +00:00 committed by Andrew Thornton
parent 0a5cdd60ac
commit c20d7d45aa
57 changed files with 2151 additions and 1776 deletions

View File

@ -7,7 +7,7 @@ package cmd
import ( import (
"log" "log"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
// create global variables for global Flags to simplify // create global variables for global Flags to simplify
@ -52,8 +52,8 @@ var OutputFlag = cli.StringFlag{
// subcommand to work around issue and provide --login and --output: // subcommand to work around issue and provide --login and --output:
// https://github.com/urfave/cli/issues/585 // https://github.com/urfave/cli/issues/585
var LoginOutputFlags = []cli.Flag{ var LoginOutputFlags = []cli.Flag{
LoginFlag, &LoginFlag,
OutputFlag, &OutputFlag,
} }
// LoginRepoFlags defines login and repo flags that should // LoginRepoFlags defines login and repo flags that should
@ -61,9 +61,9 @@ var LoginOutputFlags = []cli.Flag{
// the subcommand to work around issue and provide --login and --repo: // the subcommand to work around issue and provide --login and --repo:
// https://github.com/urfave/cli/issues/585 // https://github.com/urfave/cli/issues/585
var LoginRepoFlags = []cli.Flag{ var LoginRepoFlags = []cli.Flag{
LoginFlag, &LoginFlag,
RepoFlag, &RepoFlag,
RemoteFlag, &RemoteFlag,
} }
// AllDefaultFlags defines flags that should be available // AllDefaultFlags defines flags that should be available
@ -71,8 +71,8 @@ var LoginRepoFlags = []cli.Flag{
// to work around issue and provide --login, --repo and --output: // to work around issue and provide --login, --repo and --output:
// https://github.com/urfave/cli/issues/585 // https://github.com/urfave/cli/issues/585
var AllDefaultFlags = append([]cli.Flag{ var AllDefaultFlags = append([]cli.Flag{
RepoFlag, &RepoFlag,
RemoteFlag, &RemoteFlag,
}, LoginOutputFlags...) }, LoginOutputFlags...)
// initCommand returns repository and *Login based on flags // initCommand returns repository and *Login based on flags

View File

@ -13,7 +13,7 @@ import (
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
// CmdIssues represents to login a gitea server. // CmdIssues represents to login a gitea server.
@ -22,9 +22,9 @@ var CmdIssues = cli.Command{
Usage: "List and create issues", Usage: "List and create issues",
Description: `List and create issues`, Description: `List and create issues`,
Action: runIssues, Action: runIssues,
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
CmdIssuesList, &CmdIssuesList,
CmdIssuesCreate, &CmdIssuesCreate,
}, },
Flags: AllDefaultFlags, Flags: AllDefaultFlags,
} }
@ -124,11 +124,11 @@ var CmdIssuesCreate = cli.Command{
Description: `Create an issue on repository`, Description: `Create an issue on repository`,
Action: runIssuesCreate, Action: runIssuesCreate,
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
cli.StringFlag{ &cli.StringFlag{
Name: "title, t", Name: "title, t",
Usage: "issue title to create", Usage: "issue title to create",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "body, b", Name: "body, b",
Usage: "issue body to create", Usage: "issue body to create",
}, },

View File

@ -14,7 +14,7 @@ import (
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
// CmdLabels represents to operate repositories' labels. // CmdLabels represents to operate repositories' labels.
@ -23,13 +23,13 @@ var CmdLabels = cli.Command{
Usage: "Manage issue labels", Usage: "Manage issue labels",
Description: `Manage issue labels`, Description: `Manage issue labels`,
Action: runLabels, Action: runLabels,
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
CmdLabelCreate, &CmdLabelCreate,
CmdLabelUpdate, &CmdLabelUpdate,
CmdLabelDelete, &CmdLabelDelete,
}, },
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
cli.StringFlag{ &cli.StringFlag{
Name: "save, s", Name: "save, s",
Usage: "Save all the labels as a file", Usage: "Save all the labels as a file",
}, },
@ -94,19 +94,19 @@ var CmdLabelCreate = cli.Command{
Description: `Create a label`, Description: `Create a label`,
Action: runLabelCreate, Action: runLabelCreate,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ &cli.StringFlag{
Name: "name", Name: "name",
Usage: "label name", Usage: "label name",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "color", Name: "color",
Usage: "label color value", Usage: "label color value",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "description", Name: "description",
Usage: "label description", Usage: "label description",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "file", Name: "file",
Usage: "indicate a label file", Usage: "indicate a label file",
}, },
@ -186,19 +186,19 @@ var CmdLabelUpdate = cli.Command{
Description: `Update a label`, Description: `Update a label`,
Action: runLabelUpdate, Action: runLabelUpdate,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.IntFlag{ &cli.IntFlag{
Name: "id", Name: "id",
Usage: "label id", Usage: "label id",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "name", Name: "name",
Usage: "label name", Usage: "label name",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "color", Name: "color",
Usage: "label color value", Usage: "label color value",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "description", Name: "description",
Usage: "label description", Usage: "label description",
}, },
@ -246,7 +246,7 @@ var CmdLabelDelete = cli.Command{
Description: `Delete a label`, Description: `Delete a label`,
Action: runLabelCreate, Action: runLabelCreate,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.IntFlag{ &cli.IntFlag{
Name: "id", Name: "id",
Usage: "label id", Usage: "label id",
}, },

View File

@ -13,7 +13,7 @@ import (
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
// CmdLogin represents to login a gitea server. // CmdLogin represents to login a gitea server.
@ -21,9 +21,9 @@ var CmdLogin = cli.Command{
Name: "login", Name: "login",
Usage: "Log in to a Gitea server", Usage: "Log in to a Gitea server",
Description: `Log in to a Gitea server`, Description: `Log in to a Gitea server`,
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
cmdLoginList, &cmdLoginList,
cmdLoginAdd, &cmdLoginAdd,
}, },
} }
@ -33,23 +33,23 @@ var cmdLoginAdd = cli.Command{
Usage: "Add a Gitea login", Usage: "Add a Gitea login",
Description: `Add a Gitea login`, Description: `Add a Gitea login`,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ &cli.StringFlag{
Name: "name, n", Name: "name, n",
Usage: "Login name", Usage: "Login name",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "url, u", Name: "url, u",
Value: "https://try.gitea.io", Value: "https://try.gitea.io",
EnvVar: "GITEA_SERVER_URL", EnvVars: []string{"GITEA_SERVER_URL"},
Usage: "Server URL", Usage: "Server URL",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "token, t", Name: "token, t",
Value: "", Value: "",
EnvVar: "GITEA_SERVER_TOKEN", EnvVars: []string{"GITEA_SERVER_TOKEN"},
Usage: "Access token. Can be obtained from Settings > Applications", Usage: "Access token. Can be obtained from Settings > Applications",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "insecure, i", Name: "insecure, i",
Usage: "Disable TLS verification", Usage: "Disable TLS verification",
}, },

View File

@ -9,7 +9,7 @@ import (
"log" "log"
"os" "os"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
// CmdLogout represents to logout a gitea server. // CmdLogout represents to logout a gitea server.
@ -19,7 +19,7 @@ var CmdLogout = cli.Command{
Description: `Log out from a Gitea server`, Description: `Log out from a Gitea server`,
Action: runLogout, Action: runLogout,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ &cli.StringFlag{
Name: "name, n", Name: "name, n",
Usage: "Login name to remove", Usage: "Login name to remove",
}, },

View File

@ -10,7 +10,7 @@ import (
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
// CmdPulls represents to login a gitea server. // CmdPulls represents to login a gitea server.

View File

@ -11,7 +11,7 @@ import (
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
// CmdReleases represents to login a gitea server. // CmdReleases represents to login a gitea server.
@ -20,8 +20,8 @@ var CmdReleases = cli.Command{
Usage: "Create releases", Usage: "Create releases",
Description: `Create releases`, Description: `Create releases`,
Action: runReleases, Action: runReleases,
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
CmdReleaseCreate, &CmdReleaseCreate,
}, },
Flags: AllDefaultFlags, Flags: AllDefaultFlags,
} }
@ -71,31 +71,31 @@ var CmdReleaseCreate = cli.Command{
Description: `Create a release`, Description: `Create a release`,
Action: runReleaseCreate, Action: runReleaseCreate,
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
cli.StringFlag{ &cli.StringFlag{
Name: "tag", Name: "tag",
Usage: "Tag name", Usage: "Tag name",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "target", Name: "target",
Usage: "Target refs, branch name or commit id", Usage: "Target refs, branch name or commit id",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "title, t", Name: "title, t",
Usage: "Release title", Usage: "Release title",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "note, n", Name: "note, n",
Usage: "Release notes", Usage: "Release notes",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "draft, d", Name: "draft, d",
Usage: "Is a draft", Usage: "Is a draft",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "prerelease, p", Name: "prerelease, p",
Usage: "Is a pre-release", Usage: "Is a pre-release",
}, },
cli.StringSliceFlag{ &cli.StringSliceFlag{
Name: "asset, a", Name: "asset, a",
Usage: "List of files to attach", Usage: "List of files to attach",
}, },

View File

@ -9,7 +9,7 @@ import (
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
// CmdRepos represents to login a gitea server. // CmdRepos represents to login a gitea server.
@ -18,8 +18,8 @@ var CmdRepos = cli.Command{
Usage: "Operate with repositories", Usage: "Operate with repositories",
Description: `Operate with repositories`, Description: `Operate with repositories`,
Action: runReposList, Action: runReposList,
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
CmdReposList, &CmdReposList,
}, },
Flags: LoginOutputFlags, Flags: LoginOutputFlags,
} }
@ -31,15 +31,15 @@ var CmdReposList = cli.Command{
Description: `List available repositories`, Description: `List available repositories`,
Action: runReposList, Action: runReposList,
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
cli.StringFlag{ &cli.StringFlag{
Name: "mode", Name: "mode",
Usage: "Filter listed repositories based on mode, optional - fork, mirror, source", Usage: "Filter listed repositories based on mode, optional - fork, mirror, source",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "org", Name: "org",
Usage: "Filter listed repositories based on organization, optional", Usage: "Filter listed repositories based on organization, optional",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "user", Name: "user",
Usage: "Filter listed repositories absed on user, optional", Usage: "Filter listed repositories absed on user, optional",
}, },

2
go.mod
View File

@ -9,7 +9,7 @@ require (
github.com/mattn/go-runewidth v0.0.4 // indirect github.com/mattn/go-runewidth v0.0.4 // indirect
github.com/olekukonko/tablewriter v0.0.1 github.com/olekukonko/tablewriter v0.0.1
github.com/stretchr/testify v1.4.0 github.com/stretchr/testify v1.4.0
github.com/urfave/cli v1.22.2 github.com/urfave/cli/v2 v2.1.1
gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/src-d/go-git.v4 v4.13.1
gopkg.in/yaml.v2 v2.2.7 // indirect gopkg.in/yaml.v2 v2.2.7 // indirect
) )

4
go.sum
View File

@ -62,8 +62,8 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=

18
main.go
View File

@ -13,7 +13,7 @@ import (
"code.gitea.io/tea/cmd" "code.gitea.io/tea/cmd"
"code.gitea.io/tea/modules/setting" "code.gitea.io/tea/modules/setting"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
// Version holds the current Gitea version // Version holds the current Gitea version
@ -33,14 +33,14 @@ func main() {
app.Usage = "Command line tool to interact with Gitea" app.Usage = "Command line tool to interact with Gitea"
app.Description = `` app.Description = ``
app.Version = Version + formatBuiltWith(Tags) app.Version = Version + formatBuiltWith(Tags)
app.Commands = []cli.Command{ app.Commands = []*cli.Command{
cmd.CmdLogin, &cmd.CmdLogin,
cmd.CmdLogout, &cmd.CmdLogout,
cmd.CmdIssues, &cmd.CmdIssues,
cmd.CmdPulls, &cmd.CmdPulls,
cmd.CmdReleases, &cmd.CmdReleases,
cmd.CmdRepos, &cmd.CmdRepos,
cmd.CmdLabels, &cmd.CmdLabels,
} }
app.EnableBashCompletion = true app.EnableBashCompletion = true
err := app.Run(os.Args) err := app.Run(os.Args)

View File

@ -1,35 +0,0 @@
language: go
sudo: false
dist: bionic
osx_image: xcode10
go:
- 1.11.x
- 1.12.x
- 1.13.x
os:
- linux
- osx
env:
GO111MODULE=on
GOPROXY=https://proxy.golang.org
cache:
directories:
- node_modules
before_script:
- go get github.com/urfave/gfmrun/cmd/gfmrun
- go get golang.org/x/tools/cmd/goimports
- npm install markdown-toc
- go mod tidy
script:
- go run build.go vet
- go run build.go test
- go run build.go gfmrun docs/v1/manual.md
- go run build.go toc docs/v1/manual.md
after_success:
- bash <(curl -s https://codecov.io/bash)

View File

@ -1,44 +0,0 @@
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 lexicographicLess(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
}

View File

@ -1,339 +0,0 @@
package cli
import (
"errors"
"flag"
"fmt"
"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 {
c.setFlags = nil
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 {
globalContext(c).setFlags = nil
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 available.
//
// 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 _, f := range c.Command.Flags {
name := strings.Split(f.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 _, f := range c.App.Flags {
name := strings.Split(f.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
}
type requiredFlagsErr interface {
error
getMissingFlags() []string
}
type errRequiredFlags struct {
missingFlags []string
}
func (e *errRequiredFlags) Error() string {
numberOfMissingFlags := len(e.missingFlags)
if numberOfMissingFlags == 1 {
return fmt.Sprintf("Required flag %q not set", e.missingFlags[0])
}
joinedMissingFlags := strings.Join(e.missingFlags, ", ")
return fmt.Sprintf("Required flags %q not set", joinedMissingFlags)
}
func (e *errRequiredFlags) getMissingFlags() []string {
return e.missingFlags
}
func checkRequiredFlags(flags []Flag, context *Context) requiredFlagsErr {
var missingFlags []string
for _, f := range flags {
if rf, ok := f.(RequiredFlag); ok && rf.IsRequired() {
var flagPresent bool
var flagName string
for _, key := range strings.Split(f.GetName(), ",") {
if len(key) > 1 {
flagName = key
}
if context.IsSet(strings.TrimSpace(key)) {
flagPresent = true
}
}
if !flagPresent && flagName != "" {
missingFlags = append(missingFlags, flagName)
}
}
}
if len(missingFlags) != 0 {
return &errRequiredFlags{missingFlags: missingFlags}
}
return nil
}

View File

@ -1,110 +0,0 @@
package cli
import (
"flag"
"fmt"
"strconv"
)
// BoolTFlag is a flag with type bool that is true by default
type BoolTFlag struct {
Name string
Usage string
EnvVar string
FilePath string
Required bool
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
}
// IsRequired returns whether or not the flag is required
func (f BoolTFlag) IsRequired() bool {
return f.Required
}
// TakesValue returns true of the flag takes a value, otherwise false
func (f BoolTFlag) TakesValue() bool {
return false
}
// GetUsage returns the usage string for the flag
func (f BoolTFlag) GetUsage() string {
return f.Usage
}
// GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all.
func (f BoolTFlag) GetValue() string {
return ""
}
// 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
}
// 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
}
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
}

View File

@ -1,141 +0,0 @@
package cli
import (
"flag"
"fmt"
"strconv"
"strings"
)
// 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
}
// Int64SliceFlag is a flag with type *Int64Slice
type Int64SliceFlag struct {
Name string
Usage string
EnvVar string
FilePath string
Required bool
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
}
// IsRequired returns whether or not the flag is required
func (f Int64SliceFlag) IsRequired() bool {
return f.Required
}
// TakesValue returns true of the flag takes a value, otherwise false
func (f Int64SliceFlag) TakesValue() bool {
return true
}
// GetUsage returns the usage string for the flag
func (f Int64SliceFlag) GetUsage() string {
return f.Usage
}
// GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all.
func (f Int64SliceFlag) GetValue() string {
if f.Value != nil {
return f.Value.String()
}
return ""
}
// 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)
}
}
if f.Value == nil {
f.Value = newVal
} else {
*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
}
// 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
}

View File

@ -1,142 +0,0 @@
package cli
import (
"flag"
"fmt"
"strconv"
"strings"
)
// 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
}
// IntSliceFlag is a flag with type *IntSlice
type IntSliceFlag struct {
Name string
Usage string
EnvVar string
FilePath string
Required bool
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
}
// IsRequired returns whether or not the flag is required
func (f IntSliceFlag) IsRequired() bool {
return f.Required
}
// TakesValue returns true of the flag takes a value, otherwise false
func (f IntSliceFlag) TakesValue() bool {
return true
}
// GetUsage returns the usage string for the flag
func (f IntSliceFlag) GetUsage() string {
return f.Usage
}
// GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all.
func (f IntSliceFlag) GetValue() string {
if f.Value != nil {
return f.Value.String()
}
return ""
}
// 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)
}
}
if f.Value == nil {
f.Value = newVal
} else {
*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
}
// 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
}

View File

@ -1,138 +0,0 @@
package cli
import (
"flag"
"fmt"
"strings"
)
// 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
}
// StringSliceFlag is a flag with type *StringSlice
type StringSliceFlag struct {
Name string
Usage string
EnvVar string
FilePath string
Required bool
Hidden bool
TakesFile 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
}
// IsRequired returns whether or not the flag is required
func (f StringSliceFlag) IsRequired() bool {
return f.Required
}
// TakesValue returns true of the flag takes a value, otherwise false
func (f StringSliceFlag) TakesValue() bool {
return true
}
// GetUsage returns the usage string for the flag
func (f StringSliceFlag) GetUsage() string {
return f.Usage
}
// GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all.
func (f StringSliceFlag) GetValue() string {
if f.Value != nil {
return f.Value.String()
}
return ""
}
// 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)
}
}
if f.Value == nil {
f.Value = newVal
} else {
*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
}
// 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
}

View File

@ -1,3 +1,5 @@
*.coverprofile *.coverprofile
*.orig
node_modules/ node_modules/
vendor vendor
.idea

View File

@ -1,7 +1,6 @@
cli cli
=== ===
[![Build Status](https://travis-ci.org/urfave/cli.svg?branch=master)](https://travis-ci.org/urfave/cli)
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/rtgk5xufi932pb2v?svg=true)](https://ci.appveyor.com/project/urfave/cli) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/rtgk5xufi932pb2v?svg=true)](https://ci.appveyor.com/project/urfave/cli)
[![GoDoc](https://godoc.org/github.com/urfave/cli?status.svg)](https://godoc.org/github.com/urfave/cli) [![GoDoc](https://godoc.org/github.com/urfave/cli?status.svg)](https://godoc.org/github.com/urfave/cli)
@ -15,15 +14,44 @@ applications in an expressive way.
## Usage Documentation ## Usage Documentation
Usage documentation exists for each major version Usage documentation exists for each major version. Don't know what version you're on? You're probably using the version from the `master` branch, which is currently `v2`.
- `v2` - [./docs/v2/manual.md](./docs/v2/manual.md)
- `v1` - [./docs/v1/manual.md](./docs/v1/manual.md) - `v1` - [./docs/v1/manual.md](./docs/v1/manual.md)
- `v2` - 🚧 documentation for `v2` is WIP 🚧
## Installation ## Installation
Make sure you have a working Go environment. Go version 1.10+ is supported. [See Make sure you have a working Go environment. Go version 1.11+ is supported. [See the install instructions for Go](http://golang.org/doc/install.html).
the install instructions for Go](http://golang.org/doc/install.html).
Go Modules are strongly recommended when using this package. [See the go blog guide on using Go Modules](https://blog.golang.org/using-go-modules).
### Using `v2` releases
```
$ GO111MODULE=on go get github.com/urfave/cli/v2
```
```go
...
import (
"github.com/urfave/cli/v2" // imports as package "cli"
)
...
```
### Using `v1` releases
```
$ GO111MODULE=on go get github.com/urfave/cli
```
```go
...
import (
"github.com/urfave/cli"
)
...
```
### GOPATH ### GOPATH
@ -36,35 +64,5 @@ export PATH=$PATH:$GOPATH/bin
### Supported platforms ### Supported platforms
cli is tested against multiple versions of Go on Linux, and against the latest cli is tested against multiple versions of Go on Linux, and against the latest
released version of Go on OS X and Windows. For full details, see released version of Go on OS X and Windows. This project uses Github Actions for
[`./.travis.yml`](./.travis.yml) and [`./appveyor.yml`](./appveyor.yml). builds. For more build info, please look at the [./.github/workflows/cli.yml](https://github.com/urfave/cli/blob/master/.github/workflows/cli.yml).
### Using `v1` releases
```
$ go get github.com/urfave/cli
```
```go
...
import (
"github.com/urfave/cli"
)
...
```
### Using `v2` releases
**Warning**: `v2` is in a pre-release state.
```
$ go get github.com/urfave/cli.v2
```
```go
...
import (
"github.com/urfave/cli.v2" // imports as package "cli"
)
...
```

View File

@ -1,23 +1,21 @@
package cli package cli
import ( import (
"context"
"flag" "flag"
"fmt" "fmt"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"sort" "sort"
"time" "time"
) )
var ( var (
changeLogURL = "https://github.com/urfave/cli/blob/master/CHANGELOG.md" changeLogURL = "https://github.com/urfave/cli/blob/master/docs/CHANGELOG.md"
appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL) appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL)
// unused variable. commented for now. will remove in future if agreed upon by everyone
//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." 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. "+ errInvalidActionType = NewExitError("ERROR invalid Action type. "+
fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+ fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+
fmt.Sprintf("See %s", appActionDeprecationURL), 2) fmt.Sprintf("See %s", appActionDeprecationURL), 2)
@ -41,7 +39,7 @@ type App struct {
// Description of the program // Description of the program
Description string Description string
// List of commands to execute // List of commands to execute
Commands []Command Commands []*Command
// List of flags to parse // List of flags to parse
Flags []Flag Flags []Flag
// Boolean to enable bash completion commands // Boolean to enable bash completion commands
@ -50,9 +48,9 @@ type App struct {
HideHelp bool HideHelp bool
// Boolean to hide built-in version flag and the VERSION section of help // Boolean to hide built-in version flag and the VERSION section of help
HideVersion bool HideVersion bool
// Populate on app startup, only gettable through method Categories() // categories contains the categorized commands and is populated on app startup
categories CommandCategories categories CommandCategories
// An action to execute when the bash-completion flag is set // An action to execute when the shell completion flag is set
BashComplete BashCompleteFunc BashComplete BashCompleteFunc
// An action to execute before any subcommands are run, but after the context is ready // 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 // If a non-nil error is returned, no subcommands are run
@ -60,12 +58,8 @@ type App struct {
// An action to execute after any subcommands are run, but after the subcommand has finished // An action to execute after any subcommands are run, but after the subcommand has finished
// It is run even if Action() panics // It is run even if Action() panics
After AfterFunc After AfterFunc
// The action to execute when no subcommands are specified // The action to execute when no subcommands are specified
// Expects a `cli.ActionFunc` but will accept the *deprecated* signature of `func(*cli.Context) {}` Action ActionFunc
// *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 // Execute this function if the proper command cannot be found
CommandNotFound CommandNotFoundFunc CommandNotFound CommandNotFoundFunc
// Execute this function if an usage error occurs // Execute this function if an usage error occurs
@ -73,13 +67,9 @@ type App struct {
// Compilation date // Compilation date
Compiled time.Time Compiled time.Time
// List of all authors who contributed // List of all authors who contributed
Authors []Author Authors []*Author
// Copyright of the binary if any // Copyright of the binary if any
Copyright string 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 writer to write output to
Writer io.Writer Writer io.Writer
// ErrWriter writes error output // ErrWriter writes error output
@ -96,7 +86,7 @@ type App struct {
// render custom help text by setting this variable. // render custom help text by setting this variable.
CustomAppHelpTemplate string CustomAppHelpTemplate string
// Boolean to enable short-option handling so user can combine several // Boolean to enable short-option handling so user can combine several
// single-character bool arguements into one // single-character bool arguments into one
// i.e. foobar -o -v -> foobar -ov // i.e. foobar -o -v -> foobar -ov
UseShortOptionHandling bool UseShortOptionHandling bool
@ -121,7 +111,6 @@ func NewApp() *App {
HelpName: filepath.Base(os.Args[0]), HelpName: filepath.Base(os.Args[0]),
Usage: "A new cli application", Usage: "A new cli application",
UsageText: "", UsageText: "",
Version: "0.0.0",
BashComplete: DefaultAppComplete, BashComplete: DefaultAppComplete,
Action: helpCommand.Action, Action: helpCommand.Action,
Compiled: compileTime(), Compiled: compileTime(),
@ -139,22 +128,52 @@ func (a *App) Setup() {
a.didSetup = true a.didSetup = true
if a.Author != "" || a.Email != "" { if a.Name == "" {
a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email}) a.Name = filepath.Base(os.Args[0])
} }
var newCmds []Command if a.HelpName == "" {
a.HelpName = filepath.Base(os.Args[0])
}
if a.Usage == "" {
a.Usage = "A new cli application"
}
if a.Version == "" {
a.HideVersion = true
}
if a.BashComplete == nil {
a.BashComplete = DefaultAppComplete
}
if a.Action == nil {
a.Action = helpCommand.Action
}
if a.Compiled == (time.Time{}) {
a.Compiled = compileTime()
}
if a.Writer == nil {
a.Writer = os.Stdout
}
var newCommands []*Command
for _, c := range a.Commands { for _, c := range a.Commands {
if c.HelpName == "" { if c.HelpName == "" {
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
} }
newCmds = append(newCmds, c) newCommands = append(newCommands, c)
} }
a.Commands = newCmds a.Commands = newCommands
if a.Command(helpCommand.Name) == nil && !a.HideHelp { if a.Command(helpCommand.Name) == nil && !a.HideHelp {
a.Commands = append(a.Commands, helpCommand) a.appendCommand(helpCommand)
if (HelpFlag != BoolFlag{}) {
if HelpFlag != nil {
a.appendFlag(HelpFlag) a.appendFlag(HelpFlag)
} }
} }
@ -163,11 +182,11 @@ func (a *App) Setup() {
a.appendFlag(VersionFlag) a.appendFlag(VersionFlag)
} }
a.categories = CommandCategories{} a.categories = newCommandCategories()
for _, command := range a.Commands { for _, command := range a.Commands {
a.categories = a.categories.AddCommand(command.Category, command) a.categories.AddCommand(command.Category, command)
} }
sort.Sort(a.categories) sort.Sort(a.categories.(*commandCategories))
if a.Metadata == nil { if a.Metadata == nil {
a.Metadata = make(map[string]interface{}) a.Metadata = make(map[string]interface{})
@ -189,6 +208,13 @@ func (a *App) useShortOptionHandling() bool {
// Run is the entry point to the cli app. Parses the arguments slice and routes // Run is the entry point to the cli app. Parses the arguments slice and routes
// to the proper flag/args combination // to the proper flag/args combination
func (a *App) Run(arguments []string) (err error) { func (a *App) Run(arguments []string) (err error) {
return a.RunContext(context.Background(), arguments)
}
// RunContext is like Run except it takes a Context that will be
// passed to its commands and sub-commands. Through this, you can
// propagate timeouts and cancellation requests
func (a *App) RunContext(ctx context.Context, arguments []string) (err error) {
a.Setup() a.Setup()
// handle the completion flag separately from the flagset since // handle the completion flag separately from the flagset since
@ -204,9 +230,9 @@ func (a *App) Run(arguments []string) (err error) {
return err return err
} }
err = parseIter(set, a, arguments[1:]) err = parseIter(set, a, arguments[1:], shellComplete)
nerr := normalizeFlags(a.Flags, set) nerr := normalizeFlags(a.Flags, set)
context := NewContext(a, set, nil) context := NewContext(a, set, &Context{Context: ctx})
if nerr != nil { if nerr != nil {
_, _ = fmt.Fprintln(a.Writer, nerr) _, _ = fmt.Fprintln(a.Writer, nerr)
_ = ShowAppHelp(context) _ = ShowAppHelp(context)
@ -249,7 +275,7 @@ func (a *App) Run(arguments []string) (err error) {
defer func() { defer func() {
if afterErr := a.After(context); afterErr != nil { if afterErr := a.After(context); afterErr != nil {
if err != nil { if err != nil {
err = NewMultiError(err, afterErr) err = newMultiError(err, afterErr)
} else { } else {
err = afterErr err = afterErr
} }
@ -282,7 +308,7 @@ func (a *App) Run(arguments []string) (err error) {
} }
// Run default Action // Run default Action
err = HandleAction(a.Action, context) err = a.Action(context)
a.handleExitCoder(context, err) a.handleExitCoder(context, err)
return err return err
@ -303,17 +329,20 @@ func (a *App) RunAndExitOnError() {
// RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to // RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to
// generate command-specific flags // generate command-specific flags
func (a *App) RunAsSubcommand(ctx *Context) (err error) { func (a *App) RunAsSubcommand(ctx *Context) (err error) {
a.Setup()
// append help to commands // append help to commands
if len(a.Commands) > 0 { if len(a.Commands) > 0 {
if a.Command(helpCommand.Name) == nil && !a.HideHelp { if a.Command(helpCommand.Name) == nil && !a.HideHelp {
a.Commands = append(a.Commands, helpCommand) a.appendCommand(helpCommand)
if (HelpFlag != BoolFlag{}) {
if HelpFlag != nil {
a.appendFlag(HelpFlag) a.appendFlag(HelpFlag)
} }
} }
} }
newCmds := []Command{} var newCmds []*Command
for _, c := range a.Commands { for _, c := range a.Commands {
if c.HelpName == "" { if c.HelpName == "" {
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
@ -327,7 +356,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
return err return err
} }
err = parseIter(set, a, ctx.Args().Tail()) err = parseIter(set, a, ctx.Args().Tail(), ctx.shellComplete)
nerr := normalizeFlags(a.Flags, set) nerr := normalizeFlags(a.Flags, set)
context := NewContext(a, set, ctx) context := NewContext(a, set, ctx)
@ -379,7 +408,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
if afterErr != nil { if afterErr != nil {
a.handleExitCoder(context, err) a.handleExitCoder(context, err)
if err != nil { if err != nil {
err = NewMultiError(err, afterErr) err = newMultiError(err, afterErr)
} else { } else {
err = afterErr err = afterErr
} }
@ -406,7 +435,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
} }
// Run default Action // Run default Action
err = HandleAction(a.Action, context) err = a.Action(context)
a.handleExitCoder(context, err) a.handleExitCoder(context, err)
return err return err
@ -416,29 +445,22 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
func (a *App) Command(name string) *Command { func (a *App) Command(name string) *Command {
for _, c := range a.Commands { for _, c := range a.Commands {
if c.HasName(name) { if c.HasName(name) {
return &c return c
} }
} }
return nil 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 // VisibleCategories returns a slice of categories and commands that are
// Hidden=false // Hidden=false
func (a *App) VisibleCategories() []*CommandCategory { func (a *App) VisibleCategories() []CommandCategory {
ret := []*CommandCategory{} ret := []CommandCategory{}
for _, category := range a.categories { for _, category := range a.categories.Categories() {
if visible := func() *CommandCategory { if visible := func() CommandCategory {
for _, command := range category.Commands { if len(category.VisibleCommands()) > 0 {
if !command.Hidden {
return category return category
} }
}
return nil return nil
}(); visible != nil { }(); visible != nil {
ret = append(ret, visible) ret = append(ret, visible)
@ -448,8 +470,8 @@ func (a *App) VisibleCategories() []*CommandCategory {
} }
// VisibleCommands returns a slice of the Commands with Hidden=false // VisibleCommands returns a slice of the Commands with Hidden=false
func (a *App) VisibleCommands() []Command { func (a *App) VisibleCommands() []*Command {
var ret []Command var ret []*Command
for _, command := range a.Commands { for _, command := range a.Commands {
if !command.Hidden { if !command.Hidden {
ret = append(ret, command) ret = append(ret, command)
@ -465,7 +487,7 @@ func (a *App) VisibleFlags() []Flag {
func (a *App) hasFlag(flag Flag) bool { func (a *App) hasFlag(flag Flag) bool {
for _, f := range a.Flags { for _, f := range a.Flags {
if flag == f { if reflect.DeepEqual(flag, f) {
return true return true
} }
} }
@ -482,9 +504,15 @@ func (a *App) errWriter() io.Writer {
return a.ErrWriter return a.ErrWriter
} }
func (a *App) appendFlag(flag Flag) { func (a *App) appendFlag(fl Flag) {
if !a.hasFlag(flag) { if !hasFlag(a.Flags, fl) {
a.Flags = append(a.Flags, flag) a.Flags = append(a.Flags, fl)
}
}
func (a *App) appendCommand(c *Command) {
if !hasCommand(a.Commands, c) {
a.Commands = append(a.Commands, c)
} }
} }
@ -503,7 +531,7 @@ type Author struct {
} }
// String makes Author comply to the Stringer interface, to allow an easy print in the templating process // String makes Author comply to the Stringer interface, to allow an easy print in the templating process
func (a Author) String() string { func (a *Author) String() string {
e := "" e := ""
if a.Email != "" { if a.Email != "" {
e = " <" + a.Email + ">" e = " <" + a.Email + ">"

View File

@ -20,7 +20,7 @@ install:
- go version - go version
- go env - go env
- go get github.com/urfave/gfmrun/cmd/gfmrun - go get github.com/urfave/gfmrun/cmd/gfmrun
- go mod vendor - go mod tidy
build_script: build_script:
- go run build.go vet - go run build.go vet

54
vendor/github.com/urfave/cli/v2/args.go generated vendored Normal file
View File

@ -0,0 +1,54 @@
package cli
type Args interface {
// Get returns the nth argument, or else a blank string
Get(n int) string
// First returns the first argument, or else a blank string
First() string
// Tail returns the rest of the arguments (not the first one)
// or else an empty string slice
Tail() []string
// Len returns the length of the wrapped slice
Len() int
// Present checks if there are any arguments present
Present() bool
// Slice returns a copy of the internal slice
Slice() []string
}
type args []string
func (a *args) Get(n int) string {
if len(*a) > n {
return (*a)[n]
}
return ""
}
func (a *args) First() string {
return a.Get(0)
}
func (a *args) Tail() []string {
if a.Len() >= 2 {
tail := []string((*a)[1:])
ret := make([]string, len(tail))
copy(ret, tail)
return ret
}
return []string{}
}
func (a *args) Len() int {
return len(*a)
}
func (a *args) Present() bool {
return a.Len() != 0
}
func (a *args) Slice() []string {
ret := make([]string, len(*a))
copy(ret, *a)
return ret
}

79
vendor/github.com/urfave/cli/v2/category.go generated vendored Normal file
View File

@ -0,0 +1,79 @@
package cli
// CommandCategories interface allows for category manipulation
type CommandCategories interface {
// AddCommand adds a command to a category, creating a new category if necessary.
AddCommand(category string, command *Command)
// categories returns a copy of the category slice
Categories() []CommandCategory
}
type commandCategories []*commandCategory
func newCommandCategories() CommandCategories {
ret := commandCategories([]*commandCategory{})
return &ret
}
func (c *commandCategories) Less(i, j int) bool {
return lexicographicLess((*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]
}
func (c *commandCategories) AddCommand(category string, command *Command) {
for _, commandCategory := range []*commandCategory(*c) {
if commandCategory.name == category {
commandCategory.commands = append(commandCategory.commands, command)
return
}
}
newVal := append(*c,
&commandCategory{name: category, commands: []*Command{command}})
*c = newVal
}
func (c *commandCategories) Categories() []CommandCategory {
ret := make([]CommandCategory, len(*c))
for i, cat := range *c {
ret[i] = cat
}
return ret
}
// CommandCategory is a category containing commands.
type CommandCategory interface {
// Name returns the category name string
Name() string
// VisibleCommands returns a slice of the Commands with Hidden=false
VisibleCommands() []*Command
}
type commandCategory struct {
name string
commands []*Command
}
func (c *commandCategory) Name() string {
return c.name
}
func (c *commandCategory) VisibleCommands() []*Command {
if c.commands == nil {
c.commands = []*Command{}
}
var ret []*Command
for _, command := range c.commands {
if !command.Hidden {
ret = append(ret, command)
}
}
return ret
}

View File

@ -2,17 +2,18 @@
// Go applications. cli is designed to be easy to understand and write, the most simple // Go applications. cli is designed to be easy to understand and write, the most simple
// cli application can be written as follows: // cli application can be written as follows:
// func main() { // func main() {
// cli.NewApp().Run(os.Args) // (&cli.App{}).Run(os.Args)
// } // }
// //
// Of course this application does not do much, so let's make this an actual application: // Of course this application does not do much, so let's make this an actual application:
// func main() { // func main() {
// app := cli.NewApp() // app := &cli.App{
// app.Name = "greet" // Name: "greet",
// app.Usage = "say a greeting" // Usage: "say a greeting",
// app.Action = func(c *cli.Context) error { // Action: func(c *cli.Context) error {
// println("Greetings") // fmt.Println("Greetings")
// return nil // return nil
// },
// } // }
// //
// app.Run(os.Args) // app.Run(os.Args)

View File

@ -11,8 +11,6 @@ import (
type Command struct { type Command struct {
// The name of the command // The name of the command
Name string Name string
// short name of the command. Typically one character (deprecated, use `Aliases`)
ShortName string
// A list of aliases for the command // A list of aliases for the command
Aliases []string Aliases []string
// A short description of the usage of this command // A short description of the usage of this command
@ -34,23 +32,15 @@ type Command struct {
// It is run even if Action() panics // It is run even if Action() panics
After AfterFunc After AfterFunc
// The function to call when this command is invoked // The function to call when this command is invoked
Action interface{} Action ActionFunc
// TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind
// of deprecation period has passed, maybe?
// Execute this function if a usage error occurs. // Execute this function if a usage error occurs.
OnUsageError OnUsageErrorFunc OnUsageError OnUsageErrorFunc
// List of child commands // List of child commands
Subcommands Commands Subcommands []*Command
// List of flags to parse // List of flags to parse
Flags []Flag Flags []Flag
// Treat all flags as normal arguments if true // Treat all flags as normal arguments if true
SkipFlagParsing bool 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 // Boolean to hide built-in help command
HideHelp bool HideHelp bool
// Boolean to hide this command from help or completion // Boolean to hide this command from help or completion
@ -70,7 +60,9 @@ type Command struct {
CustomHelpTemplate string CustomHelpTemplate string
} }
type CommandsByName []Command type Commands []*Command
type CommandsByName []*Command
func (c CommandsByName) Len() int { func (c CommandsByName) Len() int {
return len(c) return len(c)
@ -86,35 +78,29 @@ func (c CommandsByName) Swap(i, j int) {
// FullName returns the full name of the command. // FullName returns the full name of the command.
// For subcommands this ensures that parent commands are part of the command path // For subcommands this ensures that parent commands are part of the command path
func (c Command) FullName() string { func (c *Command) FullName() string {
if c.commandNamePath == nil { if c.commandNamePath == nil {
return c.Name return c.Name
} }
return strings.Join(c.commandNamePath, " ") 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 // Run invokes the command given the context, parses ctx.Args() to generate command-specific flags
func (c Command) Run(ctx *Context) (err error) { func (c *Command) Run(ctx *Context) (err error) {
if len(c.Subcommands) > 0 { if len(c.Subcommands) > 0 {
return c.startApp(ctx) return c.startApp(ctx)
} }
if !c.HideHelp && (HelpFlag != BoolFlag{}) { if !c.HideHelp && HelpFlag != nil {
// append help to flags // append help to flags
c.Flags = append( c.appendFlag(HelpFlag)
c.Flags,
HelpFlag,
)
} }
if ctx.App.UseShortOptionHandling { if ctx.App.UseShortOptionHandling {
c.UseShortOptionHandling = true c.UseShortOptionHandling = true
} }
set, err := c.parseFlags(ctx.Args().Tail()) set, err := c.parseFlags(ctx.Args(), ctx.shellComplete)
context := NewContext(ctx.App, set, ctx) context := NewContext(ctx.App, set, ctx)
context.Command = c context.Command = c
@ -124,7 +110,7 @@ func (c Command) Run(ctx *Context) (err error) {
if err != nil { if err != nil {
if c.OnUsageError != nil { if c.OnUsageError != nil {
err := c.OnUsageError(context, err, false) err = c.OnUsageError(context, err, false)
context.App.handleExitCoder(context, err) context.App.handleExitCoder(context, err)
return err return err
} }
@ -150,7 +136,7 @@ func (c Command) Run(ctx *Context) (err error) {
if afterErr != nil { if afterErr != nil {
context.App.handleExitCoder(context, err) context.App.handleExitCoder(context, err)
if err != nil { if err != nil {
err = NewMultiError(err, afterErr) err = newMultiError(err, afterErr)
} else { } else {
err = afterErr err = afterErr
} }
@ -171,7 +157,8 @@ func (c Command) Run(ctx *Context) (err error) {
c.Action = helpSubcommand.Action c.Action = helpSubcommand.Action
} }
err = HandleAction(c.Action, context) context.Command = c
err = c.Action(context)
if err != nil { if err != nil {
context.App.handleExitCoder(context, err) context.App.handleExitCoder(context, err)
@ -179,26 +166,25 @@ func (c Command) Run(ctx *Context) (err error) {
return err return err
} }
func (c *Command) parseFlags(args Args) (*flag.FlagSet, error) { func (c *Command) newFlagSet() (*flag.FlagSet, error) {
return flagSet(c.Name, c.Flags)
}
func (c *Command) useShortOptionHandling() bool {
return c.UseShortOptionHandling
}
func (c *Command) parseFlags(args Args, shellComplete bool) (*flag.FlagSet, error) {
set, err := c.newFlagSet()
if err != nil {
return nil, err
}
if c.SkipFlagParsing { if c.SkipFlagParsing {
set, err := c.newFlagSet() return set, set.Parse(append([]string{"--"}, args.Tail()...))
if err != nil {
return nil, err
} }
return set, set.Parse(append([]string{"--"}, args...)) err = parseIter(set, c, args.Tail(), shellComplete)
}
if !c.SkipArgReorder {
args = reorderArgs(c.Flags, args)
}
set, err := c.newFlagSet()
if err != nil {
return nil, err
}
err = parseIter(set, c, args)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -211,96 +197,13 @@ func (c *Command) parseFlags(args Args) (*flag.FlagSet, error) {
return set, nil return set, nil
} }
func (c *Command) newFlagSet() (*flag.FlagSet, error) {
return flagSet(c.Name, c.Flags)
}
func (c *Command) useShortOptionHandling() bool {
return c.UseShortOptionHandling
}
// reorderArgs moves all flags (via reorderedArgs) before the rest of
// the arguments (remainingArgs) as this is what flag expects.
func reorderArgs(commandFlags []Flag, args []string) []string {
var remainingArgs, reorderedArgs []string
nextIndexMayContainValue := false
for i, arg := range args {
// dont reorder any args after a --
// read about -- here:
// https://unix.stackexchange.com/questions/11376/what-does-double-dash-mean-also-known-as-bare-double-dash
if arg == "--" {
remainingArgs = append(remainingArgs, args[i:]...)
break
// checks if this arg is a value that should be re-ordered next to its associated flag
} else if nextIndexMayContainValue && !strings.HasPrefix(arg, "-") {
nextIndexMayContainValue = false
reorderedArgs = append(reorderedArgs, arg)
// checks if this is an arg that should be re-ordered
} else if argIsFlag(commandFlags, arg) {
// we have determined that this is a flag that we should re-order
reorderedArgs = append(reorderedArgs, arg)
// if this arg does not contain a "=", then the next index may contain the value for this flag
nextIndexMayContainValue = !strings.Contains(arg, "=")
// simply append any remaining args
} else {
remainingArgs = append(remainingArgs, arg)
}
}
return append(reorderedArgs, remainingArgs...)
}
// argIsFlag checks if an arg is one of our command flags
func argIsFlag(commandFlags []Flag, arg string) bool {
// checks if this is just a `-`, and so definitely not a flag
if arg == "-" {
return false
}
// flags always start with a -
if !strings.HasPrefix(arg, "-") {
return false
}
// this line turns `--flag` into `flag`
if strings.HasPrefix(arg, "--") {
arg = strings.Replace(arg, "-", "", 2)
}
// this line turns `-flag` into `flag`
if strings.HasPrefix(arg, "-") {
arg = strings.Replace(arg, "-", "", 1)
}
// this line turns `flag=value` into `flag`
arg = strings.Split(arg, "=")[0]
// look through all the flags, to see if the `arg` is one of our flags
for _, flag := range commandFlags {
for _, key := range strings.Split(flag.GetName(), ",") {
key := strings.TrimSpace(key)
if key == arg {
return true
}
}
}
// return false if this arg was not one of our flags
return false
}
// Names returns the names including short names and aliases. // Names returns the names including short names and aliases.
func (c Command) Names() []string { func (c *Command) Names() []string {
names := []string{c.Name} return append([]string{c.Name}, c.Aliases...)
if c.ShortName != "" {
names = append(names, c.ShortName)
} }
return append(names, c.Aliases...) // HasName returns true if Command.Name matches given name
} func (c *Command) HasName(name string) bool {
// HasName returns true if Command.Name or Command.ShortName matches given name
func (c Command) HasName(name string) bool {
for _, n := range c.Names() { for _, n := range c.Names() {
if n == name { if n == name {
return true return true
@ -309,12 +212,12 @@ func (c Command) HasName(name string) bool {
return false return false
} }
func (c Command) startApp(ctx *Context) error { func (c *Command) startApp(ctx *Context) error {
app := NewApp() app := &App{
app.Metadata = ctx.App.Metadata Metadata: ctx.App.Metadata,
app.ExitErrHandler = ctx.App.ExitErrHandler Name: fmt.Sprintf("%s %s", ctx.App.Name, c.Name),
// set the name and usage }
app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
if c.HelpName == "" { if c.HelpName == "" {
app.HelpName = c.HelpName app.HelpName = c.HelpName
} else { } else {
@ -337,18 +240,17 @@ func (c Command) startApp(ctx *Context) error {
app.Version = ctx.App.Version app.Version = ctx.App.Version
app.HideVersion = ctx.App.HideVersion app.HideVersion = ctx.App.HideVersion
app.Compiled = ctx.App.Compiled app.Compiled = ctx.App.Compiled
app.Author = ctx.App.Author
app.Email = ctx.App.Email
app.Writer = ctx.App.Writer app.Writer = ctx.App.Writer
app.ErrWriter = ctx.App.ErrWriter app.ErrWriter = ctx.App.ErrWriter
app.ExitErrHandler = ctx.App.ExitErrHandler
app.UseShortOptionHandling = ctx.App.UseShortOptionHandling app.UseShortOptionHandling = ctx.App.UseShortOptionHandling
app.categories = CommandCategories{} app.categories = newCommandCategories()
for _, command := range c.Subcommands { for _, command := range c.Subcommands {
app.categories = app.categories.AddCommand(command.Category, command) app.categories.AddCommand(command.Category, command)
} }
sort.Sort(app.categories) sort.Sort(app.categories.(*commandCategories))
// bash completion // bash completion
app.EnableBashCompletion = ctx.App.EnableBashCompletion app.EnableBashCompletion = ctx.App.EnableBashCompletion
@ -374,6 +276,22 @@ func (c Command) startApp(ctx *Context) error {
} }
// VisibleFlags returns a slice of the Flags with Hidden=false // VisibleFlags returns a slice of the Flags with Hidden=false
func (c Command) VisibleFlags() []Flag { func (c *Command) VisibleFlags() []Flag {
return visibleFlags(c.Flags) return visibleFlags(c.Flags)
} }
func (c *Command) appendFlag(fl Flag) {
if !hasFlag(c.Flags, fl) {
c.Flags = append(c.Flags, fl)
}
}
func hasCommand(commands []*Command, command *Command) bool {
for _, existing := range commands {
if command == existing {
return true
}
}
return false
}

274
vendor/github.com/urfave/cli/v2/context.go generated vendored Normal file
View File

@ -0,0 +1,274 @@
package cli
import (
"context"
"errors"
"flag"
"fmt"
"strings"
)
// 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 {
context.Context
App *App
Command *Command
shellComplete bool
setFlags map[string]bool
flagSet *flag.FlagSet
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.Context = parentCtx.Context
c.shellComplete = parentCtx.shellComplete
if parentCtx.flagSet == nil {
parentCtx.flagSet = &flag.FlagSet{}
}
}
c.Command = &Command{}
if c.Context == nil {
c.Context = context.Background()
}
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)
}
// IsSet determines if the flag was actually set
func (c *Context) IsSet(name string) bool {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := lookupFlagSet(name, c); fs != nil {
isSet := false
fs.Visit(func(f *flag.Flag) {
if f.Name == name {
isSet = true
}
})
if isSet {
return true
}
}
f := lookupFlag(name, c)
if f == nil {
return false
}
return f.IsSet()
}
return false
}
// LocalFlagNames returns a slice of flag names used in this context.
func (c *Context) LocalFlagNames() []string {
var names []string
c.flagSet.Visit(makeFlagNameVisitor(&names))
return names
}
// FlagNames returns a slice of flag names used by the this context and all of
// its parent contexts.
func (c *Context) FlagNames() []string {
var names []string
for _, ctx := range c.Lineage() {
ctx.flagSet.Visit(makeFlagNameVisitor(&names))
}
return names
}
// Lineage returns *this* context and all of its ancestor contexts in order from
// child to parent
func (c *Context) Lineage() []*Context {
var lineage []*Context
for cur := c; cur != nil; cur = cur.parentContext {
lineage = append(lineage, cur)
}
return lineage
}
// Value returns the value of the flag corresponding to `name`
func (c *Context) Value(name string) interface{} {
return c.flagSet.Lookup(name).Value.(flag.Getter).Get()
}
// Args returns the command line arguments associated with the context.
func (c *Context) Args() Args {
ret := args(c.flagSet.Args())
return &ret
}
// NArg returns the number of the command line arguments.
func (c *Context) NArg() int {
return c.Args().Len()
}
func lookupFlag(name string, ctx *Context) Flag {
for _, c := range ctx.Lineage() {
if c.Command == nil {
continue
}
for _, f := range c.Command.Flags {
for _, n := range f.Names() {
if n == name {
return f
}
}
}
}
if ctx.App != nil {
for _, f := range ctx.App.Flags {
for _, n := range f.Names() {
if n == name {
return f
}
}
}
}
return nil
}
func lookupFlagSet(name string, ctx *Context) *flag.FlagSet {
for _, c := range ctx.Lineage() {
if f := c.flagSet.Lookup(name); f != nil {
return c.flagSet
}
}
return nil
}
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
switch ff.Value.(type) {
case Serializer:
_ = set.Set(name, ff.Value.(Serializer).Serialize())
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 := f.Names()
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
}
func makeFlagNameVisitor(names *[]string) func(*flag.Flag) {
return func(f *flag.Flag) {
nameParts := strings.Split(f.Name, ",")
name := strings.TrimSpace(nameParts[0])
for _, part := range nameParts {
part = strings.TrimSpace(part)
if len(part) > len(name) {
name = part
}
}
if name != "" {
*names = append(*names, name)
}
}
}
type requiredFlagsErr interface {
error
getMissingFlags() []string
}
type errRequiredFlags struct {
missingFlags []string
}
func (e *errRequiredFlags) Error() string {
numberOfMissingFlags := len(e.missingFlags)
if numberOfMissingFlags == 1 {
return fmt.Sprintf("Required flag %q not set", e.missingFlags[0])
}
joinedMissingFlags := strings.Join(e.missingFlags, ", ")
return fmt.Sprintf("Required flags %q not set", joinedMissingFlags)
}
func (e *errRequiredFlags) getMissingFlags() []string {
return e.missingFlags
}
func checkRequiredFlags(flags []Flag, context *Context) requiredFlagsErr {
var missingFlags []string
for _, f := range flags {
if rf, ok := f.(RequiredFlag); ok && rf.IsRequired() {
var flagPresent bool
var flagName string
for _, key := range f.Names() {
if len(key) > 1 {
flagName = key
}
if context.IsSet(strings.TrimSpace(key)) {
flagPresent = true
}
}
if !flagPresent && flagName != "" {
missingFlags = append(missingFlags, flagName)
}
}
}
if len(missingFlags) != 0 {
return &errRequiredFlags{missingFlags: missingFlags}
}
return nil
}

View File

@ -48,15 +48,14 @@ func (a *App) writeDocTemplate(w io.Writer) error {
return t.ExecuteTemplate(w, name, &cliTemplate{ return t.ExecuteTemplate(w, name, &cliTemplate{
App: a, App: a,
Commands: prepareCommands(a.Commands, 0), Commands: prepareCommands(a.Commands, 0),
GlobalArgs: prepareArgsWithValues(a.Flags), GlobalArgs: prepareArgsWithValues(a.VisibleFlags()),
SynopsisArgs: prepareArgsSynopsis(a.Flags), SynopsisArgs: prepareArgsSynopsis(a.VisibleFlags()),
}) })
} }
func prepareCommands(commands []Command, level int) []string { func prepareCommands(commands []*Command, level int) []string {
coms := []string{} var coms []string
for i := range commands { for _, command := range commands {
command := &commands[i]
if command.Hidden { if command.Hidden {
continue continue
} }
@ -110,7 +109,8 @@ func prepareFlags(
continue continue
} }
modifiedArg := opener modifiedArg := opener
for _, s := range strings.Split(flag.GetName(), ",") {
for _, s := range flag.Names() {
trimmed := strings.TrimSpace(s) trimmed := strings.TrimSpace(s)
if len(modifiedArg) > len(opener) { if len(modifiedArg) > len(opener) {
modifiedArg += sep modifiedArg += sep

View File

@ -15,25 +15,40 @@ var OsExiter = os.Exit
var ErrWriter io.Writer = os.Stderr var ErrWriter io.Writer = os.Stderr
// MultiError is an error that wraps multiple errors. // MultiError is an error that wraps multiple errors.
type MultiError struct { type MultiError interface {
Errors []error error
// Errors returns a copy of the errors slice
Errors() []error
} }
// NewMultiError creates a new MultiError. Pass in one or more errors. // NewMultiError creates a new MultiError. Pass in one or more errors.
func NewMultiError(err ...error) MultiError { func newMultiError(err ...error) MultiError {
return MultiError{Errors: err} ret := multiError(err)
return &ret
} }
type multiError []error
// Error implements the error interface. // Error implements the error interface.
func (m MultiError) Error() string { func (m *multiError) Error() string {
errs := make([]string, len(m.Errors)) errs := make([]string, len(*m))
for i, err := range m.Errors { for i, err := range *m {
errs[i] = err.Error() errs[i] = err.Error()
} }
return strings.Join(errs, "\n") return strings.Join(errs, "\n")
} }
// Errors returns a copy of the errors slice
func (m *multiError) Errors() []error {
errs := make([]error, len(*m))
for _, err := range *m {
errs = append(errs, err)
}
return errs
}
// ErrorFormatter is the interface that will suitably format the error output
type ErrorFormatter interface { type ErrorFormatter interface {
Format(s fmt.State, verb rune) Format(s fmt.State, verb rune)
} }
@ -45,29 +60,30 @@ type ExitCoder interface {
ExitCode() int ExitCode() int
} }
// ExitError fulfills both the builtin `error` interface and `ExitCoder` type exitError struct {
type ExitError struct {
exitCode int exitCode int
message interface{} message interface{}
} }
// NewExitError makes a new *ExitError // NewExitError makes a new *exitError
func NewExitError(message interface{}, exitCode int) *ExitError { func NewExitError(message interface{}, exitCode int) ExitCoder {
return &ExitError{ return Exit(message, exitCode)
exitCode: exitCode, }
// Exit wraps a message and exit code into an ExitCoder suitable for handling by
// HandleExitCoder
func Exit(message interface{}, exitCode int) ExitCoder {
return &exitError{
message: message, message: message,
exitCode: exitCode,
} }
} }
// Error returns the string message, fulfilling the interface required by func (ee *exitError) Error() string {
// `error`
func (ee *ExitError) Error() string {
return fmt.Sprintf("%v", ee.message) return fmt.Sprintf("%v", ee.message)
} }
// ExitCode returns the exit code, fulfilling the interface required by func (ee *exitError) ExitCode() int {
// `ExitCoder`
func (ee *ExitError) ExitCode() int {
return ee.exitCode return ee.exitCode
} }
@ -83,9 +99,9 @@ func HandleExitCoder(err error) {
if exitErr, ok := err.(ExitCoder); ok { if exitErr, ok := err.(ExitCoder); ok {
if err.Error() != "" { if err.Error() != "" {
if _, ok := exitErr.(ErrorFormatter); ok { if _, ok := exitErr.(ErrorFormatter); ok {
fmt.Fprintf(ErrWriter, "%+v\n", err) _, _ = fmt.Fprintf(ErrWriter, "%+v\n", err)
} else { } else {
fmt.Fprintln(ErrWriter, err) _, _ = fmt.Fprintln(ErrWriter, err)
} }
} }
OsExiter(exitErr.ExitCode()) OsExiter(exitErr.ExitCode())
@ -101,10 +117,10 @@ func HandleExitCoder(err error) {
func handleMultiError(multiErr MultiError) int { func handleMultiError(multiErr MultiError) int {
code := 1 code := 1
for _, merr := range multiErr.Errors { for _, merr := range multiErr.Errors() {
if multiErr2, ok := merr.(MultiError); ok { if multiErr2, ok := merr.(MultiError); ok {
code = handleMultiError(multiErr2) code = handleMultiError(multiErr2)
} else { } else if merr != nil {
fmt.Fprintln(ErrWriter, merr) fmt.Fprintln(ErrWriter, merr)
if exitErr, ok := merr.(ExitCoder); ok { if exitErr, ok := merr.(ExitCoder); ok {
code = exitErr.ExitCode() code = exitErr.ExitCode()

View File

@ -64,11 +64,9 @@ func (a *App) writeFishCompletionTemplate(w io.Writer) error {
}) })
} }
func (a *App) prepareFishCommands(commands []Command, allCommands *[]string, previousCommands []string) []string { func (a *App) prepareFishCommands(commands []*Command, allCommands *[]string, previousCommands []string) []string {
completions := []string{} completions := []string{}
for i := range commands { for _, command := range commands {
command := &commands[i]
if command.Hidden { if command.Hidden {
continue continue
} }
@ -131,7 +129,7 @@ func (a *App) prepareFishFlags(flags []Flag, previousCommands []string) []string
fishAddFileFlag(f, completion) fishAddFileFlag(f, completion)
for idx, opt := range strings.Split(flag.GetName(), ",") { for idx, opt := range flag.Names() {
if idx == 0 { if idx == 0 {
completion.WriteString(fmt.Sprintf( completion.WriteString(fmt.Sprintf(
" -l %s", strings.TrimSpace(opt), " -l %s", strings.TrimSpace(opt),
@ -161,15 +159,15 @@ func (a *App) prepareFishFlags(flags []Flag, previousCommands []string) []string
func fishAddFileFlag(flag Flag, completion *strings.Builder) { func fishAddFileFlag(flag Flag, completion *strings.Builder) {
switch f := flag.(type) { switch f := flag.(type) {
case GenericFlag: case *GenericFlag:
if f.TakesFile { if f.TakesFile {
return return
} }
case StringFlag: case *StringFlag:
if f.TakesFile { if f.TakesFile {
return return
} }
case StringSliceFlag: case *StringSliceFlag:
if f.TakesFile { if f.TakesFile {
return return
} }

View File

@ -5,31 +5,41 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"reflect" "reflect"
"regexp"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"syscall" "syscall"
"time"
) )
const defaultPlaceholder = "value" const defaultPlaceholder = "value"
var (
slPfx = fmt.Sprintf("sl:::%d:::", time.Now().UTC().UnixNano())
commaWhitespace = regexp.MustCompile("[, ]+.*")
)
// BashCompletionFlag enables bash-completion for all commands and subcommands // BashCompletionFlag enables bash-completion for all commands and subcommands
var BashCompletionFlag Flag = BoolFlag{ var BashCompletionFlag Flag = &BoolFlag{
Name: "generate-bash-completion", Name: "generate-bash-completion",
Hidden: true, Hidden: true,
} }
// VersionFlag prints the version for the application // VersionFlag prints the version for the application
var VersionFlag Flag = BoolFlag{ var VersionFlag Flag = &BoolFlag{
Name: "version, v", Name: "version",
Aliases: []string{"v"},
Usage: "print the version", Usage: "print the version",
} }
// HelpFlag prints the help for all commands and subcommands // HelpFlag prints the help for all commands and subcommands.
// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand // Set to nil to disable the flag. The subcommand
// unless HideHelp is set to true) // will still be added unless HideHelp is set to true.
var HelpFlag Flag = BoolFlag{ var HelpFlag Flag = &BoolFlag{
Name: "help, h", Name: "help",
Aliases: []string{"h"},
Usage: "show help", Usage: "show help",
} }
@ -37,6 +47,11 @@ var HelpFlag Flag = BoolFlag{
// to display a flag. // to display a flag.
var FlagStringer FlagStringFunc = stringifyFlag var FlagStringer FlagStringFunc = stringifyFlag
// Serializer is used to circumvent the limitations of flag.FlagSet.Set
type Serializer interface {
Serialize() string
}
// FlagNamePrefixer converts a full flag name and its placeholder into the help // FlagNamePrefixer converts a full flag name and its placeholder into the help
// message flag prefix. This is used by the default FlagStringer. // message flag prefix. This is used by the default FlagStringer.
var FlagNamePrefixer FlagNamePrefixFunc = prefixedNames var FlagNamePrefixer FlagNamePrefixFunc = prefixedNames
@ -57,7 +72,12 @@ func (f FlagsByName) Len() int {
} }
func (f FlagsByName) Less(i, j int) bool { func (f FlagsByName) Less(i, j int) bool {
return lexicographicLess(f[i].GetName(), f[j].GetName()) if len(f[j].Names()) == 0 {
return false
} else if len(f[i].Names()) == 0 {
return true
}
return lexicographicLess(f[i].Names()[0], f[j].Names()[0])
} }
func (f FlagsByName) Swap(i, j int) { func (f FlagsByName) Swap(i, j int) {
@ -70,8 +90,9 @@ func (f FlagsByName) Swap(i, j int) {
type Flag interface { type Flag interface {
fmt.Stringer fmt.Stringer
// Apply Flag settings to the given flag set // Apply Flag settings to the given flag set
Apply(*flag.FlagSet) Apply(*flag.FlagSet) error
GetName() string Names() []string
IsSet() bool
} }
// RequiredFlag is an interface that allows us to mark flags as required // RequiredFlag is an interface that allows us to mark flags as required
@ -97,40 +118,18 @@ type DocGenerationFlag interface {
GetValue() string GetValue() 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) { func flagSet(name string, flags []Flag) (*flag.FlagSet, error) {
set := flag.NewFlagSet(name, flag.ContinueOnError) set := flag.NewFlagSet(name, flag.ContinueOnError)
for _, f := range flags { for _, f := range flags {
//TODO remove in v2 when errorableFlag is removed if err := f.Apply(set); err != nil {
if ef, ok := f.(errorableFlag); ok {
if err := ef.ApplyWithError(set); err != nil {
return nil, err return nil, err
} }
} else {
f.Apply(set)
}
} }
set.SetOutput(ioutil.Discard) set.SetOutput(ioutil.Discard)
return set, nil return set, nil
} }
func eachName(longName string, fn func(string)) {
parts := strings.Split(longName, ",")
for _, name := range parts {
name = strings.Trim(name, " ")
fn(name)
}
}
func visibleFlags(fl []Flag) []Flag { func visibleFlags(fl []Flag) []Flag {
var visible []Flag var visible []Flag
for _, f := range fl { for _, f := range fl {
@ -169,25 +168,27 @@ func unquoteUsage(usage string) (string, string) {
return "", usage return "", usage
} }
func prefixedNames(fullName, placeholder string) string { func prefixedNames(names []string, placeholder string) string {
var prefixed string var prefixed string
parts := strings.Split(fullName, ",") for i, name := range names {
for i, name := range parts { if name == "" {
name = strings.Trim(name, " ") continue
}
prefixed += prefixFor(name) + name prefixed += prefixFor(name) + name
if placeholder != "" { if placeholder != "" {
prefixed += " " + placeholder prefixed += " " + placeholder
} }
if i < len(parts)-1 { if i < len(names)-1 {
prefixed += ", " prefixed += ", "
} }
} }
return prefixed return prefixed
} }
func withEnvHint(envVar, str string) string { func withEnvHint(envVars []string, str string) string {
envText := "" envText := ""
if envVar != "" { if envVars != nil && len(envVars) > 0 {
prefix := "$" prefix := "$"
suffix := "" suffix := ""
sep := ", $" sep := ", $"
@ -196,11 +197,51 @@ func withEnvHint(envVar, str string) string {
suffix = "%" suffix = "%"
sep = "%, %" sep = "%, %"
} }
envText = " [" + prefix + strings.Join(strings.Split(envVar, ","), sep) + suffix + "]"
envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(envVars, sep), suffix)
} }
return str + envText return str + envText
} }
func flagNames(f Flag) []string {
var ret []string
name := flagStringField(f, "Name")
aliases := flagStringSliceField(f, "Aliases")
for _, part := range append([]string{name}, aliases...) {
// v1 -> v2 migration warning zone:
// Strip off anything after the first found comma or space, which
// *hopefully* makes it a tiny bit more obvious that unexpected behavior is
// caused by using the v1 form of stringly typed "Name".
ret = append(ret, commaWhitespace.ReplaceAllString(part, ""))
}
return ret
}
func flagStringSliceField(f Flag, name string) []string {
fv := flagValue(f)
field := fv.FieldByName(name)
if field.IsValid() {
return field.Interface().([]string)
}
return []string{}
}
func flagStringField(f Flag, name string) string {
fv := flagValue(f)
field := fv.FieldByName(name)
if field.IsValid() {
return field.String()
}
return ""
}
func withFileHint(filePath, str string) string { func withFileHint(filePath, str string) string {
fileText := "" fileText := ""
if filePath != "" { if filePath != "" {
@ -221,39 +262,27 @@ func stringifyFlag(f Flag) string {
fv := flagValue(f) fv := flagValue(f)
switch f.(type) { switch f.(type) {
case IntSliceFlag: case *IntSliceFlag:
return FlagFileHinter( return withEnvHint(flagStringSliceField(f, "EnvVars"),
fv.FieldByName("FilePath").String(), stringifyIntSliceFlag(f.(*IntSliceFlag)))
FlagEnvHinter( case *Int64SliceFlag:
fv.FieldByName("EnvVar").String(), return withEnvHint(flagStringSliceField(f, "EnvVars"),
stringifyIntSliceFlag(f.(IntSliceFlag)), stringifyInt64SliceFlag(f.(*Int64SliceFlag)))
), case *Float64SliceFlag:
) return withEnvHint(flagStringSliceField(f, "EnvVars"),
case Int64SliceFlag: stringifyFloat64SliceFlag(f.(*Float64SliceFlag)))
return FlagFileHinter( case *StringSliceFlag:
fv.FieldByName("FilePath").String(), return withEnvHint(flagStringSliceField(f, "EnvVars"),
FlagEnvHinter( stringifyStringSliceFlag(f.(*StringSliceFlag)))
fv.FieldByName("EnvVar").String(),
stringifyInt64SliceFlag(f.(Int64SliceFlag)),
),
)
case StringSliceFlag:
return FlagFileHinter(
fv.FieldByName("FilePath").String(),
FlagEnvHinter(
fv.FieldByName("EnvVar").String(),
stringifyStringSliceFlag(f.(StringSliceFlag)),
),
)
} }
placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String()) placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String())
needsPlaceholder := false needsPlaceholder := false
defaultValueString := "" defaultValueString := ""
val := fv.FieldByName("Value")
if val := fv.FieldByName("Value"); val.IsValid() { if val.IsValid() {
needsPlaceholder = true needsPlaceholder = val.Kind() != reflect.Bool
defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface()) defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface())
if val.Kind() == reflect.String && val.String() != "" { if val.Kind() == reflect.String && val.String() != "" {
@ -261,6 +290,12 @@ func stringifyFlag(f Flag) string {
} }
} }
helpText := fv.FieldByName("DefaultText")
if helpText.IsValid() && helpText.String() != "" {
needsPlaceholder = val.Kind() != reflect.Bool
defaultValueString = fmt.Sprintf(" (default: %s)", helpText.String())
}
if defaultValueString == " (default: )" { if defaultValueString == " (default: )" {
defaultValueString = "" defaultValueString = ""
} }
@ -271,16 +306,11 @@ func stringifyFlag(f Flag) string {
usageWithDefault := strings.TrimSpace(usage + defaultValueString) usageWithDefault := strings.TrimSpace(usage + defaultValueString)
return FlagFileHinter( return withEnvHint(flagStringSliceField(f, "EnvVars"),
fv.FieldByName("FilePath").String(), fmt.Sprintf("%s\t%s", prefixedNames(f.Names(), placeholder), usageWithDefault))
FlagEnvHinter(
fv.FieldByName("EnvVar").String(),
FlagNamePrefixer(fv.FieldByName("Name").String(), placeholder)+"\t"+usageWithDefault,
),
)
} }
func stringifyIntSliceFlag(f IntSliceFlag) string { func stringifyIntSliceFlag(f *IntSliceFlag) string {
var defaultVals []string var defaultVals []string
if f.Value != nil && len(f.Value.Value()) > 0 { if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() { for _, i := range f.Value.Value() {
@ -288,10 +318,10 @@ func stringifyIntSliceFlag(f IntSliceFlag) string {
} }
} }
return stringifySliceFlag(f.Usage, f.Name, defaultVals) return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
} }
func stringifyInt64SliceFlag(f Int64SliceFlag) string { func stringifyInt64SliceFlag(f *Int64SliceFlag) string {
var defaultVals []string var defaultVals []string
if f.Value != nil && len(f.Value.Value()) > 0 { if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() { for _, i := range f.Value.Value() {
@ -299,10 +329,22 @@ func stringifyInt64SliceFlag(f Int64SliceFlag) string {
} }
} }
return stringifySliceFlag(f.Usage, f.Name, defaultVals) return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
} }
func stringifyStringSliceFlag(f StringSliceFlag) string { func stringifyFloat64SliceFlag(f *Float64SliceFlag) string {
var defaultVals []string
if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() {
defaultVals = append(defaultVals, strings.TrimRight(strings.TrimRight(fmt.Sprintf("%f", i), "0"), "."))
}
}
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
}
func stringifyStringSliceFlag(f *StringSliceFlag) string {
var defaultVals []string var defaultVals []string
if f.Value != nil && len(f.Value.Value()) > 0 { if f.Value != nil && len(f.Value.Value()) > 0 {
for _, s := range f.Value.Value() { for _, s := range f.Value.Value() {
@ -312,10 +354,10 @@ func stringifyStringSliceFlag(f StringSliceFlag) string {
} }
} }
return stringifySliceFlag(f.Usage, f.Name, defaultVals) return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
} }
func stringifySliceFlag(usage, name string, defaultVals []string) string { func stringifySliceFlag(usage string, names, defaultVals []string) string {
placeholder, usage := unquoteUsage(usage) placeholder, usage := unquoteUsage(usage)
if placeholder == "" { if placeholder == "" {
placeholder = defaultPlaceholder placeholder = defaultPlaceholder
@ -326,15 +368,25 @@ func stringifySliceFlag(usage, name string, defaultVals []string) string {
defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", ")) defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", "))
} }
usageWithDefault := strings.TrimSpace(usage + defaultVal) usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal))
return FlagNamePrefixer(name, placeholder) + "\t" + usageWithDefault return fmt.Sprintf("%s\t%s", prefixedNames(names, placeholder), usageWithDefault)
} }
func flagFromFileEnv(filePath, envName string) (val string, ok bool) { func hasFlag(flags []Flag, fl Flag) bool {
for _, envVar := range strings.Split(envName, ",") { for _, existing := range flags {
if fl == existing {
return true
}
}
return false
}
func flagFromEnvOrFile(envVars []string, filePath string) (val string, ok bool) {
for _, envVar := range envVars {
envVar = strings.TrimSpace(envVar) envVar = strings.TrimSpace(envVar)
if envVal, ok := syscall.Getenv(envVar); ok { if val, ok := syscall.Getenv(envVar); ok {
return envVal, true return val, true
} }
} }
for _, fileVar := range strings.Split(filePath, ",") { for _, fileVar := range strings.Split(filePath, ",") {

View File

@ -9,93 +9,90 @@ import (
// BoolFlag is a flag with type bool // BoolFlag is a flag with type bool
type BoolFlag struct { type BoolFlag struct {
Name string Name string
Aliases []string
Usage string Usage string
EnvVar string EnvVars []string
FilePath string FilePath string
Required bool Required bool
Hidden bool Hidden bool
Value bool
DefaultText string
Destination *bool Destination *bool
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *BoolFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f BoolFlag) String() string { func (f *BoolFlag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// GetName returns the name of the flag // Names returns the names of the flag
func (f BoolFlag) GetName() string { func (f *BoolFlag) Names() []string {
return f.Name return flagNames(f)
} }
// IsRequired returns whether or not the flag is required // IsRequired returns whether or not the flag is required
func (f BoolFlag) IsRequired() bool { func (f *BoolFlag) IsRequired() bool {
return f.Required return f.Required
} }
// TakesValue returns true of the flag takes a value, otherwise false // TakesValue returns true of the flag takes a value, otherwise false
func (f BoolFlag) TakesValue() bool { func (f *BoolFlag) TakesValue() bool {
return false return false
} }
// GetUsage returns the usage string for the flag // GetUsage returns the usage string for the flag
func (f BoolFlag) GetUsage() string { func (f *BoolFlag) GetUsage() string {
return f.Usage return f.Usage
} }
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f BoolFlag) GetValue() string { func (f *BoolFlag) GetValue() string {
return "" return ""
} }
// Apply populates the flag given the flag set and environment
func (f *BoolFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val != "" {
valBool, err := strconv.ParseBool(val)
if err != nil {
return fmt.Errorf("could not parse %q as bool value for flag %s: %s", val, f.Name, err)
}
f.Value = valBool
f.HasBeenSet = true
}
}
for _, name := range f.Names() {
if f.Destination != nil {
set.BoolVar(f.Destination, name, f.Value, f.Usage)
continue
}
set.Bool(name, f.Value, f.Usage)
}
return nil
}
// Bool looks up the value of a local BoolFlag, returns // Bool looks up the value of a local BoolFlag, returns
// false if not found // false if not found
func (c *Context) Bool(name string) bool { func (c *Context) Bool(name string) bool {
return lookupBool(name, c.flagSet) if fs := lookupFlagSet(name, c); fs != nil {
}
// 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 lookupBool(name, fs)
} }
return false return false
} }
// 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
}
func lookupBool(name string, set *flag.FlagSet) bool { func lookupBool(name string, set *flag.FlagSet) bool {
f := set.Lookup(name) f := set.Lookup(name)
if f != nil { if f != nil {

View File

@ -9,90 +9,89 @@ import (
// DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration) // DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration)
type DurationFlag struct { type DurationFlag struct {
Name string Name string
Aliases []string
Usage string Usage string
EnvVar string EnvVars []string
FilePath string FilePath string
Required bool Required bool
Hidden bool Hidden bool
Value time.Duration Value time.Duration
DefaultText string
Destination *time.Duration Destination *time.Duration
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *DurationFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f DurationFlag) String() string { func (f *DurationFlag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// GetName returns the name of the flag // Names returns the names of the flag
func (f DurationFlag) GetName() string { func (f *DurationFlag) Names() []string {
return f.Name return flagNames(f)
} }
// IsRequired returns whether or not the flag is required // IsRequired returns whether or not the flag is required
func (f DurationFlag) IsRequired() bool { func (f *DurationFlag) IsRequired() bool {
return f.Required return f.Required
} }
// TakesValue returns true of the flag takes a value, otherwise false // TakesValue returns true of the flag takes a value, otherwise false
func (f DurationFlag) TakesValue() bool { func (f *DurationFlag) TakesValue() bool {
return true return true
} }
// GetUsage returns the usage string for the flag // GetUsage returns the usage string for the flag
func (f DurationFlag) GetUsage() string { func (f *DurationFlag) GetUsage() string {
return f.Usage return f.Usage
} }
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f DurationFlag) GetValue() string { func (f *DurationFlag) GetValue() string {
return f.Value.String() return f.Value.String()
} }
// Apply populates the flag given the flag set and environment
func (f *DurationFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val != "" {
valDuration, err := time.ParseDuration(val)
if err != nil {
return fmt.Errorf("could not parse %q as duration value for flag %s: %s", val, f.Name, err)
}
f.Value = valDuration
f.HasBeenSet = true
}
}
for _, name := range f.Names() {
if f.Destination != nil {
set.DurationVar(f.Destination, name, f.Value, f.Usage)
continue
}
set.Duration(name, f.Value, f.Usage)
}
return nil
}
// Duration looks up the value of a local DurationFlag, returns // Duration looks up the value of a local DurationFlag, returns
// 0 if not found // 0 if not found
func (c *Context) Duration(name string) time.Duration { func (c *Context) Duration(name string) time.Duration {
return lookupDuration(name, c.flagSet) if fs := lookupFlagSet(name, c); fs != nil {
}
// 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 lookupDuration(name, fs)
} }
return 0 return 0
} }
// 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
}
func lookupDuration(name string, set *flag.FlagSet) time.Duration { func lookupDuration(name string, set *flag.FlagSet) time.Duration {
f := set.Lookup(name) f := set.Lookup(name)
if f != nil { if f != nil {

View File

@ -9,90 +9,90 @@ import (
// Float64Flag is a flag with type float64 // Float64Flag is a flag with type float64
type Float64Flag struct { type Float64Flag struct {
Name string Name string
Aliases []string
Usage string Usage string
EnvVar string EnvVars []string
FilePath string FilePath string
Required bool Required bool
Hidden bool Hidden bool
Value float64 Value float64
DefaultText string
Destination *float64 Destination *float64
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *Float64Flag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f Float64Flag) String() string { func (f *Float64Flag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// GetName returns the name of the flag // Names returns the names of the flag
func (f Float64Flag) GetName() string { func (f *Float64Flag) Names() []string {
return f.Name return flagNames(f)
} }
// IsRequired returns whether or not the flag is required // IsRequired returns whether or not the flag is required
func (f Float64Flag) IsRequired() bool { func (f *Float64Flag) IsRequired() bool {
return f.Required return f.Required
} }
// TakesValue returns true of the flag takes a value, otherwise false // TakesValue returns true of the flag takes a value, otherwise false
func (f Float64Flag) TakesValue() bool { func (f *Float64Flag) TakesValue() bool {
return true return true
} }
// GetUsage returns the usage string for the flag // GetUsage returns the usage string for the flag
func (f Float64Flag) GetUsage() string { func (f *Float64Flag) GetUsage() string {
return f.Usage return f.Usage
} }
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f Float64Flag) GetValue() string { func (f *Float64Flag) GetValue() string {
return fmt.Sprintf("%f", f.Value) return fmt.Sprintf("%f", f.Value)
} }
// Apply populates the flag given the flag set and environment
func (f *Float64Flag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val != "" {
valFloat, err := strconv.ParseFloat(val, 10)
if err != nil {
return fmt.Errorf("could not parse %q as float64 value for flag %s: %s", val, f.Name, err)
}
f.Value = valFloat
f.HasBeenSet = true
}
}
for _, name := range f.Names() {
if f.Destination != nil {
set.Float64Var(f.Destination, name, f.Value, f.Usage)
continue
}
set.Float64(name, f.Value, f.Usage)
}
return nil
}
// Float64 looks up the value of a local Float64Flag, returns // Float64 looks up the value of a local Float64Flag, returns
// 0 if not found // 0 if not found
func (c *Context) Float64(name string) float64 { func (c *Context) Float64(name string) float64 {
return lookupFloat64(name, c.flagSet) if fs := lookupFlagSet(name, c); fs != nil {
}
// 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 lookupFloat64(name, fs)
} }
return 0 return 0
} }
// 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 = 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 lookupFloat64(name string, set *flag.FlagSet) float64 { func lookupFloat64(name string, set *flag.FlagSet) float64 {
f := set.Lookup(name) f := set.Lookup(name)
if f != nil { if f != nil {

165
vendor/github.com/urfave/cli/v2/flag_float64_slice.go generated vendored Normal file
View File

@ -0,0 +1,165 @@
package cli
import (
"encoding/json"
"flag"
"fmt"
"strconv"
"strings"
)
// Float64Slice wraps []float64 to satisfy flag.Value
type Float64Slice struct {
slice []float64
hasBeenSet bool
}
// NewFloat64Slice makes a *Float64Slice with default values
func NewFloat64Slice(defaults ...float64) *Float64Slice {
return &Float64Slice{slice: append([]float64{}, defaults...)}
}
// Set parses the value into a float64 and appends it to the list of values
func (f *Float64Slice) Set(value string) error {
if !f.hasBeenSet {
f.slice = []float64{}
f.hasBeenSet = true
}
if strings.HasPrefix(value, slPfx) {
// Deserializing assumes overwrite
_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &f.slice)
f.hasBeenSet = true
return nil
}
tmp, err := strconv.ParseFloat(value, 64)
if err != nil {
return err
}
f.slice = append(f.slice, tmp)
return nil
}
// String returns a readable representation of this value (for usage defaults)
func (f *Float64Slice) String() string {
return fmt.Sprintf("%#v", f.slice)
}
// Serialize allows Float64Slice to fulfill Serializer
func (f *Float64Slice) Serialize() string {
jsonBytes, _ := json.Marshal(f.slice)
return fmt.Sprintf("%s%s", slPfx, string(jsonBytes))
}
// Value returns the slice of float64s set by this flag
func (f *Float64Slice) Value() []float64 {
return f.slice
}
// Get returns the slice of float64s set by this flag
func (f *Float64Slice) Get() interface{} {
return *f
}
// Float64SliceFlag is a flag with type *Float64Slice
type Float64SliceFlag struct {
Name string
Aliases []string
Usage string
EnvVars []string
FilePath string
Required bool
Hidden bool
Value *Float64Slice
DefaultText string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *Float64SliceFlag) IsSet() bool {
return f.HasBeenSet
}
// String returns a readable representation of this value
// (for usage defaults)
func (f *Float64SliceFlag) String() string {
return FlagStringer(f)
}
// Names returns the names of the flag
func (f *Float64SliceFlag) Names() []string {
return flagNames(f)
}
// IsRequired returns whether or not the flag is required
func (f *Float64SliceFlag) IsRequired() bool {
return f.Required
}
// TakesValue returns true if the flag takes a value, otherwise false
func (f *Float64SliceFlag) TakesValue() bool {
return true
}
// GetUsage returns the usage string for the flag
func (f *Float64SliceFlag) GetUsage() string {
return f.Usage
}
// GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all.
func (f *Float64SliceFlag) GetValue() string {
if f.Value != nil {
return f.Value.String()
}
return ""
}
// Apply populates the flag given the flag set and environment
func (f *Float64SliceFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val != "" {
f.Value = &Float64Slice{}
for _, s := range strings.Split(val, ",") {
if err := f.Value.Set(strings.TrimSpace(s)); err != nil {
return fmt.Errorf("could not parse %q as float64 slice value for flag %s: %s", f.Value, f.Name, err)
}
}
f.HasBeenSet = true
}
}
for _, name := range f.Names() {
if f.Value == nil {
f.Value = &Float64Slice{}
}
set.Var(f.Value, name, f.Usage)
}
return nil
}
// Float64Slice looks up the value of a local Float64SliceFlag, returns
// nil if not found
func (c *Context) Float64Slice(name string) []float64 {
if fs := lookupFlagSet(name, c); fs != nil {
return lookupFloat64Slice(name, fs)
}
return nil
}
func lookupFloat64Slice(name string, set *flag.FlagSet) []float64 {
f := set.Lookup(name)
if f != nil {
parsed, err := (f.Value.(*Float64Slice)).Value(), error(nil)
if err != nil {
return nil
}
return parsed
}
return nil
}

View File

@ -14,44 +14,52 @@ type Generic interface {
// GenericFlag is a flag with type Generic // GenericFlag is a flag with type Generic
type GenericFlag struct { type GenericFlag struct {
Name string Name string
Aliases []string
Usage string Usage string
EnvVar string EnvVars []string
FilePath string FilePath string
Required bool Required bool
Hidden bool Hidden bool
TakesFile bool TakesFile bool
Value Generic Value Generic
DefaultText string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *GenericFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f GenericFlag) String() string { func (f *GenericFlag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// GetName returns the name of the flag // Names returns the names of the flag
func (f GenericFlag) GetName() string { func (f *GenericFlag) Names() []string {
return f.Name return flagNames(f)
} }
// IsRequired returns whether or not the flag is required // IsRequired returns whether or not the flag is required
func (f GenericFlag) IsRequired() bool { func (f *GenericFlag) IsRequired() bool {
return f.Required return f.Required
} }
// TakesValue returns true of the flag takes a value, otherwise false // TakesValue returns true of the flag takes a value, otherwise false
func (f GenericFlag) TakesValue() bool { func (f *GenericFlag) TakesValue() bool {
return true return true
} }
// GetUsage returns the usage string for the flag // GetUsage returns the usage string for the flag
func (f GenericFlag) GetUsage() string { func (f *GenericFlag) GetUsage() string {
return f.Usage return f.Usage
} }
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f GenericFlag) GetValue() string { func (f *GenericFlag) GetValue() string {
if f.Value != nil { if f.Value != nil {
return f.Value.String() return f.Value.String()
} }
@ -60,24 +68,20 @@ func (f GenericFlag) GetValue() string {
// Apply takes the flagset and calls Set on the generic flag with the value // Apply takes the flagset and calls Set on the generic flag with the value
// provided by the user for parsing by the flag // provided by the user for parsing by the flag
// Ignores parsing errors func (f GenericFlag) Apply(set *flag.FlagSet) error {
func (f GenericFlag) Apply(set *flag.FlagSet) { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
_ = f.ApplyWithError(set) if val != "" {
if err := f.Value.Set(val); err != nil {
return fmt.Errorf("could not parse %q as value for flag %s: %s", val, f.Name, err)
} }
// ApplyWithError takes the flagset and calls Set on the generic flag with the value f.HasBeenSet = true
// provided by the user for parsing by the flag
func (f GenericFlag) ApplyWithError(set *flag.FlagSet) error {
val := f.Value
if fileEnvVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
if err := val.Set(fileEnvVal); err != nil {
return fmt.Errorf("could not parse %s as value for flag %s: %s", fileEnvVal, f.Name, err)
} }
} }
eachName(f.Name, func(name string) { for _, name := range f.Names() {
set.Var(f.Value, name, f.Usage) set.Var(f.Value, name, f.Usage)
}) }
return nil return nil
} }
@ -85,13 +89,7 @@ func (f GenericFlag) ApplyWithError(set *flag.FlagSet) error {
// Generic looks up the value of a local GenericFlag, returns // Generic looks up the value of a local GenericFlag, returns
// nil if not found // nil if not found
func (c *Context) Generic(name string) interface{} { func (c *Context) Generic(name string) interface{} {
return lookupGeneric(name, c.flagSet) if fs := lookupFlagSet(name, c); fs != nil {
}
// 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 lookupGeneric(name, fs)
} }
return nil return nil

View File

@ -9,70 +9,77 @@ import (
// IntFlag is a flag with type int // IntFlag is a flag with type int
type IntFlag struct { type IntFlag struct {
Name string Name string
Aliases []string
Usage string Usage string
EnvVar string EnvVars []string
FilePath string FilePath string
Required bool Required bool
Hidden bool Hidden bool
Value int Value int
DefaultText string
Destination *int Destination *int
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *IntFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f IntFlag) String() string { func (f *IntFlag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// GetName returns the name of the flag // Names returns the names of the flag
func (f IntFlag) GetName() string { func (f *IntFlag) Names() []string {
return f.Name return flagNames(f)
} }
// IsRequired returns whether or not the flag is required // IsRequired returns whether or not the flag is required
func (f IntFlag) IsRequired() bool { func (f *IntFlag) IsRequired() bool {
return f.Required return f.Required
} }
// TakesValue returns true of the flag takes a value, otherwise false // TakesValue returns true of the flag takes a value, otherwise false
func (f IntFlag) TakesValue() bool { func (f *IntFlag) TakesValue() bool {
return true return true
} }
// GetUsage returns the usage string for the flag // GetUsage returns the usage string for the flag
func (f IntFlag) GetUsage() string { func (f *IntFlag) GetUsage() string {
return f.Usage return f.Usage
} }
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f IntFlag) GetValue() string { func (f *IntFlag) GetValue() string {
return fmt.Sprintf("%d", f.Value) return fmt.Sprintf("%d", f.Value)
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
// Ignores errors func (f *IntFlag) Apply(set *flag.FlagSet) error {
func (f IntFlag) Apply(set *flag.FlagSet) { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
_ = f.ApplyWithError(set) if val != "" {
} valInt, err := strconv.ParseInt(val, 0, 64)
// 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 { if err != nil {
return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) return fmt.Errorf("could not parse %q as int value for flag %s: %s", val, f.Name, err)
}
f.Value = int(envValInt)
} }
eachName(f.Name, func(name string) { f.Value = int(valInt)
f.HasBeenSet = true
}
}
for _, name := range f.Names() {
if f.Destination != nil { if f.Destination != nil {
set.IntVar(f.Destination, name, f.Value, f.Usage) set.IntVar(f.Destination, name, f.Value, f.Usage)
return continue
} }
set.Int(name, f.Value, f.Usage) set.Int(name, f.Value, f.Usage)
}) }
return nil return nil
} }
@ -80,13 +87,7 @@ func (f IntFlag) ApplyWithError(set *flag.FlagSet) error {
// Int looks up the value of a local IntFlag, returns // Int looks up the value of a local IntFlag, returns
// 0 if not found // 0 if not found
func (c *Context) Int(name string) int { func (c *Context) Int(name string) int {
return lookupInt(name, c.flagSet) if fs := lookupFlagSet(name, c); fs != nil {
}
// 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 lookupInt(name, fs)
} }
return 0 return 0

View File

@ -9,85 +9,84 @@ import (
// Int64Flag is a flag with type int64 // Int64Flag is a flag with type int64
type Int64Flag struct { type Int64Flag struct {
Name string Name string
Aliases []string
Usage string Usage string
EnvVar string EnvVars []string
FilePath string FilePath string
Required bool Required bool
Hidden bool Hidden bool
Value int64 Value int64
DefaultText string
Destination *int64 Destination *int64
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *Int64Flag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f Int64Flag) String() string { func (f *Int64Flag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// GetName returns the name of the flag // Names returns the names of the flag
func (f Int64Flag) GetName() string { func (f *Int64Flag) Names() []string {
return f.Name return flagNames(f)
} }
// IsRequired returns whether or not the flag is required // IsRequired returns whether or not the flag is required
func (f Int64Flag) IsRequired() bool { func (f *Int64Flag) IsRequired() bool {
return f.Required return f.Required
} }
// TakesValue returns true of the flag takes a value, otherwise false // TakesValue returns true of the flag takes a value, otherwise false
func (f Int64Flag) TakesValue() bool { func (f *Int64Flag) TakesValue() bool {
return true return true
} }
// GetUsage returns the usage string for the flag // GetUsage returns the usage string for the flag
func (f Int64Flag) GetUsage() string { func (f *Int64Flag) GetUsage() string {
return f.Usage return f.Usage
} }
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f Int64Flag) GetValue() string { func (f *Int64Flag) GetValue() string {
return fmt.Sprintf("%d", f.Value) return fmt.Sprintf("%d", f.Value)
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
// Ignores errors func (f *Int64Flag) Apply(set *flag.FlagSet) error {
func (f Int64Flag) Apply(set *flag.FlagSet) { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
_ = f.ApplyWithError(set) if val != "" {
} valInt, err := strconv.ParseInt(val, 0, 64)
// 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 { if err != nil {
return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) return fmt.Errorf("could not parse %q as int value for flag %s: %s", val, f.Name, err)
} }
f.Value = envValInt f.Value = valInt
f.HasBeenSet = true
}
} }
eachName(f.Name, func(name string) { for _, name := range f.Names() {
if f.Destination != nil { if f.Destination != nil {
set.Int64Var(f.Destination, name, f.Value, f.Usage) set.Int64Var(f.Destination, name, f.Value, f.Usage)
return continue
} }
set.Int64(name, f.Value, f.Usage) set.Int64(name, f.Value, f.Usage)
}) }
return nil return nil
} }
// Int64 looks up the value of a local Int64Flag, returns // Int64 looks up the value of a local Int64Flag, returns
// 0 if not found // 0 if not found
func (c *Context) Int64(name string) int64 { func (c *Context) Int64(name string) int64 {
return lookupInt64(name, c.flagSet) if fs := lookupFlagSet(name, c); fs != nil {
}
// 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 lookupInt64(name, fs)
} }
return 0 return 0

161
vendor/github.com/urfave/cli/v2/flag_int64_slice.go generated vendored Normal file
View File

@ -0,0 +1,161 @@
package cli
import (
"encoding/json"
"flag"
"fmt"
"strconv"
"strings"
)
// Int64Slice wraps []int64 to satisfy flag.Value
type Int64Slice struct {
slice []int64
hasBeenSet bool
}
// NewInt64Slice makes an *Int64Slice with default values
func NewInt64Slice(defaults ...int64) *Int64Slice {
return &Int64Slice{slice: append([]int64{}, defaults...)}
}
// Set parses the value into an integer and appends it to the list of values
func (i *Int64Slice) Set(value string) error {
if !i.hasBeenSet {
i.slice = []int64{}
i.hasBeenSet = true
}
if strings.HasPrefix(value, slPfx) {
// Deserializing assumes overwrite
_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &i.slice)
i.hasBeenSet = true
return nil
}
tmp, err := strconv.ParseInt(value, 0, 64)
if err != nil {
return err
}
i.slice = append(i.slice, tmp)
return nil
}
// String returns a readable representation of this value (for usage defaults)
func (i *Int64Slice) String() string {
return fmt.Sprintf("%#v", i.slice)
}
// Serialize allows Int64Slice to fulfill Serializer
func (i *Int64Slice) Serialize() string {
jsonBytes, _ := json.Marshal(i.slice)
return fmt.Sprintf("%s%s", slPfx, string(jsonBytes))
}
// Value returns the slice of ints set by this flag
func (i *Int64Slice) Value() []int64 {
return i.slice
}
// Get returns the slice of ints set by this flag
func (i *Int64Slice) Get() interface{} {
return *i
}
// Int64SliceFlag is a flag with type *Int64Slice
type Int64SliceFlag struct {
Name string
Aliases []string
Usage string
EnvVars []string
FilePath string
Required bool
Hidden bool
Value *Int64Slice
DefaultText string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *Int64SliceFlag) IsSet() bool {
return f.HasBeenSet
}
// String returns a readable representation of this value
// (for usage defaults)
func (f *Int64SliceFlag) String() string {
return FlagStringer(f)
}
// Names returns the names of the flag
func (f *Int64SliceFlag) Names() []string {
return flagNames(f)
}
// IsRequired returns whether or not the flag is required
func (f *Int64SliceFlag) IsRequired() bool {
return f.Required
}
// TakesValue returns true of the flag takes a value, otherwise false
func (f *Int64SliceFlag) TakesValue() bool {
return true
}
// GetUsage returns the usage string for the flag
func (f Int64SliceFlag) GetUsage() string {
return f.Usage
}
// GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all.
func (f *Int64SliceFlag) GetValue() string {
if f.Value != nil {
return f.Value.String()
}
return ""
}
// Apply populates the flag given the flag set and environment
func (f *Int64SliceFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
f.Value = &Int64Slice{}
for _, s := range strings.Split(val, ",") {
if err := f.Value.Set(strings.TrimSpace(s)); err != nil {
return fmt.Errorf("could not parse %q as int64 slice value for flag %s: %s", val, f.Name, err)
}
}
f.HasBeenSet = true
}
for _, name := range f.Names() {
if f.Value == nil {
f.Value = &Int64Slice{}
}
set.Var(f.Value, name, f.Usage)
}
return nil
}
// 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)
}
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
}

175
vendor/github.com/urfave/cli/v2/flag_int_slice.go generated vendored Normal file
View File

@ -0,0 +1,175 @@
package cli
import (
"encoding/json"
"flag"
"fmt"
"strconv"
"strings"
)
// IntSlice wraps []int to satisfy flag.Value
type IntSlice struct {
slice []int
hasBeenSet bool
}
// NewIntSlice makes an *IntSlice with default values
func NewIntSlice(defaults ...int) *IntSlice {
return &IntSlice{slice: append([]int{}, defaults...)}
}
// TODO: Consistently have specific Set function for Int64 and Float64 ?
// SetInt directly adds an integer to the list of values
func (i *IntSlice) SetInt(value int) {
if !i.hasBeenSet {
i.slice = []int{}
i.hasBeenSet = true
}
i.slice = append(i.slice, value)
}
// Set parses the value into an integer and appends it to the list of values
func (i *IntSlice) Set(value string) error {
if !i.hasBeenSet {
i.slice = []int{}
i.hasBeenSet = true
}
if strings.HasPrefix(value, slPfx) {
// Deserializing assumes overwrite
_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &i.slice)
i.hasBeenSet = true
return nil
}
tmp, err := strconv.ParseInt(value, 0, 64)
if err != nil {
return err
}
i.slice = append(i.slice, int(tmp))
return nil
}
// String returns a readable representation of this value (for usage defaults)
func (i *IntSlice) String() string {
return fmt.Sprintf("%#v", i.slice)
}
// Serialize allows IntSlice to fulfill Serializer
func (i *IntSlice) Serialize() string {
jsonBytes, _ := json.Marshal(i.slice)
return fmt.Sprintf("%s%s", slPfx, string(jsonBytes))
}
// Value returns the slice of ints set by this flag
func (i *IntSlice) Value() []int {
return i.slice
}
// Get returns the slice of ints set by this flag
func (i *IntSlice) Get() interface{} {
return *i
}
// IntSliceFlag is a flag with type *IntSlice
type IntSliceFlag struct {
Name string
Aliases []string
Usage string
EnvVars []string
FilePath string
Required bool
Hidden bool
Value *IntSlice
DefaultText string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *IntSliceFlag) IsSet() bool {
return f.HasBeenSet
}
// String returns a readable representation of this value
// (for usage defaults)
func (f *IntSliceFlag) String() string {
return FlagStringer(f)
}
// Names returns the names of the flag
func (f *IntSliceFlag) Names() []string {
return flagNames(f)
}
// IsRequired returns whether or not the flag is required
func (f *IntSliceFlag) IsRequired() bool {
return f.Required
}
// TakesValue returns true of the flag takes a value, otherwise false
func (f *IntSliceFlag) TakesValue() bool {
return true
}
// GetUsage returns the usage string for the flag
func (f IntSliceFlag) GetUsage() string {
return f.Usage
}
// GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all.
func (f *IntSliceFlag) GetValue() string {
if f.Value != nil {
return f.Value.String()
}
return ""
}
// Apply populates the flag given the flag set and environment
func (f *IntSliceFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
f.Value = &IntSlice{}
for _, s := range strings.Split(val, ",") {
if err := f.Value.Set(strings.TrimSpace(s)); err != nil {
return fmt.Errorf("could not parse %q as int slice value for flag %s: %s", val, f.Name, err)
}
}
f.HasBeenSet = true
}
for _, name := range f.Names() {
if f.Value == nil {
f.Value = &IntSlice{}
}
set.Var(f.Value, name, f.Usage)
}
return nil
}
// IntSlice looks up the value of a local IntSliceFlag, returns
// nil if not found
func (c *Context) IntSlice(name string) []int {
if fs := lookupFlagSet(name, c); fs != nil {
return lookupIntSlice(name, c.flagSet)
}
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
}

95
vendor/github.com/urfave/cli/v2/flag_path.go generated vendored Normal file
View File

@ -0,0 +1,95 @@
package cli
import "flag"
type PathFlag struct {
Name string
Aliases []string
Usage string
EnvVars []string
FilePath string
Required bool
Hidden bool
TakesFile bool
Value string
DefaultText string
Destination *string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *PathFlag) IsSet() bool {
return f.HasBeenSet
}
// String returns a readable representation of this value
// (for usage defaults)
func (f *PathFlag) String() string {
return FlagStringer(f)
}
// Names returns the names of the flag
func (f *PathFlag) Names() []string {
return flagNames(f)
}
// IsRequired returns whether or not the flag is required
func (f *PathFlag) IsRequired() bool {
return f.Required
}
// TakesValue returns true of the flag takes a value, otherwise false
func (f *PathFlag) TakesValue() bool {
return true
}
// GetUsage returns the usage string for the flag
func (f *PathFlag) GetUsage() string {
return f.Usage
}
// GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all.
func (f *PathFlag) GetValue() string {
return f.Value
}
// Apply populates the flag given the flag set and environment
func (f *PathFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
f.Value = val
f.HasBeenSet = true
}
for _, name := range f.Names() {
if f.Destination != nil {
set.StringVar(f.Destination, name, f.Value, f.Usage)
continue
}
set.String(name, f.Value, f.Usage)
}
return nil
}
// Path looks up the value of a local PathFlag, returns
// "" if not found
func (c *Context) Path(name string) string {
if fs := lookupFlagSet(name, c); fs != nil {
return lookupPath(name, fs)
}
return ""
}
func lookupPath(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 ""
}

View File

@ -5,67 +5,70 @@ import "flag"
// StringFlag is a flag with type string // StringFlag is a flag with type string
type StringFlag struct { type StringFlag struct {
Name string Name string
Aliases []string
Usage string Usage string
EnvVar string EnvVars []string
FilePath string FilePath string
Required bool Required bool
Hidden bool Hidden bool
TakesFile bool TakesFile bool
Value string Value string
DefaultText string
Destination *string Destination *string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *StringFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f StringFlag) String() string { func (f *StringFlag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// GetName returns the name of the flag // Names returns the names of the flag
func (f StringFlag) GetName() string { func (f *StringFlag) Names() []string {
return f.Name return flagNames(f)
} }
// IsRequired returns whether or not the flag is required // IsRequired returns whether or not the flag is required
func (f StringFlag) IsRequired() bool { func (f *StringFlag) IsRequired() bool {
return f.Required return f.Required
} }
// TakesValue returns true of the flag takes a value, otherwise false // TakesValue returns true of the flag takes a value, otherwise false
func (f StringFlag) TakesValue() bool { func (f *StringFlag) TakesValue() bool {
return true return true
} }
// GetUsage returns the usage string for the flag // GetUsage returns the usage string for the flag
func (f StringFlag) GetUsage() string { func (f *StringFlag) GetUsage() string {
return f.Usage return f.Usage
} }
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f StringFlag) GetValue() string { func (f *StringFlag) GetValue() string {
return f.Value return f.Value
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
// Ignores errors func (f *StringFlag) Apply(set *flag.FlagSet) error {
func (f StringFlag) Apply(set *flag.FlagSet) { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
_ = f.ApplyWithError(set) f.Value = val
f.HasBeenSet = true
} }
// ApplyWithError populates the flag given the flag set and environment for _, name := range f.Names() {
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 { if f.Destination != nil {
set.StringVar(f.Destination, name, f.Value, f.Usage) set.StringVar(f.Destination, name, f.Value, f.Usage)
return continue
} }
set.String(name, f.Value, f.Usage) set.String(name, f.Value, f.Usage)
}) }
return nil return nil
} }
@ -73,13 +76,7 @@ func (f StringFlag) ApplyWithError(set *flag.FlagSet) error {
// String looks up the value of a local StringFlag, returns // String looks up the value of a local StringFlag, returns
// "" if not found // "" if not found
func (c *Context) String(name string) string { func (c *Context) String(name string) string {
return lookupString(name, c.flagSet) if fs := lookupFlagSet(name, c); fs != nil {
}
// 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 lookupString(name, fs)
} }
return "" return ""

159
vendor/github.com/urfave/cli/v2/flag_string_slice.go generated vendored Normal file
View File

@ -0,0 +1,159 @@
package cli
import (
"encoding/json"
"flag"
"fmt"
"strings"
)
// StringSlice wraps a []string to satisfy flag.Value
type StringSlice struct {
slice []string
hasBeenSet bool
}
// NewStringSlice creates a *StringSlice with default values
func NewStringSlice(defaults ...string) *StringSlice {
return &StringSlice{slice: append([]string{}, defaults...)}
}
// Set appends the string value to the list of values
func (s *StringSlice) Set(value string) error {
if !s.hasBeenSet {
s.slice = []string{}
s.hasBeenSet = true
}
if strings.HasPrefix(value, slPfx) {
// Deserializing assumes overwrite
_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &s.slice)
s.hasBeenSet = true
return nil
}
s.slice = append(s.slice, value)
return nil
}
// String returns a readable representation of this value (for usage defaults)
func (s *StringSlice) String() string {
return fmt.Sprintf("%s", s.slice)
}
// Serialize allows StringSlice to fulfill Serializer
func (s *StringSlice) Serialize() string {
jsonBytes, _ := json.Marshal(s.slice)
return fmt.Sprintf("%s%s", slPfx, string(jsonBytes))
}
// Value returns the slice of strings set by this flag
func (s *StringSlice) Value() []string {
return s.slice
}
// Get returns the slice of strings set by this flag
func (s *StringSlice) Get() interface{} {
return *s
}
// StringSliceFlag is a flag with type *StringSlice
type StringSliceFlag struct {
Name string
Aliases []string
Usage string
EnvVars []string
FilePath string
Required bool
Hidden bool
TakesFile bool
Value *StringSlice
DefaultText string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *StringSliceFlag) IsSet() bool {
return f.HasBeenSet
}
// String returns a readable representation of this value
// (for usage defaults)
func (f *StringSliceFlag) String() string {
return FlagStringer(f)
}
// Names returns the names of the flag
func (f *StringSliceFlag) Names() []string {
return flagNames(f)
}
// IsRequired returns whether or not the flag is required
func (f *StringSliceFlag) IsRequired() bool {
return f.Required
}
// TakesValue returns true of the flag takes a value, otherwise false
func (f *StringSliceFlag) TakesValue() bool {
return true
}
// GetUsage returns the usage string for the flag
func (f *StringSliceFlag) GetUsage() string {
return f.Usage
}
// GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all.
func (f *StringSliceFlag) GetValue() string {
if f.Value != nil {
return f.Value.String()
}
return ""
}
// Apply populates the flag given the flag set and environment
func (f *StringSliceFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
f.Value = &StringSlice{}
for _, s := range strings.Split(val, ",") {
if err := f.Value.Set(strings.TrimSpace(s)); err != nil {
return fmt.Errorf("could not parse %q as string value for flag %s: %s", val, f.Name, err)
}
}
f.HasBeenSet = true
}
for _, name := range f.Names() {
if f.Value == nil {
f.Value = &StringSlice{}
}
set.Var(f.Value, name, f.Usage)
}
return nil
}
// StringSlice looks up the value of a local StringSliceFlag, returns
// nil if not found
func (c *Context) StringSlice(name string) []string {
if fs := lookupFlagSet(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
}

152
vendor/github.com/urfave/cli/v2/flag_timestamp.go generated vendored Normal file
View File

@ -0,0 +1,152 @@
package cli
import (
"flag"
"fmt"
"time"
)
// Timestamp wrap to satisfy golang's flag interface.
type Timestamp struct {
timestamp *time.Time
hasBeenSet bool
layout string
}
// Timestamp constructor
func NewTimestamp(timestamp time.Time) *Timestamp {
return &Timestamp{timestamp: &timestamp}
}
// Set the timestamp value directly
func (t *Timestamp) SetTimestamp(value time.Time) {
if !t.hasBeenSet {
t.timestamp = &value
t.hasBeenSet = true
}
}
// Set the timestamp string layout for future parsing
func (t *Timestamp) SetLayout(layout string) {
t.layout = layout
}
// Parses the string value to timestamp
func (t *Timestamp) Set(value string) error {
timestamp, err := time.Parse(t.layout, value)
if err != nil {
return err
}
t.timestamp = &timestamp
t.hasBeenSet = true
return nil
}
// String returns a readable representation of this value (for usage defaults)
func (t *Timestamp) String() string {
return fmt.Sprintf("%#v", t.timestamp)
}
// Value returns the timestamp value stored in the flag
func (t *Timestamp) Value() *time.Time {
return t.timestamp
}
// Get returns the flag structure
func (t *Timestamp) Get() interface{} {
return *t
}
// TimestampFlag is a flag with type time
type TimestampFlag struct {
Name string
Aliases []string
Usage string
EnvVars []string
FilePath string
Required bool
Hidden bool
Layout string
Value *Timestamp
DefaultText string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *TimestampFlag) IsSet() bool {
return f.HasBeenSet
}
// String returns a readable representation of this value
// (for usage defaults)
func (f *TimestampFlag) String() string {
return FlagStringer(f)
}
// Names returns the names of the flag
func (f *TimestampFlag) Names() []string {
return flagNames(f)
}
// IsRequired returns whether or not the flag is required
func (f *TimestampFlag) IsRequired() bool {
return f.Required
}
// TakesValue returns true of the flag takes a value, otherwise false
func (f *TimestampFlag) TakesValue() bool {
return true
}
// GetUsage returns the usage string for the flag
func (f *TimestampFlag) GetUsage() string {
return f.Usage
}
// GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all.
func (f *TimestampFlag) GetValue() string {
if f.Value != nil {
return f.Value.timestamp.String()
}
return ""
}
// Apply populates the flag given the flag set and environment
func (f *TimestampFlag) Apply(set *flag.FlagSet) error {
if f.Layout == "" {
return fmt.Errorf("timestamp Layout is required")
}
f.Value = &Timestamp{}
f.Value.SetLayout(f.Layout)
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if err := f.Value.Set(val); err != nil {
return fmt.Errorf("could not parse %q as timestamp value for flag %s: %s", val, f.Name, err)
}
f.HasBeenSet = true
}
for _, name := range f.Names() {
set.Var(f.Value, name, f.Usage)
}
return nil
}
// Timestamp gets the timestamp from a flag name
func (c *Context) Timestamp(name string) *time.Time {
if fs := lookupFlagSet(name, c); fs != nil {
return lookupTimestamp(name, fs)
}
return nil
}
// Fetches the timestamp value from the local timestampWrap
func lookupTimestamp(name string, set *flag.FlagSet) *time.Time {
f := set.Lookup(name)
if f != nil {
return (f.Value.(*Timestamp)).Value()
}
return nil
}

View File

@ -9,85 +9,84 @@ import (
// UintFlag is a flag with type uint // UintFlag is a flag with type uint
type UintFlag struct { type UintFlag struct {
Name string Name string
Aliases []string
Usage string Usage string
EnvVar string EnvVars []string
FilePath string FilePath string
Required bool Required bool
Hidden bool Hidden bool
Value uint Value uint
DefaultText string
Destination *uint Destination *uint
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *UintFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f UintFlag) String() string { func (f *UintFlag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// GetName returns the name of the flag // Names returns the names of the flag
func (f UintFlag) GetName() string { func (f *UintFlag) Names() []string {
return f.Name return flagNames(f)
} }
// IsRequired returns whether or not the flag is required // IsRequired returns whether or not the flag is required
func (f UintFlag) IsRequired() bool { func (f *UintFlag) IsRequired() bool {
return f.Required return f.Required
} }
// TakesValue returns true of the flag takes a value, otherwise false // TakesValue returns true of the flag takes a value, otherwise false
func (f UintFlag) TakesValue() bool { func (f *UintFlag) TakesValue() bool {
return true return true
} }
// GetUsage returns the usage string for the flag // GetUsage returns the usage string for the flag
func (f UintFlag) GetUsage() string { func (f *UintFlag) GetUsage() string {
return f.Usage return f.Usage
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
// Ignores errors func (f *UintFlag) Apply(set *flag.FlagSet) error {
func (f UintFlag) Apply(set *flag.FlagSet) { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
_ = f.ApplyWithError(set) if val != "" {
} valInt, err := strconv.ParseUint(val, 0, 64)
// 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 { if err != nil {
return fmt.Errorf("could not parse %s as uint value for flag %s: %s", envVal, f.Name, err) return fmt.Errorf("could not parse %q as uint value for flag %s: %s", val, f.Name, err)
} }
f.Value = uint(envValInt) f.Value = uint(valInt)
f.HasBeenSet = true
}
} }
eachName(f.Name, func(name string) { for _, name := range f.Names() {
if f.Destination != nil { if f.Destination != nil {
set.UintVar(f.Destination, name, f.Value, f.Usage) set.UintVar(f.Destination, name, f.Value, f.Usage)
return continue
} }
set.Uint(name, f.Value, f.Usage) set.Uint(name, f.Value, f.Usage)
}) }
return nil return nil
} }
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f UintFlag) GetValue() string { func (f *UintFlag) GetValue() string {
return fmt.Sprintf("%d", f.Value) return fmt.Sprintf("%d", f.Value)
} }
// Uint looks up the value of a local UintFlag, returns // Uint looks up the value of a local UintFlag, returns
// 0 if not found // 0 if not found
func (c *Context) Uint(name string) uint { func (c *Context) Uint(name string) uint {
return lookupUint(name, c.flagSet) if fs := lookupFlagSet(name, c); fs != nil {
}
// 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 lookupUint(name, fs)
} }
return 0 return 0

View File

@ -9,85 +9,84 @@ import (
// Uint64Flag is a flag with type uint64 // Uint64Flag is a flag with type uint64
type Uint64Flag struct { type Uint64Flag struct {
Name string Name string
Aliases []string
Usage string Usage string
EnvVar string EnvVars []string
FilePath string FilePath string
Required bool Required bool
Hidden bool Hidden bool
Value uint64 Value uint64
DefaultText string
Destination *uint64 Destination *uint64
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *Uint64Flag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f Uint64Flag) String() string { func (f *Uint64Flag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// GetName returns the name of the flag // Names returns the names of the flag
func (f Uint64Flag) GetName() string { func (f *Uint64Flag) Names() []string {
return f.Name return flagNames(f)
} }
// IsRequired returns whether or not the flag is required // IsRequired returns whether or not the flag is required
func (f Uint64Flag) IsRequired() bool { func (f *Uint64Flag) IsRequired() bool {
return f.Required return f.Required
} }
// TakesValue returns true of the flag takes a value, otherwise false // TakesValue returns true of the flag takes a value, otherwise false
func (f Uint64Flag) TakesValue() bool { func (f *Uint64Flag) TakesValue() bool {
return true return true
} }
// GetUsage returns the usage string for the flag // GetUsage returns the usage string for the flag
func (f Uint64Flag) GetUsage() string { func (f *Uint64Flag) GetUsage() string {
return f.Usage return f.Usage
} }
// Apply populates the flag given the flag set and environment
func (f *Uint64Flag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val != "" {
valInt, err := strconv.ParseUint(val, 0, 64)
if err != nil {
return fmt.Errorf("could not parse %q as uint64 value for flag %s: %s", val, f.Name, err)
}
f.Value = valInt
f.HasBeenSet = true
}
}
for _, name := range f.Names() {
if f.Destination != nil {
set.Uint64Var(f.Destination, name, f.Value, f.Usage)
continue
}
set.Uint64(name, f.Value, f.Usage)
}
return nil
}
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f Uint64Flag) GetValue() string { func (f *Uint64Flag) GetValue() string {
return fmt.Sprintf("%d", f.Value) return fmt.Sprintf("%d", f.Value)
} }
// 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 = 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
}
// Uint64 looks up the value of a local Uint64Flag, returns // Uint64 looks up the value of a local Uint64Flag, returns
// 0 if not found // 0 if not found
func (c *Context) Uint64(name string) uint64 { func (c *Context) Uint64(name string) uint64 {
return lookupUint64(name, c.flagSet) if fs := lookupFlagSet(name, c); fs != nil {
}
// 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 lookupUint64(name, fs)
} }
return 0 return 0

View File

@ -1,6 +1,6 @@
package cli package cli
// BashCompleteFunc is an action to execute when the bash-completion flag is set // BashCompleteFunc is an action to execute when the shell completion flag is set
type BashCompleteFunc func(*Context) type BashCompleteFunc func(*Context)
// BeforeFunc is an action to execute before any subcommands are run, but after // BeforeFunc is an action to execute before any subcommands are run, but after
@ -23,7 +23,7 @@ type CommandNotFoundFunc func(*Context, string)
// is displayed and the execution is interrupted. // is displayed and the execution is interrupted.
type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error
// ExitErrHandlerFunc is executed if provided in order to handle ExitError values // ExitErrHandlerFunc is executed if provided in order to handle exitError values
// returned by Actions and Before/After functions. // returned by Actions and Before/After functions.
type ExitErrHandlerFunc func(context *Context, err error) type ExitErrHandlerFunc func(context *Context, err error)
@ -33,11 +33,11 @@ type FlagStringFunc func(Flag) string
// FlagNamePrefixFunc is used by the default FlagStringFunc to create prefix // FlagNamePrefixFunc is used by the default FlagStringFunc to create prefix
// text for a flag's full name. // text for a flag's full name.
type FlagNamePrefixFunc func(fullName, placeholder string) string type FlagNamePrefixFunc func(fullName []string, placeholder string) string
// FlagEnvHintFunc is used by the default FlagStringFunc to annotate flag help // FlagEnvHintFunc is used by the default FlagStringFunc to annotate flag help
// with the environment variable details. // with the environment variable details.
type FlagEnvHintFunc func(envVar, str string) string type FlagEnvHintFunc func(envVars []string, str string) string
// FlagFileHintFunc is used by the default FlagStringFunc to annotate flag help // FlagFileHintFunc is used by the default FlagStringFunc to annotate flag help
// with the file path details. // with the file path details.

View File

@ -1,4 +1,4 @@
module github.com/urfave/cli module github.com/urfave/cli/v2
go 1.11 go 1.11

View File

@ -10,7 +10,7 @@ import (
"unicode/utf8" "unicode/utf8"
) )
var helpCommand = Command{ var helpCommand = &Command{
Name: "help", Name: "help",
Aliases: []string{"h"}, Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command", Usage: "Shows a list of commands or help for one command",
@ -26,7 +26,7 @@ var helpCommand = Command{
}, },
} }
var helpSubcommand = Command{ var helpSubcommand = &Command{
Name: "help", Name: "help",
Aliases: []string{"h"}, Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command", Usage: "Shows a list of commands or help for one command",
@ -97,7 +97,7 @@ func DefaultAppComplete(c *Context) {
DefaultCompleteWithFlags(nil)(c) DefaultCompleteWithFlags(nil)(c)
} }
func printCommandSuggestions(commands []Command, writer io.Writer) { func printCommandSuggestions(commands []*Command, writer io.Writer) {
for _, command := range commands { for _, command := range commands {
if command.Hidden { if command.Hidden {
continue continue
@ -135,10 +135,10 @@ func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) {
cur := strings.TrimPrefix(lastArg, "-") cur := strings.TrimPrefix(lastArg, "-")
cur = strings.TrimPrefix(cur, "-") cur = strings.TrimPrefix(cur, "-")
for _, flag := range flags { for _, flag := range flags {
if bflag, ok := flag.(BoolFlag); ok && bflag.Hidden { if bflag, ok := flag.(*BoolFlag); ok && bflag.Hidden {
continue continue
} }
for _, name := range strings.Split(flag.GetName(), ",") { for _, name := range flag.Names() {
name = strings.TrimSpace(name) name = strings.TrimSpace(name)
// this will get total count utf8 letters in flag name // this will get total count utf8 letters in flag name
count := utf8.RuneCountInString(name) count := utf8.RuneCountInString(name)
@ -151,7 +151,7 @@ func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) {
continue continue
} }
// match if last argument matches this flag and it is not repeated // match if last argument matches this flag and it is not repeated
if strings.HasPrefix(name, cur) && cur != name && !cliArgContains(flag.GetName()) { if strings.HasPrefix(name, cur) && cur != name && !cliArgContains(name) {
flagCompletion := fmt.Sprintf("%s%s", strings.Repeat("-", count), name) flagCompletion := fmt.Sprintf("%s%s", strings.Repeat("-", count), name)
_, _ = fmt.Fprintln(writer, flagCompletion) _, _ = fmt.Fprintln(writer, flagCompletion)
} }
@ -207,7 +207,7 @@ func ShowCommandHelp(ctx *Context, command string) error {
} }
if ctx.App.CommandNotFound == nil { if ctx.App.CommandNotFound == nil {
return NewExitError(fmt.Sprintf("No help topic for '%v'", command), 3) return Exit(fmt.Sprintf("No help topic for '%v'", command), 3)
} }
ctx.App.CommandNotFound(ctx, command) ctx.App.CommandNotFound(ctx, command)
@ -216,9 +216,17 @@ func ShowCommandHelp(ctx *Context, command string) error {
// ShowSubcommandHelp prints help for the given subcommand // ShowSubcommandHelp prints help for the given subcommand
func ShowSubcommandHelp(c *Context) error { func ShowSubcommandHelp(c *Context) error {
if c == nil {
return nil
}
if c.Command != nil {
return ShowCommandHelp(c, c.Command.Name) return ShowCommandHelp(c, c.Command.Name)
} }
return ShowCommandHelp(c, "")
}
// ShowVersion prints the version number of the App // ShowVersion prints the version number of the App
func ShowVersion(c *Context) { func ShowVersion(c *Context) {
VersionPrinter(c) VersionPrinter(c)
@ -263,6 +271,7 @@ func printHelpCustom(out io.Writer, templ string, data interface{}, customFuncs
w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0) w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0)
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
err := t.Execute(w, data) err := t.Execute(w, data)
if err != nil { if err != nil {
// If the writer is closed, t.Execute will fail, and there's nothing // If the writer is closed, t.Execute will fail, and there's nothing
@ -281,24 +290,20 @@ func printHelp(out io.Writer, templ string, data interface{}) {
func checkVersion(c *Context) bool { func checkVersion(c *Context) bool {
found := false found := false
if VersionFlag.GetName() != "" { for _, name := range VersionFlag.Names() {
eachName(VersionFlag.GetName(), func(name string) { if c.Bool(name) {
if c.GlobalBool(name) || c.Bool(name) {
found = true found = true
} }
})
} }
return found return found
} }
func checkHelp(c *Context) bool { func checkHelp(c *Context) bool {
found := false found := false
if HelpFlag.GetName() != "" { for _, name := range HelpFlag.Names() {
eachName(HelpFlag.GetName(), func(name string) { if c.Bool(name) {
if c.GlobalBool(name) || c.Bool(name) {
found = true found = true
} }
})
} }
return found return found
} }
@ -329,7 +334,7 @@ func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) {
pos := len(arguments) - 1 pos := len(arguments) - 1
lastArg := arguments[pos] lastArg := arguments[pos]
if lastArg != "--"+BashCompletionFlag.GetName() { if lastArg != "--generate-bash-completion" {
return false, arguments return false, arguments
} }

View File

@ -14,10 +14,15 @@ type iterativeParser interface {
// iteratively catch parsing errors. This way we achieve LR parsing without // iteratively catch parsing errors. This way we achieve LR parsing without
// transforming any arguments. Otherwise, there is no way we can discriminate // transforming any arguments. Otherwise, there is no way we can discriminate
// combined short options from common arguments that should be left untouched. // combined short options from common arguments that should be left untouched.
func parseIter(set *flag.FlagSet, ip iterativeParser, args []string) error { // Pass `shellComplete` to continue parsing options on failure during shell
// completion when, the user-supplied options may be incomplete.
func parseIter(set *flag.FlagSet, ip iterativeParser, args []string, shellComplete bool) error {
for { for {
err := set.Parse(args) err := set.Parse(args)
if !ip.useShortOptionHandling() || err == nil { if !ip.useShortOptionHandling() || err == nil {
if shellComplete {
return nil
}
return err return err
} }

View File

@ -20,7 +20,6 @@ AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}:
{{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}} {{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}}
COMMANDS:{{range .VisibleCategories}}{{if .Name}} COMMANDS:{{range .VisibleCategories}}{{if .Name}}
{{.Name}}:{{range .VisibleCommands}} {{.Name}}:{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}} {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlags}} {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
@ -63,7 +62,6 @@ USAGE:
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}} {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}
COMMANDS:{{range .VisibleCategories}}{{if .Name}} COMMANDS:{{range .VisibleCategories}}{{if .Name}}
{{.Name}}:{{range .VisibleCommands}} {{.Name}}:{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}} {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}} {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
@ -73,9 +71,9 @@ OPTIONS:
{{end}}{{end}} {{end}}{{end}}
` `
var MarkdownDocTemplate = `% {{ .App.Name }}(8) {{ .App.Description }} var MarkdownDocTemplate = `% {{ .App.Name }}(8){{ if .App.Description }} {{ .App.Description }}{{ end }}
{{ range $a := .App.Authors }}
% {{ .App.Author }} % {{ $a }}{{ end }}
# NAME # NAME

4
vendor/modules.txt vendored
View File

@ -38,8 +38,8 @@ github.com/src-d/gcfg/token
github.com/src-d/gcfg/types github.com/src-d/gcfg/types
# github.com/stretchr/testify v1.4.0 # github.com/stretchr/testify v1.4.0
github.com/stretchr/testify/assert github.com/stretchr/testify/assert
# github.com/urfave/cli v1.22.2 # github.com/urfave/cli/v2 v2.1.1
github.com/urfave/cli github.com/urfave/cli/v2
# github.com/xanzy/ssh-agent v0.2.1 # github.com/xanzy/ssh-agent v0.2.1
github.com/xanzy/ssh-agent github.com/xanzy/ssh-agent
# golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 # golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4