Skip to content

Commit 3c8a19e

Browse files
authored
fix RegisterFlagCompletionFunc concurrent map writes error (#1423)
* fix-RegisterFlagCompletionFunc-concurrent * set to root command * move to non-public fields
1 parent 2dea4f2 commit 3c8a19e

File tree

3 files changed

+12
-7
lines changed

3 files changed

+12
-7
lines changed

bash_completions.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ func writeLocalNonPersistentFlag(buf io.StringWriter, flag *pflag.Flag) {
512512

513513
// Setup annotations for go completions for registered flags
514514
func prepareCustomAnnotationsForFlags(cmd *Command) {
515-
for flag := range flagCompletionFunctions {
515+
for flag := range cmd.Root().flagCompletionFunctions {
516516
// Make sure the completion script calls the __*_go_custom_completion function for
517517
// every registered flag. We need to do this here (and not when the flag was registered
518518
// for completion) so that we can know the root command name for the prefix

command.go

+3
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ type Command struct {
142142
// that we can use on every pflag set and children commands
143143
globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName
144144

145+
//flagCompletionFunctions is map of flag completion functions.
146+
flagCompletionFunctions map[*flag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)
147+
145148
// usageFunc is usage func defined by user.
146149
usageFunc func(*Command) error
147150
// usageTemplate is usage template defined by user.

completions.go

+8-6
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@ const (
1717
ShellCompNoDescRequestCmd = "__completeNoDesc"
1818
)
1919

20-
// Global map of flag completion functions.
21-
var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){}
22-
2320
// ShellCompDirective is a bit map representing the different behaviors the shell
2421
// can be instructed to have once completions have been provided.
2522
type ShellCompDirective int
@@ -94,10 +91,15 @@ func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Comman
9491
if flag == nil {
9592
return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' does not exist", flagName)
9693
}
97-
if _, exists := flagCompletionFunctions[flag]; exists {
94+
95+
root := c.Root()
96+
if _, exists := root.flagCompletionFunctions[flag]; exists {
9897
return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' already registered", flagName)
9998
}
100-
flagCompletionFunctions[flag] = f
99+
if root.flagCompletionFunctions == nil {
100+
root.flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){}
101+
}
102+
root.flagCompletionFunctions[flag] = f
101103
return nil
102104
}
103105

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

0 commit comments

Comments
 (0)