Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into michaeljs1990-add-fla…
Browse files Browse the repository at this point in the history
…g-category-support
  • Loading branch information
meatballhat committed May 22, 2022
2 parents a78717f + 939ab7f commit 4bca72c
Show file tree
Hide file tree
Showing 24 changed files with 103 additions and 69 deletions.
11 changes: 6 additions & 5 deletions CODE_OF_CONDUCT.md
Expand Up @@ -55,11 +55,12 @@ further defined and clarified by project maintainers.
## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting Dan Buch at dan@meatballhat.com. All complaints will be
reviewed and investigated and will result in a response that is deemed necessary
and appropriate to the circumstances. The project team is obligated to maintain
confidentiality with regard to the reporter of an incident. Further details of
specific enforcement policies may be posted separately.
reported by contacting urfave-governance@googlegroups.com, a members-only group
that is world-postable. All complaints will be reviewed and investigated and
will result in a response that is deemed necessary and appropriate to the
circumstances. The project team is obligated to maintain confidentiality with
regard to the reporter of an incident. Further details of specific enforcement
policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
Expand Down
7 changes: 5 additions & 2 deletions app_test.go
Expand Up @@ -228,6 +228,7 @@ func ExampleApp_Run_subcommandNoAction() {
}

func ExampleApp_Run_bashComplete_withShortFlag() {
os.Setenv("SHELL", "bash")
os.Args = []string{"greet", "-", "--generate-bash-completion"}

app := NewApp()
Expand Down Expand Up @@ -255,6 +256,7 @@ func ExampleApp_Run_bashComplete_withShortFlag() {
}

func ExampleApp_Run_bashComplete_withLongFlag() {
os.Setenv("SHELL", "bash")
os.Args = []string{"greet", "--s", "--generate-bash-completion"}

app := NewApp()
Expand Down Expand Up @@ -283,6 +285,7 @@ func ExampleApp_Run_bashComplete_withLongFlag() {
// --similar-flag
}
func ExampleApp_Run_bashComplete_withMultipleLongFlag() {
os.Setenv("SHELL", "bash")
os.Args = []string{"greet", "--st", "--generate-bash-completion"}

app := NewApp()
Expand Down Expand Up @@ -315,7 +318,7 @@ func ExampleApp_Run_bashComplete_withMultipleLongFlag() {
}

func ExampleApp_Run_bashComplete() {
// set args for examples sake
os.Setenv("SHELL", "bash")
os.Args = []string{"greet", "--generate-bash-completion"}

app := &App{
Expand Down Expand Up @@ -355,7 +358,7 @@ func ExampleApp_Run_bashComplete() {
func ExampleApp_Run_zshComplete() {
// set args for examples sake
os.Args = []string{"greet", "--generate-bash-completion"}
_ = os.Setenv("_CLI_ZSH_AUTOCOMPLETE_HACK", "1")
_ = os.Setenv("SHELL", "/usr/bin/zsh")

app := NewApp()
app.Name = "greet"
Expand Down
7 changes: 2 additions & 5 deletions autocomplete/zsh_autocomplete
@@ -1,23 +1,20 @@
#compdef $PROG

_cli_zsh_autocomplete() {

local -a opts
local cur
cur=${words[-1]}
if [[ "$cur" == "-"* ]]; then
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}")
opts=("${(@f)$(${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}")
else
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}")
opts=("${(@f)$(${words[@]:0:#words[@]-1} --generate-bash-completion)}")
fi

if [[ "${opts[1]}" != "" ]]; then
_describe 'values' opts
else
_files
fi

return
}

compdef _cli_zsh_autocomplete $PROG
27 changes: 27 additions & 0 deletions docs/SECURITY.md
@@ -0,0 +1,27 @@
# Security Policy

Hello and thank you for your interest in the `urfave/cli` security
policy! :tada: :lock:

## Supported Versions

| Version | Supported |
| ------------ | ------------------------------------- |
| `>= v2.3.x` | :white_check_mark: |
| `< v2.3` | :x: |
| `>= v1.22.x` | :white_check_mark: :lady_beetle: [^1] |
| `< v1.22` | :x: |

## Reporting a Vulnerability

Please disclose any vulnerabilities by sending an email to:

[urfave-security@googlegroups.com](mailto:urfave-security@googlegroups.com)

You should expect a response within 48 hours and further
communications to be decided via email. The `urfave/cli` maintainer
team comprises volunteers who contribute when possible, so please
have patience :bow:

[^1]: The `v1.22.x` series will receive bug fixes and security
patches only.
11 changes: 5 additions & 6 deletions docs/v2/manual.md
Expand Up @@ -1165,15 +1165,14 @@ func main() {
```

#### ZSH Support
Auto-completion for ZSH is also supported using the `autocomplete/zsh_autocomplete`
file included in this repo. Two environment variables are used, `PROG` and `_CLI_ZSH_AUTOCOMPLETE_HACK`.
Set `PROG` to the program name as before, set `_CLI_ZSH_AUTOCOMPLETE_HACK` to `1`, and
then `source path/to/autocomplete/zsh_autocomplete`. Adding the following lines to your ZSH
configuration file (usually `.zshrc`) will allow the auto-completion to persist across new shells:
Auto-completion for ZSH is also supported using the `autocomplete/zsh_autocomplete`
file included in this repo. One environment variable is used, `PROG`. Set
`PROG` to the program name as before, and then `source path/to/autocomplete/zsh_autocomplete`.
Adding the following lines to your ZSH configuration file (usually `.zshrc`)
will allow the auto-completion to persist across new shells:

```
PROG=<myprogram>
_CLI_ZSH_AUTOCOMPLETE_HACK=1
source path/to/autocomplete/zsh_autocomplete
```
#### ZSH default auto-complete example
Expand Down
13 changes: 8 additions & 5 deletions flag.go
Expand Up @@ -394,21 +394,24 @@ func hasFlag(flags []Flag, fl Flag) bool {
return false
}

func flagFromEnvOrFile(envVars []string, filePath string) (val string, ok bool) {
// Return the first value from a list of environment variables and files
// (which may or may not exist), a description of where the value was found,
// and a boolean which is true if a value was found.
func flagFromEnvOrFile(envVars []string, filePath string) (value string, fromWhere string, found bool) {
for _, envVar := range envVars {
envVar = strings.TrimSpace(envVar)
if val, ok := syscall.Getenv(envVar); ok {
return val, true
if value, found := syscall.Getenv(envVar); found {
return value, fmt.Sprintf("environment variable %q", envVar), true
}
}
for _, fileVar := range strings.Split(filePath, ",") {
if fileVar != "" {
if data, err := ioutil.ReadFile(fileVar); err == nil {
return string(data), true
return string(data), fmt.Sprintf("file %q", filePath), true
}
}
}
return "", false
return "", "", false
}

func flagSplitMultiValues(val string) []string {
Expand Down
4 changes: 2 additions & 2 deletions flag_bool.go
Expand Up @@ -42,12 +42,12 @@ func (f *BoolFlag) GetEnvVars() []string {

// 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, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
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)
return fmt.Errorf("could not parse %q as bool value from %s for flag %s: %s", val, source, f.Name, err)
}

f.Value = valBool
Expand Down
4 changes: 2 additions & 2 deletions flag_duration.go
Expand Up @@ -42,12 +42,12 @@ func (f *DurationFlag) GetEnvVars() []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, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
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)
return fmt.Errorf("could not parse %q as duration value from %s for flag %s: %s", val, source, f.Name, err)
}

f.Value = valDuration
Expand Down
4 changes: 2 additions & 2 deletions flag_float64.go
Expand Up @@ -42,11 +42,11 @@ func (f *Float64Flag) GetEnvVars() []string {

// 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, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
if val != "" {
valFloat, err := strconv.ParseFloat(val, 64)
if err != nil {
return fmt.Errorf("could not parse %q as float64 value for flag %s: %s", val, f.Name, err)
return fmt.Errorf("could not parse %q as float64 value from %s for flag %s: %s", val, source, f.Name, err)
}

f.Value = valFloat
Expand Down
4 changes: 2 additions & 2 deletions flag_float64_slice.go
Expand Up @@ -120,13 +120,13 @@ func (f *Float64SliceFlag) GetEnvVars() []string {

// 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, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
if val != "" {
f.Value = &Float64Slice{}

for _, s := range flagSplitMultiValues(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)
return fmt.Errorf("could not parse %q as float64 slice value from %s for flag %s: %s", f.Value, source, f.Name, err)
}
}

Expand Down
4 changes: 2 additions & 2 deletions flag_generic.go
Expand Up @@ -51,10 +51,10 @@ func (f *GenericFlag) GetEnvVars() []string {
// Apply takes the flagset and calls Set on the generic flag with the value
// provided by the user for parsing by the flag
func (f GenericFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
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)
return fmt.Errorf("could not parse %q from %s as value for flag %s: %s", val, source, f.Name, err)
}

f.HasBeenSet = true
Expand Down
4 changes: 2 additions & 2 deletions flag_int.go
Expand Up @@ -42,12 +42,12 @@ func (f *IntFlag) GetEnvVars() []string {

// Apply populates the flag given the flag set and environment
func (f *IntFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
if val != "" {
valInt, err := strconv.ParseInt(val, 0, 64)

if err != nil {
return fmt.Errorf("could not parse %q as int value for flag %s: %s", val, f.Name, err)
return fmt.Errorf("could not parse %q as int value from %s for flag %s: %s", val, source, f.Name, err)
}

f.Value = int(valInt)
Expand Down
4 changes: 2 additions & 2 deletions flag_int64.go
Expand Up @@ -42,12 +42,12 @@ func (f *Int64Flag) GetEnvVars() []string {

// Apply populates the flag given the flag set and environment
func (f *Int64Flag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
if val != "" {
valInt, err := strconv.ParseInt(val, 0, 64)

if err != nil {
return fmt.Errorf("could not parse %q as int value for flag %s: %s", val, f.Name, err)
return fmt.Errorf("could not parse %q as int value from %s for flag %s: %s", val, source, f.Name, err)
}

f.Value = valInt
Expand Down
4 changes: 2 additions & 2 deletions flag_int64_slice.go
Expand Up @@ -121,12 +121,12 @@ func (f *Int64SliceFlag) GetEnvVars() []string {

// 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 {
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
f.Value = &Int64Slice{}

for _, s := range flagSplitMultiValues(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)
return fmt.Errorf("could not parse %q as int64 slice value from %s for flag %s: %s", val, source, f.Name, err)
}
}

Expand Down
4 changes: 2 additions & 2 deletions flag_int_slice.go
Expand Up @@ -132,12 +132,12 @@ func (f *IntSliceFlag) GetEnvVars() []string {

// 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 {
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
f.Value = &IntSlice{}

for _, s := range flagSplitMultiValues(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)
return fmt.Errorf("could not parse %q as int slice value from %s for flag %s: %s", val, source, f.Name, err)
}
}

Expand Down
2 changes: 1 addition & 1 deletion flag_path.go
Expand Up @@ -46,7 +46,7 @@ func (f *PathFlag) GetEnvVars() []string {

// 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 {
if val, _, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
f.Value = val
f.HasBeenSet = true
}
Expand Down
2 changes: 1 addition & 1 deletion flag_string.go
Expand Up @@ -44,7 +44,7 @@ func (f *StringFlag) GetEnvVars() []string {

// Apply populates the flag given the flag set and environment
func (f *StringFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val, _, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
f.Value = val
f.HasBeenSet = true
}
Expand Down
4 changes: 2 additions & 2 deletions flag_string_slice.go
Expand Up @@ -122,7 +122,7 @@ func (f *StringSliceFlag) Apply(set *flag.FlagSet) error {

}

if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
if f.Value == nil {
f.Value = &StringSlice{}
}
Expand All @@ -133,7 +133,7 @@ func (f *StringSliceFlag) Apply(set *flag.FlagSet) error {

for _, s := range flagSplitMultiValues(val) {
if err := destination.Set(strings.TrimSpace(s)); err != nil {
return fmt.Errorf("could not parse %q as string value for flag %s: %s", val, f.Name, err)
return fmt.Errorf("could not parse %q as string value from %s for flag %s: %s", val, source, f.Name, err)
}
}

Expand Down

0 comments on commit 4bca72c

Please sign in to comment.