Skip to content

Commit

Permalink
fix RegisterFlagCompletionFunc concurrent map writes error (#1423)
Browse files Browse the repository at this point in the history
* fix-RegisterFlagCompletionFunc-concurrent
* set to root command
* move to non-public fields
  • Loading branch information
silenceshell committed Jun 30, 2021
1 parent 2dea4f2 commit 3c8a19e
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 7 deletions.
2 changes: 1 addition & 1 deletion bash_completions.go
Expand Up @@ -512,7 +512,7 @@ func writeLocalNonPersistentFlag(buf io.StringWriter, flag *pflag.Flag) {

// Setup annotations for go completions for registered flags
func prepareCustomAnnotationsForFlags(cmd *Command) {
for flag := range flagCompletionFunctions {
for flag := range cmd.Root().flagCompletionFunctions {
// Make sure the completion script calls the __*_go_custom_completion function for
// every registered flag. We need to do this here (and not when the flag was registered
// for completion) so that we can know the root command name for the prefix
Expand Down
3 changes: 3 additions & 0 deletions command.go
Expand Up @@ -142,6 +142,9 @@ type Command struct {
// that we can use on every pflag set and children commands
globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName

//flagCompletionFunctions is map of flag completion functions.
flagCompletionFunctions map[*flag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)

// usageFunc is usage func defined by user.
usageFunc func(*Command) error
// usageTemplate is usage template defined by user.
Expand Down
14 changes: 8 additions & 6 deletions completions.go
Expand Up @@ -17,9 +17,6 @@ const (
ShellCompNoDescRequestCmd = "__completeNoDesc"
)

// Global map of flag completion functions.
var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){}

// ShellCompDirective is a bit map representing the different behaviors the shell
// can be instructed to have once completions have been provided.
type ShellCompDirective int
Expand Down Expand Up @@ -94,10 +91,15 @@ func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Comman
if flag == nil {
return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' does not exist", flagName)
}
if _, exists := flagCompletionFunctions[flag]; exists {

root := c.Root()
if _, exists := root.flagCompletionFunctions[flag]; exists {
return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' already registered", flagName)
}
flagCompletionFunctions[flag] = f
if root.flagCompletionFunctions == nil {
root.flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){}
}
root.flagCompletionFunctions[flag] = f
return nil
}

Expand Down Expand Up @@ -374,7 +376,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
// Find the completion function for the flag or command
var completionFn func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)
if flag != nil {
completionFn = flagCompletionFunctions[flag]
completionFn = c.Root().flagCompletionFunctions[flag]
} else {
completionFn = finalCmd.ValidArgsFunction
}
Expand Down

0 comments on commit 3c8a19e

Please sign in to comment.