Merge branch 'main' into shift-supported-go
This commit is contained in:
commit
6331954e44
3
.github/workflows/cli.yml
vendored
3
.github/workflows/cli.yml
vendored
@ -47,6 +47,9 @@ jobs:
|
||||
- name: test
|
||||
run: go run internal/build/build.go test
|
||||
|
||||
- name: test urfave-cli-genflags
|
||||
run: make -C cmd/urfave-cli-genflags
|
||||
|
||||
- name: check-binary-size
|
||||
run: go run internal/build/build.go check-binary-size
|
||||
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -9,3 +9,5 @@
|
||||
coverage.txt
|
||||
internal/*/built-example
|
||||
vendor
|
||||
/cmd/urfave-cli-genflags/urfave-cli-genflags
|
||||
*.exe
|
||||
|
2
cli.go
2
cli.go
@ -22,4 +22,4 @@
|
||||
// }
|
||||
package cli
|
||||
|
||||
//go:generate go run internal/genflags/cmd/genflags/main.go
|
||||
//go:generate go run cmd/urfave-cli-genflags/main.go
|
||||
|
21
cmd/urfave-cli-genflags/Makefile
Normal file
21
cmd/urfave-cli-genflags/Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
GOTEST_FLAGS ?= -v --coverprofile main.coverprofile --covermode count --cover github.com/urfave/cli/v2/cmd/urfave-cli-genflags
|
||||
GOBUILD_FLAGS ?= -x
|
||||
|
||||
.PHONY: all
|
||||
all: test build smoke-test
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test $(GOTEST_FLAGS) ./...
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
go build $(GOBUILD_FLAGS) ./...
|
||||
|
||||
.PHONY: smoke-test
|
||||
smoke-test: build
|
||||
./urfave-cli-genflags --help
|
||||
|
||||
.PHONY: show-cover
|
||||
show-cover:
|
||||
go tool cover -func main.coverprofile
|
15
cmd/urfave-cli-genflags/README.md
Normal file
15
cmd/urfave-cli-genflags/README.md
Normal file
@ -0,0 +1,15 @@
|
||||
# urfave-cli-genflags
|
||||
|
||||
This is a tool that is used internally by [urfave/cli] to generate
|
||||
flag types and methods from a YAML input. It intentionally pins
|
||||
usage of `github.com/urfave/cli/v2` to a *release* rather than
|
||||
using the adjacent code so that changes don't result in *this* tool
|
||||
refusing to compile. It's almost like dogfooding?
|
||||
|
||||
## support warning
|
||||
|
||||
This tool is maintained as a sub-project and is not covered by the
|
||||
API and backward compatibility guaranteed by releases of
|
||||
[urfave/cli].
|
||||
|
||||
[urfave/cli]: https://github.com/urfave/cli
|
15
cmd/urfave-cli-genflags/go.mod
Normal file
15
cmd/urfave-cli-genflags/go.mod
Normal file
@ -0,0 +1,15 @@
|
||||
module github.com/urfave/cli/v2/cmd/urfave-cli-genflags
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/urfave/cli/v2 v2.11.2
|
||||
golang.org/x/text v0.3.7
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
)
|
17
cmd/urfave-cli-genflags/go.sum
Normal file
17
cmd/urfave-cli-genflags/go.sum
Normal file
@ -0,0 +1,17 @@
|
||||
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
|
||||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/urfave/cli/v2 v2.11.2 h1:FVfNg4m3vbjbBpLYxW//WjxUoHvJ9TlppXcqY9Q9ZfA=
|
||||
github.com/urfave/cli/v2 v2.11.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
@ -9,12 +9,14 @@ import (
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"syscall"
|
||||
"text/template"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v2/internal/genflags"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@ -22,6 +24,16 @@ const (
|
||||
defaultPackageName = "cli"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed generated.gotmpl
|
||||
TemplateString string
|
||||
|
||||
//go:embed generated_test.gotmpl
|
||||
TestTemplateString string
|
||||
|
||||
titler = cases.Title(language.Und, cases.NoLower)
|
||||
)
|
||||
|
||||
func sh(ctx context.Context, exe string, args ...string) (string, error) {
|
||||
cmd := exec.CommandContext(ctx, exe, args...)
|
||||
cmd.Stderr = os.Stderr
|
||||
@ -92,7 +104,7 @@ func runGenFlags(cCtx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
spec := &genflags.Spec{}
|
||||
spec := &Spec{}
|
||||
if err := yaml.Unmarshal(specBytes, spec); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -123,12 +135,12 @@ func runGenFlags(cCtx *cli.Context) error {
|
||||
spec.UrfaveCLITestNamespace = "cli."
|
||||
}
|
||||
|
||||
genTmpl, err := template.New("gen").Parse(genflags.TemplateString)
|
||||
genTmpl, err := template.New("gen").Parse(TemplateString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
genTestTmpl, err := template.New("gen_test").Parse(genflags.TestTemplateString)
|
||||
genTestTmpl, err := template.New("gen_test").Parse(TestTemplateString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -161,3 +173,120 @@ func runGenFlags(cCtx *cli.Context) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TypeName(goType string, fc *FlagTypeConfig) string {
|
||||
if fc != nil && strings.TrimSpace(fc.TypeName) != "" {
|
||||
return strings.TrimSpace(fc.TypeName)
|
||||
}
|
||||
|
||||
dotSplit := strings.Split(goType, ".")
|
||||
goType = dotSplit[len(dotSplit)-1]
|
||||
|
||||
if strings.HasPrefix(goType, "[]") {
|
||||
return titler.String(strings.TrimPrefix(goType, "[]")) + "SliceFlag"
|
||||
}
|
||||
|
||||
return titler.String(goType) + "Flag"
|
||||
}
|
||||
|
||||
type Spec struct {
|
||||
FlagTypes map[string]*FlagTypeConfig `yaml:"flag_types"`
|
||||
PackageName string `yaml:"package_name"`
|
||||
TestPackageName string `yaml:"test_package_name"`
|
||||
UrfaveCLINamespace string `yaml:"urfave_cli_namespace"`
|
||||
UrfaveCLITestNamespace string `yaml:"urfave_cli_test_namespace"`
|
||||
}
|
||||
|
||||
func (gfs *Spec) SortedFlagTypes() []*FlagType {
|
||||
typeNames := []string{}
|
||||
|
||||
for name := range gfs.FlagTypes {
|
||||
if strings.HasPrefix(name, "[]") {
|
||||
name = strings.TrimPrefix(name, "[]") + "Slice"
|
||||
}
|
||||
|
||||
typeNames = append(typeNames, name)
|
||||
}
|
||||
|
||||
sort.Strings(typeNames)
|
||||
|
||||
ret := make([]*FlagType, len(typeNames))
|
||||
|
||||
for i, typeName := range typeNames {
|
||||
ret[i] = &FlagType{
|
||||
GoType: typeName,
|
||||
Config: gfs.FlagTypes[typeName],
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
type FlagTypeConfig struct {
|
||||
SkipInterfaces []string `yaml:"skip_interfaces"`
|
||||
StructFields []*FlagStructField `yaml:"struct_fields"`
|
||||
TypeName string `yaml:"type_name"`
|
||||
ValuePointer bool `yaml:"value_pointer"`
|
||||
}
|
||||
|
||||
type FlagStructField struct {
|
||||
Name string
|
||||
Type string
|
||||
}
|
||||
|
||||
type FlagType struct {
|
||||
GoType string
|
||||
Config *FlagTypeConfig
|
||||
}
|
||||
|
||||
func (ft *FlagType) StructFields() []*FlagStructField {
|
||||
if ft.Config == nil || ft.Config.StructFields == nil {
|
||||
return []*FlagStructField{}
|
||||
}
|
||||
|
||||
return ft.Config.StructFields
|
||||
}
|
||||
|
||||
func (ft *FlagType) ValuePointer() bool {
|
||||
if ft.Config == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return ft.Config.ValuePointer
|
||||
}
|
||||
|
||||
func (ft *FlagType) TypeName() string {
|
||||
return TypeName(ft.GoType, ft.Config)
|
||||
}
|
||||
|
||||
func (ft *FlagType) GenerateFmtStringerInterface() bool {
|
||||
return ft.skipInterfaceNamed("fmt.Stringer")
|
||||
}
|
||||
|
||||
func (ft *FlagType) GenerateFlagInterface() bool {
|
||||
return ft.skipInterfaceNamed("Flag")
|
||||
}
|
||||
|
||||
func (ft *FlagType) GenerateRequiredFlagInterface() bool {
|
||||
return ft.skipInterfaceNamed("RequiredFlag")
|
||||
}
|
||||
|
||||
func (ft *FlagType) GenerateVisibleFlagInterface() bool {
|
||||
return ft.skipInterfaceNamed("VisibleFlag")
|
||||
}
|
||||
|
||||
func (ft *FlagType) skipInterfaceNamed(name string) bool {
|
||||
if ft.Config == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
lowName := strings.ToLower(name)
|
||||
|
||||
for _, interfaceName := range ft.Config.SkipInterfaces {
|
||||
if strings.ToLower(interfaceName) == lowName {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
@ -1,29 +1,63 @@
|
||||
package genflags_test
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v2/internal/genflags"
|
||||
main "github.com/urfave/cli/v2/cmd/urfave-cli-genflags"
|
||||
)
|
||||
|
||||
func TestTypeName(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
gt string
|
||||
fc *main.FlagTypeConfig
|
||||
expected string
|
||||
}{
|
||||
{gt: "int", fc: nil, expected: "IntFlag"},
|
||||
{gt: "int", fc: &main.FlagTypeConfig{}, expected: "IntFlag"},
|
||||
{gt: "int", fc: &main.FlagTypeConfig{TypeName: "VeryIntyFlag"}, expected: "VeryIntyFlag"},
|
||||
{gt: "[]bool", fc: nil, expected: "BoolSliceFlag"},
|
||||
{gt: "[]bool", fc: &main.FlagTypeConfig{}, expected: "BoolSliceFlag"},
|
||||
{gt: "[]bool", fc: &main.FlagTypeConfig{TypeName: "ManyTruthsFlag"}, expected: "ManyTruthsFlag"},
|
||||
{gt: "time.Rumination", fc: nil, expected: "RuminationFlag"},
|
||||
{gt: "time.Rumination", fc: &main.FlagTypeConfig{}, expected: "RuminationFlag"},
|
||||
{gt: "time.Rumination", fc: &main.FlagTypeConfig{TypeName: "PonderFlag"}, expected: "PonderFlag"},
|
||||
} {
|
||||
t.Run(
|
||||
fmt.Sprintf("type=%s,cfg=%v", tc.gt, func() string {
|
||||
if tc.fc != nil {
|
||||
return tc.fc.TypeName
|
||||
}
|
||||
return "nil"
|
||||
}()),
|
||||
func(ct *testing.T) {
|
||||
actual := main.TypeName(tc.gt, tc.fc)
|
||||
if tc.expected != actual {
|
||||
ct.Errorf("expected %q, got %q", tc.expected, actual)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSpec_SortedFlagTypes(t *testing.T) {
|
||||
spec := &genflags.Spec{
|
||||
FlagTypes: map[string]*genflags.FlagTypeConfig{
|
||||
"nerf": &genflags.FlagTypeConfig{},
|
||||
spec := &main.Spec{
|
||||
FlagTypes: map[string]*main.FlagTypeConfig{
|
||||
"nerf": &main.FlagTypeConfig{},
|
||||
"gerf": nil,
|
||||
},
|
||||
}
|
||||
|
||||
actual := spec.SortedFlagTypes()
|
||||
expected := []*genflags.FlagType{
|
||||
expected := []*main.FlagType{
|
||||
{
|
||||
GoType: "gerf",
|
||||
Config: nil,
|
||||
},
|
||||
{
|
||||
GoType: "nerf",
|
||||
Config: &genflags.FlagTypeConfig{},
|
||||
Config: &main.FlagTypeConfig{},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
@ -31,12 +65,12 @@ func TestSpec_SortedFlagTypes(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func genFlagType() *genflags.FlagType {
|
||||
return &genflags.FlagType{
|
||||
func genFlagType() *main.FlagType {
|
||||
return &main.FlagType{
|
||||
GoType: "blerf",
|
||||
Config: &genflags.FlagTypeConfig{
|
||||
Config: &main.FlagTypeConfig{
|
||||
SkipInterfaces: []string{"fmt.Stringer"},
|
||||
StructFields: []*genflags.FlagStructField{
|
||||
StructFields: []*main.FlagStructField{
|
||||
{
|
||||
Name: "Foibles",
|
||||
Type: "int",
|
@ -95,7 +95,7 @@ The built-in `go generate` command is used to run the commands specified in
|
||||
line help system which may be consulted for further information, e.g.:
|
||||
|
||||
```sh
|
||||
go run internal/genflags/cmd/genflags/main.go --help
|
||||
go run cmd/urfave-cli-genflags/main.go --help
|
||||
```
|
||||
|
||||
#### docs output
|
||||
|
@ -1,6 +1,6 @@
|
||||
# NOTE: this file is used by the tool defined in
|
||||
# ./internal/genflags/cmd/genflags/main.go which uses the
|
||||
# `genflags.Spec` type that maps to this file structure.
|
||||
# ./cmd/urfave-cli-genflags/main.go which uses the
|
||||
# `Spec` type that maps to this file structure.
|
||||
|
||||
flag_types:
|
||||
bool: {}
|
||||
|
55
flag.go
55
flag.go
@ -7,7 +7,6 @@ import (
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
@ -318,53 +317,6 @@ func stringifyFlag(f Flag) string {
|
||||
fmt.Sprintf("%s\t%s", prefixedNames(df.Names(), placeholder), usageWithDefault))
|
||||
}
|
||||
|
||||
func stringifyIntSliceFlag(f *IntSliceFlag) string {
|
||||
var defaultVals []string
|
||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
||||
for _, i := range f.Value.Value() {
|
||||
defaultVals = append(defaultVals, strconv.Itoa(i))
|
||||
}
|
||||
}
|
||||
|
||||
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
|
||||
}
|
||||
|
||||
func stringifyInt64SliceFlag(f *Int64SliceFlag) string {
|
||||
var defaultVals []string
|
||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
||||
for _, i := range f.Value.Value() {
|
||||
defaultVals = append(defaultVals, strconv.FormatInt(i, 10))
|
||||
}
|
||||
}
|
||||
|
||||
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
|
||||
}
|
||||
|
||||
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
|
||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
||||
for _, s := range f.Value.Value() {
|
||||
if len(s) > 0 {
|
||||
defaultVals = append(defaultVals, strconv.Quote(s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
|
||||
}
|
||||
|
||||
func stringifySliceFlag(usage string, names, defaultVals []string) string {
|
||||
placeholder, usage := unquoteUsage(usage)
|
||||
if placeholder == "" {
|
||||
@ -377,11 +329,8 @@ func stringifySliceFlag(usage string, names, defaultVals []string) string {
|
||||
}
|
||||
|
||||
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal))
|
||||
multiInputString := "(accepts multiple inputs)"
|
||||
if usageWithDefault != "" {
|
||||
multiInputString = "\t" + multiInputString
|
||||
}
|
||||
return fmt.Sprintf("%s\t%s%s", prefixedNames(names, placeholder), usageWithDefault, multiInputString)
|
||||
pn := prefixedNames(names, placeholder)
|
||||
return fmt.Sprintf("%s [ %s ]\t%s", pn, pn, usageWithDefault)
|
||||
}
|
||||
|
||||
func hasFlag(flags []Flag, fl Flag) bool {
|
||||
|
@ -83,7 +83,7 @@ func (f *Float64Slice) Get() interface{} {
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f *Float64SliceFlag) String() string {
|
||||
return withEnvHint(f.GetEnvVars(), stringifyFloat64SliceFlag(f))
|
||||
return withEnvHint(f.GetEnvVars(), f.stringify())
|
||||
}
|
||||
|
||||
// TakesValue returns true if the flag takes a value, otherwise false
|
||||
@ -169,6 +169,18 @@ func (f *Float64SliceFlag) Get(ctx *Context) []float64 {
|
||||
return ctx.Float64Slice(f.Name)
|
||||
}
|
||||
|
||||
func (f *Float64SliceFlag) stringify() 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)
|
||||
}
|
||||
|
||||
// Float64Slice looks up the value of a local Float64SliceFlag, returns
|
||||
// nil if not found
|
||||
func (cCtx *Context) Float64Slice(name string) []float64 {
|
||||
|
@ -84,7 +84,7 @@ func (i *Int64Slice) Get() interface{} {
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f *Int64SliceFlag) String() string {
|
||||
return withEnvHint(f.GetEnvVars(), stringifyInt64SliceFlag(f))
|
||||
return withEnvHint(f.GetEnvVars(), f.stringify())
|
||||
}
|
||||
|
||||
// TakesValue returns true of the flag takes a value, otherwise false
|
||||
@ -168,6 +168,17 @@ func (f *Int64SliceFlag) Get(ctx *Context) []int64 {
|
||||
return ctx.Int64Slice(f.Name)
|
||||
}
|
||||
|
||||
func (f *Int64SliceFlag) stringify() string {
|
||||
var defaultVals []string
|
||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
||||
for _, i := range f.Value.Value() {
|
||||
defaultVals = append(defaultVals, strconv.FormatInt(i, 10))
|
||||
}
|
||||
}
|
||||
|
||||
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
|
||||
}
|
||||
|
||||
// Int64Slice looks up the value of a local Int64SliceFlag, returns
|
||||
// nil if not found
|
||||
func (cCtx *Context) Int64Slice(name string) []int64 {
|
||||
|
@ -95,7 +95,7 @@ func (i *IntSlice) Get() interface{} {
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f *IntSliceFlag) String() string {
|
||||
return withEnvHint(f.GetEnvVars(), stringifyIntSliceFlag(f))
|
||||
return withEnvHint(f.GetEnvVars(), f.stringify())
|
||||
}
|
||||
|
||||
// TakesValue returns true of the flag takes a value, otherwise false
|
||||
@ -179,6 +179,17 @@ func (f *IntSliceFlag) Get(ctx *Context) []int {
|
||||
return ctx.IntSlice(f.Name)
|
||||
}
|
||||
|
||||
func (f *IntSliceFlag) stringify() string {
|
||||
var defaultVals []string
|
||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
||||
for _, i := range f.Value.Value() {
|
||||
defaultVals = append(defaultVals, strconv.Itoa(i))
|
||||
}
|
||||
}
|
||||
|
||||
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
|
||||
}
|
||||
|
||||
// IntSlice looks up the value of a local IntSliceFlag, returns
|
||||
// nil if not found
|
||||
func (cCtx *Context) IntSlice(name string) []int {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -73,7 +74,7 @@ func (s *StringSlice) Get() interface{} {
|
||||
// String returns a readable representation of this value
|
||||
// (for usage defaults)
|
||||
func (f *StringSliceFlag) String() string {
|
||||
return withEnvHint(f.GetEnvVars(), stringifyStringSliceFlag(f))
|
||||
return withEnvHint(f.GetEnvVars(), f.stringify())
|
||||
}
|
||||
|
||||
// TakesValue returns true of the flag takes a value, otherwise false
|
||||
@ -157,6 +158,19 @@ func (f *StringSliceFlag) Get(ctx *Context) []string {
|
||||
return ctx.StringSlice(f.Name)
|
||||
}
|
||||
|
||||
func (f *StringSliceFlag) stringify() string {
|
||||
var defaultVals []string
|
||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
||||
for _, s := range f.Value.Value() {
|
||||
if len(s) > 0 {
|
||||
defaultVals = append(defaultVals, strconv.Quote(s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
|
||||
}
|
||||
|
||||
// StringSlice looks up the value of a local StringSliceFlag, returns
|
||||
// nil if not found
|
||||
func (cCtx *Context) StringSlice(name string) []string {
|
||||
|
36
flag_test.go
36
flag_test.go
@ -558,11 +558,11 @@ var stringSliceFlagTests = []struct {
|
||||
value *StringSlice
|
||||
expected string
|
||||
}{
|
||||
{"foo", nil, NewStringSlice(""), "--foo value\t(accepts multiple inputs)"},
|
||||
{"f", nil, NewStringSlice(""), "-f value\t(accepts multiple inputs)"},
|
||||
{"f", nil, NewStringSlice("Lipstick"), "-f value\t(default: \"Lipstick\")\t(accepts multiple inputs)"},
|
||||
{"test", nil, NewStringSlice("Something"), "--test value\t(default: \"Something\")\t(accepts multiple inputs)"},
|
||||
{"dee", []string{"d"}, NewStringSlice("Inka", "Dinka", "dooo"), "--dee value, -d value\t(default: \"Inka\", \"Dinka\", \"dooo\")\t(accepts multiple inputs)"},
|
||||
{"foo", nil, NewStringSlice(""), "--foo value [ --foo value ]\t"},
|
||||
{"f", nil, NewStringSlice(""), "-f value [ -f value ]\t"},
|
||||
{"f", nil, NewStringSlice("Lipstick"), "-f value [ -f value ]\t(default: \"Lipstick\")"},
|
||||
{"test", nil, NewStringSlice("Something"), "--test value [ --test value ]\t(default: \"Something\")"},
|
||||
{"dee", []string{"d"}, NewStringSlice("Inka", "Dinka", "dooo"), "--dee value, -d value [ --dee value, -d value ]\t(default: \"Inka\", \"Dinka\", \"dooo\")"},
|
||||
}
|
||||
|
||||
func TestStringSliceFlagHelpOutput(t *testing.T) {
|
||||
@ -911,9 +911,9 @@ var intSliceFlagTests = []struct {
|
||||
value *IntSlice
|
||||
expected string
|
||||
}{
|
||||
{"heads", nil, NewIntSlice(), "--heads value\t(accepts multiple inputs)"},
|
||||
{"H", nil, NewIntSlice(), "-H value\t(accepts multiple inputs)"},
|
||||
{"H", []string{"heads"}, NewIntSlice(9, 3), "-H value, --heads value\t(default: 9, 3)\t(accepts multiple inputs)"},
|
||||
{"heads", nil, NewIntSlice(), "--heads value [ --heads value ]\t"},
|
||||
{"H", nil, NewIntSlice(), "-H value [ -H value ]\t"},
|
||||
{"H", []string{"heads"}, NewIntSlice(9, 3), "-H value, --heads value [ -H value, --heads value ]\t(default: 9, 3)"},
|
||||
}
|
||||
|
||||
func TestIntSliceFlagHelpOutput(t *testing.T) {
|
||||
@ -1008,10 +1008,10 @@ var int64SliceFlagTests = []struct {
|
||||
value *Int64Slice
|
||||
expected string
|
||||
}{
|
||||
{"heads", nil, NewInt64Slice(), "--heads value\t(accepts multiple inputs)"},
|
||||
{"H", nil, NewInt64Slice(), "-H value\t(accepts multiple inputs)"},
|
||||
{"heads", nil, NewInt64Slice(), "--heads value [ --heads value ]\t"},
|
||||
{"H", nil, NewInt64Slice(), "-H value [ -H value ]\t"},
|
||||
{"heads", []string{"H"}, NewInt64Slice(int64(2), int64(17179869184)),
|
||||
"--heads value, -H value\t(default: 2, 17179869184)\t(accepts multiple inputs)"},
|
||||
"--heads value, -H value [ --heads value, -H value ]\t(default: 2, 17179869184)"},
|
||||
}
|
||||
|
||||
func TestInt64SliceFlagHelpOutput(t *testing.T) {
|
||||
@ -1169,10 +1169,10 @@ var float64SliceFlagTests = []struct {
|
||||
value *Float64Slice
|
||||
expected string
|
||||
}{
|
||||
{"heads", nil, NewFloat64Slice(), "--heads value\t(accepts multiple inputs)"},
|
||||
{"H", nil, NewFloat64Slice(), "-H value\t(accepts multiple inputs)"},
|
||||
{"heads", nil, NewFloat64Slice(), "--heads value [ --heads value ]\t"},
|
||||
{"H", nil, NewFloat64Slice(), "-H value [ -H value ]\t"},
|
||||
{"heads", []string{"H"}, NewFloat64Slice(0.1234, -10.5),
|
||||
"--heads value, -H value\t(default: 0.1234, -10.5)\t(accepts multiple inputs)"},
|
||||
"--heads value, -H value [ --heads value, -H value ]\t(default: 0.1234, -10.5)"},
|
||||
}
|
||||
|
||||
func TestFloat64SliceFlagHelpOutput(t *testing.T) {
|
||||
@ -2398,25 +2398,25 @@ func TestFlagDefaultValue(t *testing.T) {
|
||||
name: "stringSclice",
|
||||
flag: &StringSliceFlag{Name: "flag", Value: NewStringSlice("default1", "default2")},
|
||||
toParse: []string{"--flag", "parsed"},
|
||||
expect: `--flag value (default: "default1", "default2") (accepts multiple inputs)`,
|
||||
expect: `--flag value [ --flag value ] (default: "default1", "default2")`,
|
||||
},
|
||||
{
|
||||
name: "float64Sclice",
|
||||
flag: &Float64SliceFlag{Name: "flag", Value: NewFloat64Slice(1.1, 2.2)},
|
||||
toParse: []string{"--flag", "13.3"},
|
||||
expect: `--flag value (default: 1.1, 2.2) (accepts multiple inputs)`,
|
||||
expect: `--flag value [ --flag value ] (default: 1.1, 2.2)`,
|
||||
},
|
||||
{
|
||||
name: "int64Sclice",
|
||||
flag: &Int64SliceFlag{Name: "flag", Value: NewInt64Slice(1, 2)},
|
||||
toParse: []string{"--flag", "13"},
|
||||
expect: `--flag value (default: 1, 2) (accepts multiple inputs)`,
|
||||
expect: `--flag value [ --flag value ] (default: 1, 2)`,
|
||||
},
|
||||
{
|
||||
name: "intSclice",
|
||||
flag: &IntSliceFlag{Name: "flag", Value: NewIntSlice(1, 2)},
|
||||
toParse: []string{"--flag", "13"},
|
||||
expect: `--flag value (default: 1, 2) (accepts multiple inputs)`,
|
||||
expect: `--flag value [ --flag value ] (default: 1, 2)`,
|
||||
},
|
||||
{
|
||||
name: "string",
|
||||
|
1
go.mod
1
go.mod
@ -6,7 +6,6 @@ require (
|
||||
github.com/BurntSushi/toml v1.1.0
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673
|
||||
golang.org/x/text v0.3.7
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
|
6
go.sum
6
go.sum
@ -1,17 +1,11 @@
|
||||
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
|
||||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
@ -94,7 +94,7 @@ func main() {
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "packages",
|
||||
Value: cli.NewStringSlice("cli", "altsrc", "internal/build", "internal/genflags"),
|
||||
Value: cli.NewStringSlice("cli", "altsrc", "internal/build"),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1,34 +0,0 @@
|
||||
package genflags
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed generated.gotmpl
|
||||
TemplateString string
|
||||
|
||||
//go:embed generated_test.gotmpl
|
||||
TestTemplateString string
|
||||
|
||||
titler = cases.Title(language.Und, cases.NoLower)
|
||||
)
|
||||
|
||||
func TypeName(goType string, fc *FlagTypeConfig) string {
|
||||
if fc != nil && strings.TrimSpace(fc.TypeName) != "" {
|
||||
return strings.TrimSpace(fc.TypeName)
|
||||
}
|
||||
|
||||
dotSplit := strings.Split(goType, ".")
|
||||
goType = dotSplit[len(dotSplit)-1]
|
||||
|
||||
if strings.HasPrefix(goType, "[]") {
|
||||
return titler.String(strings.TrimPrefix(goType, "[]")) + "SliceFlag"
|
||||
}
|
||||
|
||||
return titler.String(goType) + "Flag"
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package genflags_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v2/internal/genflags"
|
||||
)
|
||||
|
||||
func TestTypeName(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
gt string
|
||||
fc *genflags.FlagTypeConfig
|
||||
expected string
|
||||
}{
|
||||
{gt: "int", fc: nil, expected: "IntFlag"},
|
||||
{gt: "int", fc: &genflags.FlagTypeConfig{}, expected: "IntFlag"},
|
||||
{gt: "int", fc: &genflags.FlagTypeConfig{TypeName: "VeryIntyFlag"}, expected: "VeryIntyFlag"},
|
||||
{gt: "[]bool", fc: nil, expected: "BoolSliceFlag"},
|
||||
{gt: "[]bool", fc: &genflags.FlagTypeConfig{}, expected: "BoolSliceFlag"},
|
||||
{gt: "[]bool", fc: &genflags.FlagTypeConfig{TypeName: "ManyTruthsFlag"}, expected: "ManyTruthsFlag"},
|
||||
{gt: "time.Rumination", fc: nil, expected: "RuminationFlag"},
|
||||
{gt: "time.Rumination", fc: &genflags.FlagTypeConfig{}, expected: "RuminationFlag"},
|
||||
{gt: "time.Rumination", fc: &genflags.FlagTypeConfig{TypeName: "PonderFlag"}, expected: "PonderFlag"},
|
||||
} {
|
||||
t.Run(
|
||||
fmt.Sprintf("type=%s,cfg=%v", tc.gt, func() string {
|
||||
if tc.fc != nil {
|
||||
return tc.fc.TypeName
|
||||
}
|
||||
return "nil"
|
||||
}()),
|
||||
func(ct *testing.T) {
|
||||
actual := genflags.TypeName(tc.gt, tc.fc)
|
||||
if tc.expected != actual {
|
||||
ct.Errorf("expected %q, got %q", tc.expected, actual)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
package genflags
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Spec struct {
|
||||
FlagTypes map[string]*FlagTypeConfig `yaml:"flag_types"`
|
||||
PackageName string `yaml:"package_name"`
|
||||
TestPackageName string `yaml:"test_package_name"`
|
||||
UrfaveCLINamespace string `yaml:"urfave_cli_namespace"`
|
||||
UrfaveCLITestNamespace string `yaml:"urfave_cli_test_namespace"`
|
||||
}
|
||||
|
||||
func (gfs *Spec) SortedFlagTypes() []*FlagType {
|
||||
typeNames := []string{}
|
||||
|
||||
for name := range gfs.FlagTypes {
|
||||
if strings.HasPrefix(name, "[]") {
|
||||
name = strings.TrimPrefix(name, "[]") + "Slice"
|
||||
}
|
||||
|
||||
typeNames = append(typeNames, name)
|
||||
}
|
||||
|
||||
sort.Strings(typeNames)
|
||||
|
||||
ret := make([]*FlagType, len(typeNames))
|
||||
|
||||
for i, typeName := range typeNames {
|
||||
ret[i] = &FlagType{
|
||||
GoType: typeName,
|
||||
Config: gfs.FlagTypes[typeName],
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
type FlagTypeConfig struct {
|
||||
SkipInterfaces []string `yaml:"skip_interfaces"`
|
||||
StructFields []*FlagStructField `yaml:"struct_fields"`
|
||||
TypeName string `yaml:"type_name"`
|
||||
ValuePointer bool `yaml:"value_pointer"`
|
||||
}
|
||||
|
||||
type FlagStructField struct {
|
||||
Name string
|
||||
Type string
|
||||
}
|
||||
|
||||
type FlagType struct {
|
||||
GoType string
|
||||
Config *FlagTypeConfig
|
||||
}
|
||||
|
||||
func (ft *FlagType) StructFields() []*FlagStructField {
|
||||
if ft.Config == nil || ft.Config.StructFields == nil {
|
||||
return []*FlagStructField{}
|
||||
}
|
||||
|
||||
return ft.Config.StructFields
|
||||
}
|
||||
|
||||
func (ft *FlagType) ValuePointer() bool {
|
||||
if ft.Config == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return ft.Config.ValuePointer
|
||||
}
|
||||
|
||||
func (ft *FlagType) TypeName() string {
|
||||
return TypeName(ft.GoType, ft.Config)
|
||||
}
|
||||
|
||||
func (ft *FlagType) GenerateFmtStringerInterface() bool {
|
||||
return ft.skipInterfaceNamed("fmt.Stringer")
|
||||
}
|
||||
|
||||
func (ft *FlagType) GenerateFlagInterface() bool {
|
||||
return ft.skipInterfaceNamed("Flag")
|
||||
}
|
||||
|
||||
func (ft *FlagType) GenerateRequiredFlagInterface() bool {
|
||||
return ft.skipInterfaceNamed("RequiredFlag")
|
||||
}
|
||||
|
||||
func (ft *FlagType) GenerateVisibleFlagInterface() bool {
|
||||
return ft.skipInterfaceNamed("VisibleFlag")
|
||||
}
|
||||
|
||||
func (ft *FlagType) skipInterfaceNamed(name string) bool {
|
||||
if ft.Config == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
lowName := strings.ToLower(name)
|
||||
|
||||
for _, interfaceName := range ft.Config.SkipInterfaces {
|
||||
if strings.ToLower(interfaceName) == lowName {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
Loading…
Reference in New Issue
Block a user