8000 Fix:(issue_2066) Remove dependency on golang flag library by dearchap · Pull Request #2074 · urfave/cli · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Fix:(issue_2066) Remove dependency on golang flag library #2074

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
Mar 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
866 changes: 51 additions & 815 deletions command.go

Large diffs are not rendered by default.

207 changes: 207 additions & 0 deletions command_parse.go
8000
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
package cli

import (
"fmt"
"strings"
)

const (
providedButNotDefinedErrMsg = "flag provided but not defined: -"
argumentNotProvidedErrMsg = "flag needs an argument: "
)

// flagFromError tries to parse a provided flag from an error message. If the
// parsing fails, it returns the input error and an empty string
func flagFromError(err error) (string, error) {
errStr := err.Error()
trimmed := strings.TrimPrefix(errStr, providedButNotDefinedErrMsg)
if errStr == trimmed {
return "", err
}
return trimmed, nil
}

func (cmd *Command) parseFlags(args Args) (Args, error) {
tracef("parsing flags from arguments %[1]q (cmd=%[2]q)", args, cmd.Name)

cmd.setFlags = map[Flag]struct{}{}
cmd.appliedFlags = cmd.allFlags()

tracef("walking command lineage for persistent flags (cmd=%[1]q)", cmd.Name)

for pCmd := cmd.parent; pCmd != nil; pCmd = pCmd.parent {
tracef(
"checking ancestor command=%[1]q for persistent flags (cmd=%[2]q)",
pCmd.Name, cmd.Name,
)

for _, fl := range pCmd.Flags {
flNames := fl.Names()

pfl, ok := fl.(LocalFlag)
if !ok || pfl.IsLocal() {
tracef("skipping non-persistent flag %[1]q (cmd=%[2]q)", flNames, cmd.Name)
continue
}

tracef(
"checking for applying persistent flag=%[1]q pCmd=%[2]q (cmd=%[3]q)",
flNames, pCmd.Name, cmd.Name,
)

applyPersistentFlag := true

for _, name := range flNames {
if cmd.lFlag(name) != nil {
applyPersistentFlag = false
break
}
}

if !applyPersistentFlag {
tracef("not applying as persistent flag=%[1]q (cmd=%[2]q)", flNames, cmd.Name)
continue
}

tracef("applying as persistent flag=%[1]q (cmd=%[2]q)", flNames, cmd.Name)

tracef("appending to applied flags flag=%[1]q (cmd=%[2]q)", flNames, cmd.Name)
cmd.appliedFlags = append(cmd.appliedFlags, fl)
}
}

tracef("parsing flags iteratively tail=%[1]q (cmd=%[2]q)", args.Tail(), cmd.Name)
defer tracef("done parsing flags (cmd=%[1]q)", cmd.Name)

posArgs := []string{}
for rargs := args.Slice(); len(rargs) > 0; rargs = rargs[1:] {
tracef("rearrange:1 (cmd=%[1]q) %[2]q", cmd.Name, rargs)

firstArg := strings.TrimSpace(rargs[0])
if len(firstArg) == 0 {
break
}

// stop parsing once we see a "--"
if firstArg == "--" {
posArgs = append(posArgs, rargs[1:]...)
return &stringSliceArgs{posArgs}, nil
}

// handle positional args
if firstArg[0] != '-' {
// positional argument probably
tracef("rearrange-3 (cmd=%[1]q) check %[2]q", cmd.Name, firstArg)

// if there is a command by that name let the command handle the
// rest of the parsing
if cmd.Command(firstArg) != nil {
posArgs = append(posArgs, rargs...)
return &stringSliceArgs{posArgs}, nil
}

posArgs = append(posArgs, firstArg)
continue
}

numMinuses := 1
// this is same as firstArg == "-"
if len(firstArg) == 1 {
posArgs = append(posArgs, firstArg)
break
}

shortOptionHandling := cmd.useShortOptionHandling()

// stop parsing -- as short flags
if firstArg[1] == '-' {
numMinuses++
shortOptionHandling = false
}

tracef("parseFlags (shortOptionHandling=%[1]q)", shortOptionHandling)

flagName := firstArg[numMinuses:]
flagVal := ""
tracef("flagName:1 (fName=%[1]q)", flagName)
if index := strings.Index(flagName, "="); index != -1 {
flagVal = flagName[index+1:]
flagName = flagName[:index]
}

tracef("flagName:2 (fName=%[1]q) (fVal=%[2]q)", flagName, flagVal)

f := cmd.lookupFlag(flagName)
// found a flag matching given flagName
if f != nil {
tracef("Trying flag type (fName=%[1]q) (type=%[2]T)", flagName, f)
if fb, ok := f.(boolFlag); ok && fb.IsBoolFlag() {
if flagVal == "" {
flagVal = "true"
}
tracef("parse Apply bool flag (fName=%[1]q) (fVal=%[2]q)", flagName, flagVal)
if err := cmd.set(flagName, f, flagVal); err != nil {
return &stringSliceArgs{posArgs}, err
}
continue
}

tracef("processing non bool flag (fName=%[1]q)", flagName)
// not a bool flag so need to get the next arg
if flagVal == "" {
if len(rargs) == 1 {
return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", argumentNotProvidedErrMsg, firstArg)
}
flagVal = rargs[1]
rargs = rargs[1:]
}

tracef("setting non bool flag (fName=%[1]q) (fVal=%[2]q)", flagName, flagVal)
if err := cmd.set(flagName, f, flagVal); err != nil {
return &stringSliceArgs{posArgs}, err
}

continue
}

// no flag lookup found and short handling is disabled
if !shortOptionHandling {
return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", providedButNotDefinedErrMsg, flagName)
}

// try to split the flags
for index, c := range flagName {
tracef("processing flag (fName=%[1]q)", string(c))
if sf := cmd.lookupFlag(string(c)); sf == nil {
return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", providedButNotDefinedErrMsg, flagName)
} else if fb, ok := sf.(boolFlag); ok && fb.IsBoolFlag() {
fv := flagVal
if index == (len(flagName)-1) && flagVal == "" {
fv = "true"
}
if fv == "" {
fv = "true"
}
if err := cmd.set(flagName, sf, fv); err != nil {
tracef("processing flag.2 (fName=%[1]q)", string(c))
return &stringSliceArgs{posArgs}, err
}

Check warning on line 188 in command_parse.go

View check run for this annotation

Codecov / codecov/patch

command_parse.go#L186-L188

Added lines #L186 - L188 were not covered by tests
} else if index == len(flagName)-1 { // last flag can take an arg
if flagVal == "" {
if len(rargs) == 1 {
return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", argumentNotProvidedErrMsg, string(c))
}

Check warning on line 193 in command_parse.go

View check run for this annotation

Codecov / codecov/patch

command_parse.go#L192-L193

Added lines #L192 - L193 were not covered by tests
flagVal = rargs[1]
}
tracef("parseFlags (flagName %[1]q) (flagVal %[2]q)", flagName, flagVal)
if err := cmd.set(flagName, sf, flagVal); err != nil {
tracef("processing flag.4 (fName=%[1]q)", string(c))
return &stringSliceArgs{posArgs}, err
}

Check warning on line 200 in command_parse.go

View check run for this annotation

Codecov / codecov/patch

command_parse.go#L198-L200

Added lines #L198 - L200 were not covered by tests
}
}
}

tracef("returning-2 (cmd=%[1]q) args %[2]q", cmd.Name, posArgs)
return &stringSliceArgs{posArgs}, nil
}
Loading
Loading
0