Skip to content

Commit

Permalink
Merge branch 'spf13:main' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
mavaddat authored Oct 30, 2023
2 parents c901861 + 48cea5c commit 8b4835d
Show file tree
Hide file tree
Showing 30 changed files with 631 additions and 144 deletions.
19 changes: 10 additions & 9 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
steps:

- uses: actions/checkout@v3
- uses: actions/checkout@v4

- run: >-
docker run
Expand All @@ -39,17 +39,17 @@ jobs:
runs-on: ubuntu-latest
steps:

- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: actions/setup-go@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.20'
go-version: '^1.21'
check-latest: true
cache: true

- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: golangci/golangci-lint-action@v3.5.0
- uses: golangci/golangci-lint-action@v3.7.0
with:
version: latest
args: --verbose
Expand All @@ -67,13 +67,14 @@ jobs:
- 18
- 19
- 20
- 21
name: '${{ matrix.platform }} | 1.${{ matrix.go }}.x'
runs-on: ${{ matrix.platform }}-latest
steps:

- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: actions/setup-go@v3
- uses: actions/setup-go@v4
with:
go-version: 1.${{ matrix.go }}.x
cache: true
Expand Down Expand Up @@ -107,7 +108,7 @@ jobs:
unzip
mingw-w64-x86_64-go
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: actions/cache@v3
with:
Expand Down
8 changes: 4 additions & 4 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ linters:
disable-all: true
enable:
#- bodyclose
- deadcode
# - deadcode ! deprecated since v1.49.0; replaced by 'unused'
#- depguard
#- dogsled
#- dupl
Expand Down Expand Up @@ -51,12 +51,12 @@ linters:
#- rowserrcheck
#- scopelint
#- staticcheck
- structcheck
#- structcheck ! deprecated since v1.49.0; replaced by 'unused'
#- stylecheck
#- typecheck
- unconvert
#- unparam
#- unused
- varcheck
- unused
# - varcheck ! deprecated since v1.49.0; replaced by 'unused'
#- whitespace
fast: false
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Cobra is a library for creating powerful modern CLI applications.

Cobra is used in many Go projects such as [Kubernetes](https://kubernetes.io/),
[Hugo](https://gohugo.io), and [GitHub CLI](https://github.com/cli/cli) to
name a few. [This list](./projects_using_cobra.md) contains a more extensive list of projects using Cobra.
name a few. [This list](site/content/projects_using_cobra.md) contains a more extensive list of projects using Cobra.

[![](https://img.shields.io/github/actions/workflow/status/spf13/cobra/test.yml?branch=main&longCache=true&label=Test&logo=github%20actions&logoColor=fff)](https://github.com/spf13/cobra/actions?query=workflow%3ATest)
[![Go Reference](https://pkg.go.dev/badge/github.com/spf13/cobra.svg)](https://pkg.go.dev/github.com/spf13/cobra)
Expand Down Expand Up @@ -80,7 +80,7 @@ which maintains the same interface while adding POSIX compliance.

# Installing
Using Cobra is easy. First, use `go get` to install the latest version
of the library.
of the library.

```
go get -u github.com/spf13/cobra@latest
Expand All @@ -105,8 +105,8 @@ go install github.com/spf13/cobra-cli@latest

For complete details on using the Cobra-CLI generator, please read [The Cobra Generator README](https://github.com/spf13/cobra-cli/blob/main/README.md)

For complete details on using the Cobra library, please read the [The Cobra User Guide](user_guide.md).
For complete details on using the Cobra library, please read the [The Cobra User Guide](site/content/user_guide.md).

# License

Cobra is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/spf13/cobra/blob/master/LICENSE.txt)
Cobra is released under the Apache 2.0 license. See [LICENSE.txt](LICENSE.txt)
10 changes: 7 additions & 3 deletions active_help.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package cobra
import (
"fmt"
"os"
"regexp"
"strings"
)

Expand All @@ -29,6 +30,8 @@ const (
activeHelpGlobalDisable = "0"
)

var activeHelpEnvVarPrefixSubstRegexp = regexp.MustCompile(`[^A-Z0-9_]`)

// AppendActiveHelp adds the specified string to the specified array to be used as ActiveHelp.
// Such strings will be processed by the completion script and will be shown as ActiveHelp
// to the user.
Expand All @@ -42,7 +45,7 @@ func AppendActiveHelp(compArray []string, activeHelpStr string) []string {

// GetActiveHelpConfig returns the value of the ActiveHelp environment variable
// <PROGRAM>_ACTIVE_HELP where <PROGRAM> is the name of the root command in upper
// case, with all - replaced by _.
// case, with all non-ASCII-alphanumeric characters replaced by `_`.
// It will always return "0" if the global environment variable COBRA_ACTIVE_HELP
// is set to "0".
func GetActiveHelpConfig(cmd *Command) string {
Expand All @@ -55,9 +58,10 @@ func GetActiveHelpConfig(cmd *Command) string {

// activeHelpEnvVar returns the name of the program-specific ActiveHelp environment
// variable. It has the format <PROGRAM>_ACTIVE_HELP where <PROGRAM> is the name of the
// root command in upper case, with all - replaced by _.
// root command in upper case, with all non-ASCII-alphanumeric characters replaced by `_`.
func activeHelpEnvVar(name string) string {
// This format should not be changed: users will be using it explicitly.
activeHelpEnvVar := strings.ToUpper(fmt.Sprintf("%s%s", name, activeHelpEnvVarSuffix))
return strings.ReplaceAll(activeHelpEnvVar, "-", "_")
activeHelpEnvVar = activeHelpEnvVarPrefixSubstRegexp.ReplaceAllString(activeHelpEnvVar, "_")
return activeHelpEnvVar
}
11 changes: 8 additions & 3 deletions cobra.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@ var initializers []func()
var finalizers []func()

const (
defaultPrefixMatching = false
defaultCommandSorting = true
defaultCaseInsensitive = false
defaultPrefixMatching = false
defaultCommandSorting = true
defaultCaseInsensitive = false
defaultTraverseRunHooks = false
)

// EnablePrefixMatching allows setting automatic prefix matching. Automatic prefix matching can be a dangerous thing
Expand All @@ -60,6 +61,10 @@ var EnableCommandSorting = defaultCommandSorting
// EnableCaseInsensitive allows case-insensitive commands names. (case sensitive by default)
var EnableCaseInsensitive = defaultCaseInsensitive

// EnableTraverseRunHooks executes persistent pre-run and post-run hooks from all parents.
// By default this is disabled, which means only the first run hook to be found is executed.
var EnableTraverseRunHooks = defaultTraverseRunHooks

// MousetrapHelpText enables an information splash screen on Windows
// if the CLI is started from explorer.exe.
// To disable the mousetrap, just set this variable to blank string ("").
Expand Down
59 changes: 52 additions & 7 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ type Command struct {
// * PostRun()
// * PersistentPostRun()
// All functions get the same args, the arguments after the command name.
// The *PreRun and *PostRun functions will only be executed if the Run function of the current
// command has been declared.
//
// PersistentPreRun: children of this command will inherit and execute.
PersistentPreRun func(cmd *Command, args []string)
Expand Down Expand Up @@ -181,6 +183,9 @@ type Command struct {
// versionTemplate is the version template defined by user.
versionTemplate string

// errPrefix is the error message prefix defined by user.
errPrefix string

// inReader is a reader defined by the user that replaces stdin
inReader io.Reader
// outWriter is a writer defined by the user that replaces stdout
Expand Down Expand Up @@ -346,6 +351,11 @@ func (c *Command) SetVersionTemplate(s string) {
c.versionTemplate = s
}

// SetErrPrefix sets error message prefix to be used. Application can use it to set custom prefix.
func (c *Command) SetErrPrefix(s string) {
c.errPrefix = s
}

// SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands.
// The user should not have a cyclic dependency on commands.
func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) {
Expand Down Expand Up @@ -595,6 +605,18 @@ func (c *Command) VersionTemplate() string {
`
}

// ErrPrefix return error message prefix for the command
func (c *Command) ErrPrefix() string {
if c.errPrefix != "" {
return c.errPrefix
}

if c.HasParent() {
return c.parent.ErrPrefix()
}
return "Error:"
}

func hasNoOptDefVal(name string, fs *flag.FlagSet) bool {
flag := fs.Lookup(name)
if flag == nil {
Expand Down Expand Up @@ -752,7 +774,9 @@ func (c *Command) findNext(next string) *Command {
}

if len(matches) == 1 {
return matches[0]
// Temporarily disable gosec G602, which produces a false positive.
// See https://github.com/securego/gosec/issues/1005.
return matches[0] // #nosec G602
}

return nil
Expand Down Expand Up @@ -910,15 +934,31 @@ func (c *Command) execute(a []string) (err error) {
return err
}

parents := make([]*Command, 0, 5)
for p := c; p != nil; p = p.Parent() {
if EnableTraverseRunHooks {
// When EnableTraverseRunHooks is set:
// - Execute all persistent pre-runs from the root parent till this command.
// - Execute all persistent post-runs from this command till the root parent.
parents = append([]*Command{p}, parents...)
} else {
// Otherwise, execute only the first found persistent hook.
parents = append(parents, p)
}
}
for _, p := range parents {
if p.PersistentPreRunE != nil {
if err := p.PersistentPreRunE(c, argWoFlags); err != nil {
return err
}
break
if !EnableTraverseRunHooks {
break
}
} else if p.PersistentPreRun != nil {
p.PersistentPreRun(c, argWoFlags)
break
if !EnableTraverseRunHooks {
break
}
}
}
if c.PreRunE != nil {
Expand Down Expand Up @@ -955,10 +995,14 @@ func (c *Command) execute(a []string) (err error) {
if err := p.PersistentPostRunE(c, argWoFlags); err != nil {
return err
}
break
if !EnableTraverseRunHooks {
break
}
} else if p.PersistentPostRun != nil {
p.PersistentPostRun(c, argWoFlags)
break
if !EnableTraverseRunHooks {
break
}
}
}

Expand Down Expand Up @@ -1048,7 +1092,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
c = cmd
}
if !c.SilenceErrors {
c.PrintErrln("Error:", err.Error())
c.PrintErrln(c.ErrPrefix(), err.Error())
c.PrintErrf("Run '%v --help' for usage.\n", c.CommandPath())
}
return c, err
Expand Down Expand Up @@ -1077,7 +1121,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
// If root command has SilenceErrors flagged,
// all subcommands should respect it
if !cmd.SilenceErrors && !c.SilenceErrors {
c.PrintErrln("Error:", err.Error())
c.PrintErrln(cmd.ErrPrefix(), err.Error())
}

// If root command has SilenceUsage flagged,
Expand Down Expand Up @@ -1402,6 +1446,7 @@ func (c *Command) UseLine() string {

// DebugFlags used to determine which flags have been assigned to which commands
// and which persist.
// nolint:goconst
func (c *Command) DebugFlags() {
c.Println("DebugFlags called on", c.Name())
var debugflags func(*Command)
Expand Down
Loading

0 comments on commit 8b4835d

Please sign in to comment.