Add DestinationPointer for flags generator

In this commit I added a DestinationPointer variable that should be set
if the `Destination` should be configured as a pointer for a specific
flag type. It is expected that Generic type which is an interface will
not be a pointer but a struct. Before this change the code compilation
was failing with `type *Generic is pointer to interface, not interface`.

See https://github.com/urfave/cli/issues/1441
This commit is contained in:
Jakub Nowakowski 2022-07-26 16:13:05 +02:00 committed by Naveen Gogineni
parent b68db8d010
commit 891ffb017b
4 changed files with 166 additions and 2 deletions

View File

@ -17,7 +17,11 @@ type {{.TypeName}} struct {
HasBeenSet bool
Value {{if .ValuePointer}}*{{end}}{{.GoType}}
<<<<<<< HEAD:cmd/urfave-cli-genflags/generated.gotmpl
Destination {{if .NoDestinationPointer}}{{else}}*{{end}}{{.GoType}}
=======
Destination {{if .DestinationPointer}}*{{end}}{{.GoType}}
>>>>>>> Add DestinationPointer for flags generator:internal/genflags/generated.gotmpl
Aliases []string
EnvVars []string

View File

@ -80,8 +80,9 @@ func genFlagType() *main.FlagType {
Type: "bool",
},
},
TypeName: "YeOldeBlerfFlag",
ValuePointer: true,
TypeName: "YeOldeBlerfFlag",
ValuePointer: true,
DestinationPointer: true,
},
}
}
@ -115,6 +116,21 @@ func TestFlagType_ValuePointer(t *testing.T) {
}
}
func TestFlagType_DestinationPointer(t *testing.T) {
ft := genFlagType()
if !ft.DestinationPointer() {
t.Errorf("expected DestinationPointer to be true")
return
}
ft.Config = nil
if ft.DestinationPointer() {
t.Errorf("expected DestinationPointer to be false")
}
}
func TestFlagType_GenerateFmtStringerInterface(t *testing.T) {
ft := genFlagType()

View File

@ -2,6 +2,7 @@
# ./cmd/urfave-cli-genflags/main.go which uses the
# `Spec` type that maps to this file structure.
flag_types:
<<<<<<< HEAD
bool:
struct_fields:
- name: Count
@ -13,8 +14,30 @@ flag_types:
struct_fields:
- name: Action
type: "func(*Context, float64) error"
=======
bool: {}
float64: {}
int64: {}
int: {}
time.Duration: {}
uint64: {}
uint: {}
string:
destination_pointer: true
struct_fields:
- { name: TakesFile, type: bool }
Generic:
struct_fields:
- { name: TakesFile, type: bool }
Path:
destination_pointer: true
struct_fields:
- { name: TakesFile, type: bool }
>>>>>>> Add DestinationPointer for flags generator
Float64Slice:
value_pointer: true
destination_pointer: true
skip_interfaces:
- fmt.Stringer
struct_fields:
@ -41,6 +64,7 @@ flag_types:
type: "func(*Context, int64) error"
Int64Slice:
value_pointer: true
destination_pointer: true
skip_interfaces:
- fmt.Stringer
struct_fields:
@ -54,6 +78,7 @@ flag_types:
type: "func(*Context, uint) error"
UintSlice:
value_pointer: true
destination_pointer: true
skip_interfaces:
- fmt.Stringer
struct_fields:
@ -80,6 +105,7 @@ flag_types:
type: "func(*Context, string) error"
StringSlice:
value_pointer: true
destination_pointer: true
skip_interfaces:
- fmt.Stringer
struct_fields:
@ -93,6 +119,7 @@ flag_types:
type: "func(*Context, time.Duration) error"
Timestamp:
value_pointer: true
destination_pointer: true
struct_fields:
- name: Layout
type: string

117
internal/genflags/spec.go Normal file
View File

@ -0,0 +1,117 @@
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"`
DestinationPointer bool `yaml:"destination_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) DestinationPointer() bool {
if ft.Config == nil {
return false
}
return ft.Config.DestinationPointer
}
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
}