Skip to content

Commit

Permalink
refactor: update flags value by index and help opt for commands
Browse files Browse the repository at this point in the history
  • Loading branch information
joseluisq committed Nov 13, 2020
1 parent 1a440a8 commit 9c5b66b
Show file tree
Hide file tree
Showing 4 changed files with 214 additions and 80 deletions.
154 changes: 121 additions & 33 deletions cline.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,43 +62,54 @@ func New() *App {
return &App{}
}

// validateCommands checks if a command is valid and initialize it
func validateCommands(commands []Cmd) ([]Cmd, error) {
var cmds []Cmd
for _, c := range commands {
name := strings.TrimSpace(c.Name)
if name == "" {
return nil, fmt.Errorf("command name has empty value")
}
cflags, err := validateAndInitFlags(c.Flags)
if err != nil {
return nil, err
}
c.Flags = cflags
cmds = append(cmds, c)
}
return cmds, nil
}

// Run executes the current application.
func (app *App) Run(vArgs []string) error {
// Commands and flags validation

// 1. Check application flags
aflags, err := checkAndInitFlags(app.Flags)
// 1. Check application global flags
vflags, err := validateAndInitFlags(app.Flags)
if err != nil {
return err
}
app.Flags = aflags
app.Flags = vflags

// 2. Check commands and their flags
var cmds []Cmd
for _, c := range app.Commands {
name := strings.ToLower(strings.TrimSpace(c.Name))
if name == "" {
return fmt.Errorf("command name has empty value")
}
cflags, err := checkAndInitFlags(c.Flags)
if err != nil {
return err
}
c.Flags = cflags
cmds = append(cmds, c)
vcmds, err := validateCommands(app.Commands)
if err != nil {
return err
}
app.Commands = cmds
app.Commands = vcmds

// 3. Process commands and flags
var lastCmd Cmd
var lastFlag Flag
var lastFlagIndex int = -1
// var lastCmdFlagList []Flag
var tailArgs []string
var hasCommand = false
var hasCmd = false
var hasHelp = false
var hasVersion = false

for i := 1; i < len(vArgs); i++ {
arg := strings.ToLower(strings.TrimSpace(vArgs[i]))
arg := strings.TrimSpace(vArgs[i])

// Check for no supported arguments (remaining)
if len(tailArgs) > 0 {
Expand All @@ -110,7 +121,7 @@ func (app *App) Run(vArgs []string) error {
if strings.HasPrefix(arg, "-") {
flagKey := strings.TrimPrefix(strings.TrimPrefix(arg, "-"), "-")
// Skip unsupported fags
if strings.HasPrefix(flagKey, "-") {
if flagKey == "" || strings.HasPrefix(flagKey, "-") {
tailArgs = append(tailArgs, arg)
continue
}
Expand All @@ -120,40 +131,73 @@ func (app *App) Run(vArgs []string) error {
case "help", "h":
hasHelp = true
case "version", "v":
hasVersion = true
if !hasCmd {
hasVersion = true
}
}
if hasHelp || hasVersion {
break
}

// Assign flag default values
var flags []Flag
if hasCommand {
if hasCmd {
flags = lastCmd.Flags
} else {
flags = app.Flags
}

// Find argument key flag on flag list
flag := findFlagByKey(flagKey, flags)
i, flag := findFlagByKey(flagKey, flags)
if flag == nil {
return fmt.Errorf("argument `%s` is not recognised", arg)
}
lastFlag = flag
lastFlagIndex = i

switch fl := lastFlag.(type) {
case FlagBool:
if fl.Name != "" {
if fl.zflagAssigned {
tailArgs = append(tailArgs, arg)
continue
}

// If bool flag is defined is assumed as `true`
s := FlagValue("1")
fl.zflag = s
fl.zflagAssigned = true
lastFlag = fl

if hasCmd {
if len(lastCmd.Flags) > 0 && lastFlagIndex > -1 {
lastCmd.Flags[lastFlagIndex] = fl
}
} else {
if len(app.Flags) > 0 && lastFlagIndex > -1 {
app.Flags[lastFlagIndex] = fl
}
}

tailArgs = append(tailArgs, arg)
continue
}
}

continue
}

// 3.2. Commands
// 3.2.1 Check for a valid command (first time)
if !hasCommand {
if !hasCmd {
for _, c := range app.Commands {
if c.Name == arg {
hasCommand = true
hasCmd = true
lastCmd = c
break
}
}
if hasCommand {
if hasCmd {
continue
}
}
Expand All @@ -172,14 +216,24 @@ func (app *App) Run(vArgs []string) error {
tailArgs = append(tailArgs, arg)
continue
}
s := FlagValue(arg)
if _, err := s.Bool(); err == nil {
fl.zflag = s
fl.zflagAssigned = true
lastFlag = fl

// If bool flag is defined is assumed as `true`
s := FlagValue("1")
fl.zflag = s
fl.zflagAssigned = true
lastFlag = fl

if hasCmd {
if len(lastCmd.Flags) > 0 && lastFlagIndex > -1 {
lastCmd.Flags[lastFlagIndex] = fl
}
} else {
tailArgs = append(tailArgs, arg)
if len(app.Flags) > 0 && lastFlagIndex > -1 {
app.Flags[lastFlagIndex] = fl
}
}

tailArgs = append(tailArgs, arg)
continue
}
case FlagInt:
Expand All @@ -193,6 +247,16 @@ func (app *App) Run(vArgs []string) error {
fl.zflag = s
fl.zflagAssigned = true
lastFlag = fl

if hasCmd {
if len(lastCmd.Flags) > 0 && lastFlagIndex > -1 {
lastCmd.Flags[lastFlagIndex] = fl
}
} else {
if len(app.Flags) > 0 && lastFlagIndex > -1 {
app.Flags[lastFlagIndex] = fl
}
}
} else {
tailArgs = append(tailArgs, arg)
}
Expand All @@ -207,6 +271,16 @@ func (app *App) Run(vArgs []string) error {
fl.zflag = FlagValue(arg)
fl.zflagAssigned = true
lastFlag = fl

if hasCmd {
if len(lastCmd.Flags) > 0 && lastFlagIndex > -1 {
lastCmd.Flags[lastFlagIndex] = fl
}
} else {
if len(app.Flags) > 0 && lastFlagIndex > -1 {
app.Flags[lastFlagIndex] = fl
}
}
continue
}
case FlagStringSlice:
Expand All @@ -218,6 +292,16 @@ func (app *App) Run(vArgs []string) error {
fl.zflag = FlagValue(arg)
fl.zflagAssigned = true
lastFlag = fl

if hasCmd {
if len(lastCmd.Flags) > 0 && lastFlagIndex > -1 {
lastCmd.Flags[lastFlagIndex] = fl
}
} else {
if len(app.Flags) > 0 && lastFlagIndex > -1 {
app.Flags[lastFlagIndex] = fl
}
}
continue
}
default:
Expand All @@ -228,7 +312,11 @@ func (app *App) Run(vArgs []string) error {

// Show `help` flag details
if hasHelp {
return app.printHelp()
if hasCmd {
return printHelp(app, &lastCmd)
}

return printHelp(app, nil)
}

// Show `version` flag details
Expand All @@ -238,7 +326,7 @@ func (app *App) Run(vArgs []string) error {
}

// Call command handler
if hasCommand && lastCmd.Handler != nil {
if hasCmd && lastCmd.Handler != nil {
return lastCmd.Handler(&CmdContext{
Cmd: &lastCmd,
Flags: &FlagMapValues{
Expand Down
16 changes: 11 additions & 5 deletions examples/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func main() {
Name: "verbose",
Summary: "Enable more verbose info",
Value: false,
Aliases: []string{"v"},
Aliases: []string{"V"},
EnvVar: "ENV_VERBOSE",
},
}
Expand All @@ -41,10 +41,10 @@ func main() {
Summary: "Show command information",
Flags: []cli.Flag{
cli.FlagInt{
Name: "version",
Summary: "Enable more verbose command information",
Name: "trace",
Summary: "Enable tracing mode",
Value: 10,
Aliases: []string{"z"},
Aliases: []string{"t"},
},
cli.FlagBool{
Name: "detailed",
Expand All @@ -61,6 +61,9 @@ func main() {
os.Exit(1)
}
fmt.Printf("Cmd Flag `version` opted: `%d` (%T)\n", i, i)

d := ctx.Flags.String("detailed")
fmt.Printf("Cmd Flag `detailed` opted: `%s` (%T)\n", d, d)
fmt.Printf("Cmd Tail arguments: %#v\n", ctx.TailArgs)
return nil
},
Expand All @@ -70,7 +73,10 @@ func main() {
fmt.Printf("App `%s` executed!\n", ctx.App.Name)
fmt.Printf("App Tail arguments: %#v\n", ctx.TailArgs)
fmt.Printf("App Flag `file` opted: `%s`\n", ctx.Flags.StringSlice("file"))
fmt.Printf("App Flag `verbose` opted: `%s`\n", ctx.Flags.StringSlice("verbose"))

b, _ := ctx.Flags.Bool("verbose")

fmt.Printf("App Flag `verbose` opted: `%v`\n", b)
return nil
}
if err := app.Run(os.Args); err != nil {
Expand Down
26 changes: 13 additions & 13 deletions flag_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"strings"
)

// checkAndInitFlags checks for a flag and initialize it
func checkAndInitFlags(flags []Flag) ([]Flag, error) {
// validateAndInitFlags checks for a flag and initialize it
func validateAndInitFlags(flags []Flag) ([]Flag, error) {
var sFlags []Flag
for _, v := range flags {
switch f := v.(type) {
Expand Down Expand Up @@ -46,54 +46,54 @@ func checkAndInitFlags(flags []Flag) ([]Flag, error) {
}

// findFlagByKey finds a flag item in a flag's array by key.
func findFlagByKey(key string, flags []Flag) Flag {
for _, f := range flags {
func findFlagByKey(key string, flags []Flag) (int, Flag) {
for i, f := range flags {
switch fl := f.(type) {
case FlagBool:
// Check for long named flags
if key == fl.Name {
return fl
return i, fl
}
// Check for short named flags
for _, s := range fl.Aliases {
if key == s {
return fl
return i, fl
}
}
case FlagInt:
// Check for long named flags
if key == fl.Name {
return fl
return i, fl
}
// Check for short named flags
for _, s := range fl.Aliases {
if key == s {
return fl
return i, fl
}
}
case FlagString:
// Check for long named flags
if key == fl.Name {
return fl
return i, fl
}
// Check for short named flags
for _, s := range fl.Aliases {
if key == s {
return fl
return i, fl
}
}
case FlagStringSlice:
// Check for long named flags
if key == fl.Name {
return fl
return i, fl
}
// Check for short named flags
for _, s := range fl.Aliases {
if key == s {
return fl
return i, fl
}
}
}
}
return nil
return -1, nil
}
Loading

0 comments on commit 9c5b66b

Please sign in to comment.