mirror of https://github.com/k3d-io/k3d
With the updated cobra depencendy, we're now passing a context from the cmd to the called functions. When creating a cluster, one can pass a Duration to the --timeout flag, which will create a new context with a timeout. In the two blocking functions, where we're waiting for the master nodes (initializing master nodes and "normal" master nodes), we're now checking for the context cancellation as well, which may be caused by the timeout.pull/224/head
parent
80d1c5c2de
commit
1b7f5c5f78
@ -0,0 +1,36 @@ |
||||
BIN="./bin"
|
||||
SRC=$(shell find . -name "*.go")
|
||||
|
||||
ifeq (, $(shell which richgo)) |
||||
$(warning "could not find richgo in $(PATH), run: go get github.com/kyoh86/richgo") |
||||
endif |
||||
|
||||
.PHONY: fmt vet test cobra_generator install_deps clean |
||||
|
||||
default: all |
||||
|
||||
all: fmt vet test cobra_generator |
||||
|
||||
fmt: |
||||
$(info ******************** checking formatting ********************)
|
||||
@test -z $(shell gofmt -l $(SRC)) || (gofmt -d $(SRC); exit 1)
|
||||
|
||||
test: install_deps vet |
||||
$(info ******************** running tests ********************)
|
||||
richgo test -v ./...
|
||||
|
||||
cobra_generator: install_deps |
||||
$(info ******************** building generator ********************)
|
||||
mkdir -p $(BIN)
|
||||
make -C cobra all
|
||||
|
||||
install_deps: |
||||
$(info ******************** downloading dependencies ********************)
|
||||
go get -v ./...
|
||||
|
||||
vet: |
||||
$(info ******************** vetting ********************)
|
||||
go vet ./...
|
||||
|
||||
clean: |
||||
rm -rf $(BIN)
|
@ -0,0 +1,384 @@ |
||||
package cobra |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"os" |
||||
"strings" |
||||
|
||||
"github.com/spf13/pflag" |
||||
) |
||||
|
||||
const ( |
||||
// ShellCompRequestCmd is the name of the hidden command that is used to request
|
||||
// completion results from the program. It is used by the shell completion scripts.
|
||||
ShellCompRequestCmd = "__complete" |
||||
// ShellCompNoDescRequestCmd is the name of the hidden command that is used to request
|
||||
// completion results without their description. It is used by the shell completion scripts.
|
||||
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 |
||||
|
||||
const ( |
||||
// ShellCompDirectiveError indicates an error occurred and completions should be ignored.
|
||||
ShellCompDirectiveError ShellCompDirective = 1 << iota |
||||
|
||||
// ShellCompDirectiveNoSpace indicates that the shell should not add a space
|
||||
// after the completion even if there is a single completion provided.
|
||||
ShellCompDirectiveNoSpace |
||||
|
||||
// ShellCompDirectiveNoFileComp indicates that the shell should not provide
|
||||
// file completion even when no completion is provided.
|
||||
// This currently does not work for zsh or bash < 4
|
||||
ShellCompDirectiveNoFileComp |
||||
|
||||
// ShellCompDirectiveDefault indicates to let the shell perform its default
|
||||
// behavior after completions have been provided.
|
||||
ShellCompDirectiveDefault ShellCompDirective = 0 |
||||
) |
||||
|
||||
// RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag.
|
||||
func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)) error { |
||||
flag := c.Flag(flagName) |
||||
if flag == nil { |
||||
return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' does not exist", flagName) |
||||
} |
||||
if _, exists := flagCompletionFunctions[flag]; exists { |
||||
return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' already registered", flagName) |
||||
} |
||||
flagCompletionFunctions[flag] = f |
||||
return nil |
||||
} |
||||
|
||||
// Returns a string listing the different directive enabled in the specified parameter
|
||||
func (d ShellCompDirective) string() string { |
||||
var directives []string |
||||
if d&ShellCompDirectiveError != 0 { |
||||
directives = append(directives, "ShellCompDirectiveError") |
||||
} |
||||
if d&ShellCompDirectiveNoSpace != 0 { |
||||
directives = append(directives, "ShellCompDirectiveNoSpace") |
||||
} |
||||
if d&ShellCompDirectiveNoFileComp != 0 { |
||||
directives = append(directives, "ShellCompDirectiveNoFileComp") |
||||
} |
||||
if len(directives) == 0 { |
||||
directives = append(directives, "ShellCompDirectiveDefault") |
||||
} |
||||
|
||||
if d > ShellCompDirectiveError+ShellCompDirectiveNoSpace+ShellCompDirectiveNoFileComp { |
||||
return fmt.Sprintf("ERROR: unexpected ShellCompDirective value: %d", d) |
||||
} |
||||
return strings.Join(directives, ", ") |
||||
} |
||||
|
||||
// Adds a special hidden command that can be used to request custom completions.
|
||||
func (c *Command) initCompleteCmd(args []string) { |
||||
completeCmd := &Command{ |
||||
Use: fmt.Sprintf("%s [command-line]", ShellCompRequestCmd), |
||||
Aliases: []string{ShellCompNoDescRequestCmd}, |
||||
DisableFlagsInUseLine: true, |
||||
Hidden: true, |
||||
DisableFlagParsing: true, |
||||
Args: MinimumNArgs(1), |
||||
Short: "Request shell completion choices for the specified command-line", |
||||
Long: fmt.Sprintf("%[2]s is a special command that is used by the shell completion logic\n%[1]s", |
||||
"to request completion choices for the specified command-line.", ShellCompRequestCmd), |
||||
Run: func(cmd *Command, args []string) { |
||||
finalCmd, completions, directive, err := cmd.getCompletions(args) |
||||
if err != nil { |
||||
CompErrorln(err.Error()) |
||||
// Keep going for multiple reasons:
|
||||
// 1- There could be some valid completions even though there was an error
|
||||
// 2- Even without completions, we need to print the directive
|
||||
} |
||||
|
||||
noDescriptions := (cmd.CalledAs() == ShellCompNoDescRequestCmd) |
||||
for _, comp := range completions { |
||||
if noDescriptions { |
||||
// Remove any description that may be included following a tab character.
|
||||
comp = strings.Split(comp, "\t")[0] |
||||
} |
||||
// Print each possible completion to stdout for the completion script to consume.
|
||||
fmt.Fprintln(finalCmd.OutOrStdout(), comp) |
||||
} |
||||
|
||||
if directive > ShellCompDirectiveError+ShellCompDirectiveNoSpace+ShellCompDirectiveNoFileComp { |
||||
directive = ShellCompDirectiveDefault |
||||
} |
||||
|
||||
// As the last printout, print the completion directive for the completion script to parse.
|
||||
// The directive integer must be that last character following a single colon (:).
|
||||
// The completion script expects :<directive>
|
||||
fmt.Fprintf(finalCmd.OutOrStdout(), ":%d\n", directive) |
||||
|
||||
// Print some helpful info to stderr for the user to understand.
|
||||
// Output from stderr must be ignored by the completion script.
|
||||
fmt.Fprintf(finalCmd.ErrOrStderr(), "Completion ended with directive: %s\n", directive.string()) |
||||
}, |
||||
} |
||||
c.AddCommand(completeCmd) |
||||
subCmd, _, err := c.Find(args) |
||||
if err != nil || subCmd.Name() != ShellCompRequestCmd { |
||||
// Only create this special command if it is actually being called.
|
||||
// This reduces possible side-effects of creating such a command;
|
||||
// for example, having this command would cause problems to a
|
||||
// cobra program that only consists of the root command, since this
|
||||
// command would cause the root command to suddenly have a subcommand.
|
||||
c.RemoveCommand(completeCmd) |
||||
} |
||||
} |
||||
|
||||
func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDirective, error) { |
||||
var completions []string |
||||
|
||||
// The last argument, which is not completely typed by the user,
|
||||
// should not be part of the list of arguments
|
||||
toComplete := args[len(args)-1] |
||||
trimmedArgs := args[:len(args)-1] |
||||
|
||||
// Find the real command for which completion must be performed
|
||||
finalCmd, finalArgs, err := c.Root().Find(trimmedArgs) |
||||
if err != nil { |
||||
// Unable to find the real command. E.g., <program> someInvalidCmd <TAB>
|
||||
return c, completions, ShellCompDirectiveDefault, fmt.Errorf("Unable to find a command for arguments: %v", trimmedArgs) |
||||
} |
||||
|
||||
// When doing completion of a flag name, as soon as an argument starts with
|
||||
// a '-' we know it is a flag. We cannot use isFlagArg() here as it requires
|
||||
// the flag to be complete
|
||||
if len(toComplete) > 0 && toComplete[0] == '-' && !strings.Contains(toComplete, "=") { |
||||
// We are completing a flag name
|
||||
finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { |
||||
completions = append(completions, getFlagNameCompletions(flag, toComplete)...) |
||||
}) |
||||
finalCmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) { |
||||
completions = append(completions, getFlagNameCompletions(flag, toComplete)...) |
||||
}) |
||||
|
||||
directive := ShellCompDirectiveDefault |
||||
if len(completions) > 0 { |
||||
if strings.HasSuffix(completions[0], "=") { |
||||
directive = ShellCompDirectiveNoSpace |
||||
} |
||||
} |
||||
return finalCmd, completions, directive, nil |
||||
} |
||||
|
||||
var flag *pflag.Flag |
||||
if !finalCmd.DisableFlagParsing { |
||||
// We only do flag completion if we are allowed to parse flags
|
||||
// This is important for commands which have requested to do their own flag completion.
|
||||
flag, finalArgs, toComplete, err = checkIfFlagCompletion(finalCmd, finalArgs, toComplete) |
||||
if err != nil { |
||||
// Error while attempting to parse flags
|
||||
return finalCmd, completions, ShellCompDirectiveDefault, err |
||||
} |
||||
} |
||||
|
||||
if flag == nil { |
||||
// Complete subcommand names
|
||||
for _, subCmd := range finalCmd.Commands() { |
||||
if subCmd.IsAvailableCommand() && strings.HasPrefix(subCmd.Name(), toComplete) { |
||||
completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short)) |
||||
} |
||||
} |
||||
|
||||
if len(finalCmd.ValidArgs) > 0 { |
||||
// Always complete ValidArgs, even if we are completing a subcommand name.
|
||||
// This is for commands that have both subcommands and ValidArgs.
|
||||
for _, validArg := range finalCmd.ValidArgs { |
||||
if strings.HasPrefix(validArg, toComplete) { |
||||
completions = append(completions, validArg) |
||||
} |
||||
} |
||||
|
||||
// If there are ValidArgs specified (even if they don't match), we stop completion.
|
||||
// Only one of ValidArgs or ValidArgsFunction can be used for a single command.
|
||||
return finalCmd, completions, ShellCompDirectiveNoFileComp, nil |
||||
} |
||||
|
||||
// Always let the logic continue so as to add any ValidArgsFunction completions,
|
||||
// even if we already found sub-commands.
|
||||
// This is for commands that have subcommands but also specify a ValidArgsFunction.
|
||||
} |
||||
|
||||
// Parse the flags and extract the arguments to prepare for calling the completion function
|
||||
if err = finalCmd.ParseFlags(finalArgs); err != nil { |
||||
return finalCmd, completions, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error()) |
||||
} |
||||
|
||||
// We only remove the flags from the arguments if DisableFlagParsing is not set.
|
||||
// This is important for commands which have requested to do their own flag completion.
|
||||
if !finalCmd.DisableFlagParsing { |
||||
finalArgs = finalCmd.Flags().Args() |
||||
} |
||||
|
||||
// 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] |
||||
} else { |
||||
completionFn = finalCmd.ValidArgsFunction |
||||
} |
||||
if completionFn == nil { |
||||
// Go custom completion not supported/needed for this flag or command
|
||||
return finalCmd, completions, ShellCompDirectiveDefault, nil |
||||
} |
||||
|
||||
// Call the registered completion function to get the completions
|
||||
comps, directive := completionFn(finalCmd, finalArgs, toComplete) |
||||
completions = append(completions, comps...) |
||||
return finalCmd, completions, directive, nil |
||||
} |
||||
|
||||
func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string { |
||||
if nonCompletableFlag(flag) { |
||||
return []string{} |
||||
} |
||||
|
||||
var completions []string |
||||
flagName := "--" + flag.Name |
||||
if strings.HasPrefix(flagName, toComplete) { |
||||
// Flag without the =
|
||||
completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) |
||||
|
||||
if len(flag.NoOptDefVal) == 0 { |
||||
// Flag requires a value, so it can be suffixed with =
|
||||
flagName += "=" |
||||
completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) |
||||
} |
||||
} |
||||
|
||||
flagName = "-" + flag.Shorthand |
||||
if len(flag.Shorthand) > 0 && strings.HasPrefix(flagName, toComplete) { |
||||
completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) |
||||
} |
||||
|
||||
return completions |
||||
} |
||||
|
||||
func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*pflag.Flag, []string, string, error) { |
||||
var flagName string |
||||
trimmedArgs := args |
||||
flagWithEqual := false |
||||
if isFlagArg(lastArg) { |
||||
if index := strings.Index(lastArg, "="); index >= 0 { |
||||
flagName = strings.TrimLeft(lastArg[:index], "-") |
||||
lastArg = lastArg[index+1:] |
||||
flagWithEqual = true |
||||
} else { |
||||
return nil, nil, "", errors.New("Unexpected completion request for flag") |
||||
} |
||||
} |
||||
|
||||
if len(flagName) == 0 { |
||||
if len(args) > 0 { |
||||
prevArg := args[len(args)-1] |
||||
if isFlagArg(prevArg) { |
||||
// Only consider the case where the flag does not contain an =.
|
||||
// If the flag contains an = it means it has already been fully processed,
|
||||
// so we don't need to deal with it here.
|
||||
if index := strings.Index(prevArg, "="); index < 0 { |
||||
flagName = strings.TrimLeft(prevArg, "-") |
||||
|
||||
// Remove the uncompleted flag or else there could be an error created
|
||||
// for an invalid value for that flag
|
||||
trimmedArgs = args[:len(args)-1] |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
if len(flagName) == 0 { |
||||
// Not doing flag completion
|
||||
return nil, trimmedArgs, lastArg, nil |
||||
} |
||||
|
||||
flag := findFlag(finalCmd, flagName) |
||||
if flag == nil { |
||||
// Flag not supported by this command, nothing to complete
|
||||
err := fmt.Errorf("Subcommand '%s' does not support flag '%s'", finalCmd.Name(), flagName) |
||||
return nil, nil, "", err |
||||
} |
||||
|
||||
if !flagWithEqual { |
||||
if len(flag.NoOptDefVal) != 0 { |
||||
// We had assumed dealing with a two-word flag but the flag is a boolean flag.
|
||||
// In that case, there is no value following it, so we are not really doing flag completion.
|
||||
// Reset everything to do noun completion.
|
||||
trimmedArgs = args |
||||
flag = nil |
||||
} |
||||
} |
||||
|
||||
return flag, trimmedArgs, lastArg, nil |
||||
} |
||||
|
||||
func findFlag(cmd *Command, name string) *pflag.Flag { |
||||
flagSet := cmd.Flags() |
||||
if len(name) == 1 { |
||||
// First convert the short flag into a long flag
|
||||
// as the cmd.Flag() search only accepts long flags
|
||||
if short := flagSet.ShorthandLookup(name); short != nil { |
||||
name = short.Name |
||||
} else { |
||||
set := cmd.InheritedFlags() |
||||
if short = set.ShorthandLookup(name); short != nil { |
||||
name = short.Name |
||||
} else { |
||||
return nil |
||||
} |
||||
} |
||||
} |
||||
return cmd.Flag(name) |
||||
} |
||||
|
||||
// CompDebug prints the specified string to the same file as where the
|
||||
// completion script prints its logs.
|
||||
// Note that completion printouts should never be on stdout as they would
|
||||
// be wrongly interpreted as actual completion choices by the completion script.
|
||||
func CompDebug(msg string, printToStdErr bool) { |
||||
msg = fmt.Sprintf("[Debug] %s", msg) |
||||
|
||||
// Such logs are only printed when the user has set the environment
|
||||
// variable BASH_COMP_DEBUG_FILE to the path of some file to be used.
|
||||
if path := os.Getenv("BASH_COMP_DEBUG_FILE"); path != "" { |
||||
f, err := os.OpenFile(path, |
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) |
||||
if err == nil { |
||||
defer f.Close() |
||||
f.WriteString(msg) |
||||
} |
||||
} |
||||
|
||||
if printToStdErr { |
||||
// Must print to stderr for this not to be read by the completion script.
|
||||
fmt.Fprintf(os.Stderr, msg) |
||||
} |
||||
} |
||||
|
||||
// CompDebugln prints the specified string with a newline at the end
|
||||
// to the same file as where the completion script prints its logs.
|
||||
// Such logs are only printed when the user has set the environment
|
||||
// variable BASH_COMP_DEBUG_FILE to the path of some file to be used.
|
||||
func CompDebugln(msg string, printToStdErr bool) { |
||||
CompDebug(fmt.Sprintf("%s\n", msg), printToStdErr) |
||||
} |
||||
|
||||
// CompError prints the specified completion message to stderr.
|
||||
func CompError(msg string) { |
||||
msg = fmt.Sprintf("[Error] %s", msg) |
||||
CompDebug(msg, true) |
||||
} |
||||
|
||||
// CompErrorln prints the specified completion message to stderr with a newline at the end.
|
||||
func CompErrorln(msg string) { |
||||
CompError(fmt.Sprintf("%s\n", msg)) |
||||
} |
@ -0,0 +1,172 @@ |
||||
package cobra |
||||
|
||||
import ( |
||||
"bytes" |
||||
"fmt" |
||||
"io" |
||||
"os" |
||||
) |
||||
|
||||
func genFishComp(buf *bytes.Buffer, name string, includeDesc bool) { |
||||
compCmd := ShellCompRequestCmd |
||||
if !includeDesc { |
||||
compCmd = ShellCompNoDescRequestCmd |
||||
} |
||||
buf.WriteString(fmt.Sprintf("# fish completion for %-36s -*- shell-script -*-\n", name)) |
||||
buf.WriteString(fmt.Sprintf(` |
||||
function __%[1]s_debug |
||||
set file "$BASH_COMP_DEBUG_FILE" |
||||
if test -n "$file" |
||||
echo "$argv" >> $file |
||||
end |
||||
end |
||||
|
||||
function __%[1]s_perform_completion |
||||
__%[1]s_debug "Starting __%[1]s_perform_completion with: $argv" |
||||
|
||||
set args (string split -- " " "$argv") |
||||
set lastArg "$args[-1]" |
||||
|
||||
__%[1]s_debug "args: $args" |
||||
__%[1]s_debug "last arg: $lastArg" |
||||
|
||||
set emptyArg "" |
||||
if test -z "$lastArg" |
||||
__%[1]s_debug "Setting emptyArg" |
||||
set emptyArg \"\" |
||||
end |
||||
__%[1]s_debug "emptyArg: $emptyArg" |
||||
|
||||
set requestComp "$args[1] %[2]s $args[2..-1] $emptyArg" |
||||
__%[1]s_debug "Calling $requestComp" |
||||
|
||||
set results (eval $requestComp 2> /dev/null) |
||||
set comps $results[1..-2] |
||||
set directiveLine $results[-1] |
||||
|
||||
# For Fish, when completing a flag with an = (e.g., <program> -n=<TAB>) |
||||
# completions must be prefixed with the flag |
||||
set flagPrefix (string match -r -- '-.*=' "$lastArg") |
||||
|
||||
__%[1]s_debug "Comps: $comps" |
||||
__%[1]s_debug "DirectiveLine: $directiveLine" |
||||
__%[1]s_debug "flagPrefix: $flagPrefix" |
||||
|
||||
for comp in $comps |
||||
printf "%%s%%s\n" "$flagPrefix" "$comp" |
||||
end |
||||
|
||||
printf "%%s\n" "$directiveLine" |
||||
end |
||||
|
||||
# This function does three things: |
||||
# 1- Obtain the completions and store them in the global __%[1]s_comp_results |
||||
# 2- Set the __%[1]s_comp_do_file_comp flag if file completion should be performed |
||||
# and unset it otherwise |
||||
# 3- Return true if the completion results are not empty |
||||
function __%[1]s_prepare_completions |
||||
# Start fresh |
||||
set --erase __%[1]s_comp_do_file_comp |
||||
set --erase __%[1]s_comp_results |
||||
|
||||
# Check if the command-line is already provided. This is useful for testing. |
||||
if not set --query __%[1]s_comp_commandLine |
||||
set __%[1]s_comp_commandLine (commandline) |
||||
end |
||||
__%[1]s_debug "commandLine is: $__%[1]s_comp_commandLine" |
||||
|
||||
set results (__%[1]s_perform_completion "$__%[1]s_comp_commandLine") |
||||
set --erase __%[1]s_comp_commandLine |
||||
__%[1]s_debug "Completion results: $results" |
||||
|
||||
if test -z "$results" |
||||
__%[1]s_debug "No completion, probably due to a failure" |
||||
# Might as well do file completion, in case it helps |
||||
set --global __%[1]s_comp_do_file_comp 1 |
||||
return 0 |
||||
end |
||||
|
||||
set directive (string sub --start 2 $results[-1]) |
||||
set --global __%[1]s_comp_results $results[1..-2] |
||||
|
||||
__%[1]s_debug "Completions are: $__%[1]s_comp_results" |
||||
__%[1]s_debug "Directive is: $directive" |
||||
|
||||
if test -z "$directive" |
||||
set directive 0 |
||||
end |
||||
|
||||
set compErr (math (math --scale 0 $directive / %[3]d) %% 2) |
||||
if test $compErr -eq 1 |
||||
__%[1]s_debug "Received error directive: aborting." |
||||
# Might as well do file completion, in case it helps |
||||
set --global __%[1]s_comp_do_file_comp 1 |
||||
return 0 |
||||
end |
||||
|
||||
set nospace (math (math --scale 0 $directive / %[4]d) %% 2) |
||||
set nofiles (math (math --scale 0 $directive / %[5]d) %% 2) |
||||
|
||||
__%[1]s_debug "nospace: $nospace, nofiles: $nofiles" |
||||
|
||||
# Important not to quote the variable for count to work |
||||
set numComps (count $__%[1]s_comp_results) |
||||
__%[1]s_debug "numComps: $numComps" |
||||
|
||||
if test $numComps -eq 1; and test $nospace -ne 0 |
||||
# To support the "nospace" directive we trick the shell |
||||
# by outputting an extra, longer completion. |
||||
__%[1]s_debug "Adding second completion to perform nospace directive" |
||||
set --append __%[1]s_comp_results $__%[1]s_comp_results[1]. |
||||
end |
||||
|
||||
if test $numComps -eq 0; and test $nofiles -eq 0 |
||||
__%[1]s_debug "Requesting file completion" |
||||
set --global __%[1]s_comp_do_file_comp 1 |
||||
end |
||||
|
||||
# If we don't want file completion, we must return true even if there |
||||
# are no completions found. This is because fish will perform the last |
||||
# completion command, even if its condition is false, if no other |
||||
# completion command was triggered |
||||
return (not set --query __%[1]s_comp_do_file_comp) |
||||
end |
||||
|
||||
# Remove any pre-existing completions for the program since we will be handling all of them |
||||
# TODO this cleanup is not sufficient. Fish completions are only loaded once the user triggers |
||||
# them, so the below deletion will not work as it is run too early. What else can we do? |
||||
complete -c %[1]s -e |
||||
|
||||
# The order in which the below two lines are defined is very important so that __%[1]s_prepare_completions |
||||
# is called first. It is __%[1]s_prepare_completions that sets up the __%[1]s_comp_do_file_comp variable. |
||||
# |
||||
# This completion will be run second as complete commands are added FILO. |
||||
# It triggers file completion choices when __%[1]s_comp_do_file_comp is set. |
||||
complete -c %[1]s -n 'set --query __%[1]s_comp_do_file_comp' |
||||
|
||||
# This completion will be run first as complete commands are added FILO. |
||||
# The call to __%[1]s_prepare_completions will setup both __%[1]s_comp_results abd __%[1]s_comp_do_file_comp. |
||||
# It provides the program's completion choices. |
||||
complete -c %[1]s -n '__%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results' |
||||
|
||||
`, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp)) |
||||
} |
||||
|
||||
// GenFishCompletion generates fish completion file and writes to the passed writer.
|
||||
func (c *Command) GenFishCompletion(w io.Writer, includeDesc bool) error { |
||||
buf := new(bytes.Buffer) |
||||
genFishComp(buf, c.Name(), includeDesc) |
||||
_, err := buf.WriteTo(w) |
||||
return err |
||||
} |
||||
|
||||
// GenFishCompletionFile generates fish completion file.
|
||||
func (c *Command) GenFishCompletionFile(filename string, includeDesc bool) error { |
||||
outFile, err := os.Create(filename) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
defer outFile.Close() |
||||
|
||||
return c.GenFishCompletion(outFile, includeDesc) |
||||
} |
@ -0,0 +1,7 @@ |
||||
## Generating Fish Completions for your own cobra.Command |
||||
|
||||
Cobra supports native Fish completions generated from the root `cobra.Command`. You can use the `command.GenFishCompletion()` or `command.GenFishCompletionFile()` functions. You must provide these functions with a parameter indicating if the completions should be annotated with a description; Cobra will provide the description automatically based on usage information. You can choose to make this option configurable by your users. |
||||
|
||||
### Limitations |
||||
|
||||
* Custom completions implemented using the `ValidArgsFunction` and `RegisterFlagCompletionFunc()` are supported automatically but the ones implemented in Bash scripting are not. |
@ -0,0 +1,174 @@ |
||||
package pflag |
||||
|
||||
import ( |
||||
"fmt" |
||||
"strconv" |
||||
"strings" |
||||
) |
||||
|
||||
// -- float32Slice Value
|
||||
type float32SliceValue struct { |
||||
value *[]float32 |
||||
changed bool |
||||
} |
||||
|
||||
func newFloat32SliceValue(val []float32, p *[]float32) *float32SliceValue { |
||||
isv := new(float32SliceValue) |
||||
isv.value = p |
||||
*isv.value = val |
||||
return isv |
||||
} |
||||
|
||||
func (s *float32SliceValue) Set(val string) error { |
||||
ss := strings.Split(val, ",") |
||||
out := make([]float32, len(ss)) |
||||
for i, d := range ss { |
||||
var err error |
||||
var temp64 float64 |
||||
temp64, err = strconv.ParseFloat(d, 32) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
out[i] = float32(temp64) |
||||
|
||||
} |
||||
if !s.changed { |
||||
*s.value = out |
||||
} else { |
||||
*s.value = append(*s.value, out...) |
||||
} |
||||
s.changed = true |
||||
return nil |
||||
} |
||||
|
||||
func (s *float32SliceValue) Type() string { |
||||
return "float32Slice" |
||||
} |
||||
|
||||
func (s *float32SliceValue) String() string { |
||||
out := make([]string, len(*s.value)) |
||||
for i, d := range *s.value { |
||||
out[i] = fmt.Sprintf("%f", d) |
||||
} |
||||
return "[" + strings.Join(out, ",") + "]" |
||||
} |
||||
|
||||
func (s *float32SliceValue) fromString(val string) (float32, error) { |
||||
t64, err := strconv.ParseFloat(val, 32) |
||||
if err != nil { |
||||
return 0, err |
||||
} |
||||
return float32(t64), nil |
||||
} |
||||
|
||||
func (s *float32SliceValue) toString(val float32) string { |
||||
return fmt.Sprintf("%f", val) |
||||
} |
||||
|
||||
func (s *float32SliceValue) Append(val string) error { |
||||
i, err := s.fromString(val) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
*s.value = append(*s.value, i) |
||||
return nil |
||||
} |
||||
|
||||
func (s *float32SliceValue) Replace(val []string) error { |
||||
out := make([]float32, len(val)) |
||||
for i, d := range val { |
||||
var err error |
||||
out[i], err = s.fromString(d) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
*s.value = out |
||||
return nil |
||||
} |
||||
|
||||
func (s *float32SliceValue) GetSlice() []string { |
||||
out := make([]string, len(*s.value)) |
||||
for i, d := range *s.value { |
||||
out[i] = s.toString(d) |
||||
} |
||||
return out |
||||
} |
||||
|
||||
func float32SliceConv(val string) (interface{}, error) { |
||||
val = strings.Trim(val, "[]") |
||||
// Empty string would cause a slice with one (empty) entry
|
||||
if len(val) == 0 { |
||||
return []float32{}, nil |
||||
} |
||||
ss := strings.Split(val, ",") |
||||
out := make([]float32, len(ss)) |
||||
for i, d := range ss { |
||||
var err error |
||||
var temp64 float64 |
||||
temp64, err = strconv.ParseFloat(d, 32) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
out[i] = float32(temp64) |
||||
|
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
// GetFloat32Slice return the []float32 value of a flag with the given name
|
||||
func (f *FlagSet) GetFloat32Slice(name string) ([]float32, error) { |
||||
val, err := f.getFlagType(name, "float32Slice", float32SliceConv) |
||||
if err != nil { |
||||
return []float32{}, err |
||||
} |
||||
return val.([]float32), nil |
||||
} |
||||
|
||||
// Float32SliceVar defines a float32Slice flag with specified name, default value, and usage string.
|
||||
// The argument p points to a []float32 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Float32SliceVar(p *[]float32, name string, value []float32, usage string) { |
||||
f.VarP(newFloat32SliceValue(value, p), name, "", usage) |
||||
} |
||||
|
||||
// Float32SliceVarP is like Float32SliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Float32SliceVarP(p *[]float32, name, shorthand string, value []float32, usage string) { |
||||
f.VarP(newFloat32SliceValue(value, p), name, shorthand, usage) |
||||
} |
||||
|
||||
// Float32SliceVar defines a float32[] flag with specified name, default value, and usage string.
|
||||
// The argument p points to a float32[] variable in which to store the value of the flag.
|
||||
func Float32SliceVar(p *[]float32, name string, value []float32, usage string) { |
||||
CommandLine.VarP(newFloat32SliceValue(value, p), name, "", usage) |
||||
} |
||||
|
||||
// Float32SliceVarP is like Float32SliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Float32SliceVarP(p *[]float32, name, shorthand string, value []float32, usage string) { |
||||
CommandLine.VarP(newFloat32SliceValue(value, p), name, shorthand, usage) |
||||
} |
||||
|
||||
// Float32Slice defines a []float32 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []float32 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Float32Slice(name string, value []float32, usage string) *[]float32 { |
||||
p := []float32{} |
||||
f.Float32SliceVarP(&p, name, "", value, usage) |
||||
return &p |
||||
} |
||||
|
||||
// Float32SliceP is like Float32Slice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Float32SliceP(name, shorthand string, value []float32, usage string) *[]float32 { |
||||
p := []float32{} |
||||
f.Float32SliceVarP(&p, name, shorthand, value, usage) |
||||
return &p |
||||
} |
||||
|
||||
// Float32Slice defines a []float32 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []float32 variable that stores the value of the flag.
|
||||
func Float32Slice(name string, value []float32, usage string) *[]float32 { |
||||
return CommandLine.Float32SliceP(name, "", value, usage) |
||||
} |
||||
|
||||
// Float32SliceP is like Float32Slice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Float32SliceP(name, shorthand string, value []float32, usage string) *[]float32 { |
||||
return CommandLine.Float32SliceP(name, shorthand, value, usage) |
||||
} |
@ -0,0 +1,166 @@ |
||||
package pflag |
||||
|
||||
import ( |
||||
"fmt" |
||||
"strconv" |
||||
"strings" |
||||
) |
||||
|
||||
// -- float64Slice Value
|
||||
type float64SliceValue struct { |
||||
value *[]float64 |
||||
changed bool |
||||
} |
||||
|
||||
func newFloat64SliceValue(val []float64, p *[]float64) *float64SliceValue { |
||||
isv := new(float64SliceValue) |
||||
isv.value = p |
||||
*isv.value = val |
||||
return isv |
||||
} |
||||
|
||||
func (s *float64SliceValue) Set(val string) error { |
||||
ss := strings.Split(val, ",") |
||||
out := make([]float64, len(ss)) |
||||
for i, d := range ss { |
||||
var err error |
||||
out[i], err = strconv.ParseFloat(d, 64) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
} |
||||
if !s.changed { |
||||
*s.value = out |
||||
} else { |
||||
*s.value = append(*s.value, out...) |
||||
} |
||||
s.changed = true |
||||
return nil |
||||
} |
||||
|
||||
func (s *float64SliceValue) Type() string { |
||||
return "float64Slice" |
||||
} |
||||
|
||||
func (s *float64SliceValue) String() string { |
||||
out := make([]string, len(*s.value)) |
||||
for i, d := range *s.value { |
||||
out[i] = fmt.Sprintf("%f", d) |
||||
} |
||||
return "[" + strings.Join(out, ",") + "]" |
||||
} |
||||
|
||||
func (s *float64SliceValue) fromString(val string) (float64, error) { |
||||
return strconv.ParseFloat(val, 64) |
||||
} |
||||
|
||||
func (s *float64SliceValue) toString(val float64) string { |
||||
return fmt.Sprintf("%f", val) |
||||
} |
||||
|
||||
func (s *float64SliceValue) Append(val string) error { |
||||
i, err := s.fromString(val) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
*s.value = append(*s.value, i) |
||||
return nil |
||||
} |
||||
|
||||
func (s *float64SliceValue) Replace(val []string) error { |
||||
out := make([]float64, len(val)) |
||||
for i, d := range val { |
||||
var err error |
||||
out[i], err = s.fromString(d) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
*s.value = out |
||||
return nil |
||||
} |
||||
|
||||
func (s *float64SliceValue) GetSlice() []string { |
||||
out := make([]string, len(*s.value)) |
||||
for i, d := range *s.value { |
||||
out[i] = s.toString(d) |
||||
} |
||||
return out |
||||
} |
||||
|
||||
func float64SliceConv(val string) (interface{}, error) { |
||||
val = strings.Trim(val, "[]") |
||||
// Empty string would cause a slice with one (empty) entry
|
||||
if len(val) == 0 { |
||||
return []float64{}, nil |
||||
} |
||||
ss := strings.Split(val, ",") |
||||
out := make([]float64, len(ss)) |
||||
for i, d := range ss { |
||||
var err error |
||||
out[i], err = strconv.ParseFloat(d, 64) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
// GetFloat64Slice return the []float64 value of a flag with the given name
|
||||
func (f *FlagSet) GetFloat64Slice(name string) ([]float64, error) { |
||||
val, err := f.getFlagType(name, "float64Slice", float64SliceConv) |
||||
if err != nil { |
||||
return []float64{}, err |
||||
} |
||||
return val.([]float64), nil |
||||
} |
||||
|
||||
// Float64SliceVar defines a float64Slice flag with specified name, default value, and usage string.
|
||||
// The argument p points to a []float64 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Float64SliceVar(p *[]float64, name string, value []float64, usage string) { |
||||
f.VarP(newFloat64SliceValue(value, p), name, "", usage) |
||||
} |
||||
|
||||
// Float64SliceVarP is like Float64SliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Float64SliceVarP(p *[]float64, name, shorthand string, value []float64, usage string) { |
||||
f.VarP(newFloat64SliceValue(value, p), name, shorthand, usage) |
||||
} |
||||
|
||||
// Float64SliceVar defines a float64[] flag with specified name, default value, and usage string.
|
||||
// The argument p points to a float64[] variable in which to store the value of the flag.
|
||||
func Float64SliceVar(p *[]float64, name string, value []float64, usage string) { |
||||
CommandLine.VarP(newFloat64SliceValue(value, p), name, "", usage) |
||||
} |
||||
|
||||
// Float64SliceVarP is like Float64SliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Float64SliceVarP(p *[]float64, name, shorthand string, value []float64, usage string) { |
||||
CommandLine.VarP(newFloat64SliceValue(value, p), name, shorthand, usage) |
||||
} |
||||
|
||||
// Float64Slice defines a []float64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []float64 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Float64Slice(name string, value []float64, usage string) *[]float64 { |
||||
p := []float64{} |
||||
f.Float64SliceVarP(&p, name, "", value, usage) |
||||
return &p |
||||
} |
||||
|
||||
// Float64SliceP is like Float64Slice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Float64SliceP(name, shorthand string, value []float64, usage string) *[]float64 { |
||||
p := []float64{} |
||||
f.Float64SliceVarP(&p, name, shorthand, value, usage) |
||||
return &p |
||||
} |
||||
|
||||
// Float64Slice defines a []float64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []float64 variable that stores the value of the flag.
|
||||
func Float64Slice(name string, value []float64, usage string) *[]float64 { |
||||
return CommandLine.Float64SliceP(name, "", value, usage) |
||||
} |
||||
|
||||
// Float64SliceP is like Float64Slice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Float64SliceP(name, shorthand string, value []float64, usage string) *[]float64 { |
||||
return CommandLine.Float64SliceP(name, shorthand, value, usage) |
||||
} |
@ -0,0 +1,3 @@ |
||||
module github.com/spf13/pflag |
||||
|
||||
go 1.12 |
@ -0,0 +1,174 @@ |
||||
package pflag |
||||
|
||||
import ( |
||||
"fmt" |
||||
"strconv" |
||||
"strings" |
||||
) |
||||
|
||||
// -- int32Slice Value
|
||||
type int32SliceValue struct { |
||||
value *[]int32 |
||||
changed bool |
||||
} |
||||
|
||||
func newInt32SliceValue(val []int32, p *[]int32) *int32SliceValue { |
||||
isv := new(int32SliceValue) |
||||
isv.value = p |
||||
*isv.value = val |
||||
return isv |
||||
} |
||||
|
||||
func (s *int32SliceValue) Set(val string) error { |
||||
ss := strings.Split(val, ",") |
||||
out := make([]int32, len(ss)) |
||||
for i, d := range ss { |
||||
var err error |
||||
var temp64 int64 |
||||
temp64, err = strconv.ParseInt(d, 0, 32) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
out[i] = int32(temp64) |
||||
|
||||
} |
||||
if !s.changed { |
||||
*s.value = out |
||||
} else { |
||||
*s.value = append(*s.value, out...) |
||||
} |
||||
s.changed = true |
||||
return nil |
||||
} |
||||
|
||||
func (s *int32SliceValue) Type() string { |
||||
return "int32Slice" |
||||
} |
||||
|
||||
func (s *int32SliceValue) String() string { |
||||
out := make([]string, len(*s.value)) |
||||
for i, d := range *s.value { |
||||
out[i] = fmt.Sprintf("%d", d) |
||||
} |
||||
return "[" + strings.Join(out, ",") + "]" |
||||
} |
||||
|
||||
func (s *int32SliceValue) fromString(val string) (int32, error) { |
||||
t64, err := strconv.ParseInt(val, 0, 32) |
||||
if err != nil { |
||||
return 0, err |
||||
} |
||||
return int32(t64), nil |
||||
} |
||||
|
||||
func (s *int32SliceValue) toString(val int32) string { |
||||
return fmt.Sprintf("%d", val) |
||||
} |
||||
|
||||
func (s *int32SliceValue) Append(val string) error { |
||||
i, err := s.fromString(val) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
*s.value = append(*s.value, i) |
||||
return nil |
||||
} |
||||
|
||||
func (s *int32SliceValue) Replace(val []string) error { |
||||
out := make([]int32, len(val)) |
||||
for i, d := range val { |
||||
var err error |
||||
out[i], err = s.fromString(d) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
*s.value = out |
||||
return nil |
||||
} |
||||
|
||||
func (s *int32SliceValue) GetSlice() []string { |
||||
out := make([]string, len(*s.value)) |
||||
for i, d := range *s.value { |
||||
out[i] = s.toString(d) |
||||
} |
||||
return out |
||||
} |
||||
|
||||
func int32SliceConv(val string) (interface{}, error) { |
||||
val = strings.Trim(val, "[]") |
||||
// Empty string would cause a slice with one (empty) entry
|
||||
if len(val) == 0 { |
||||
return []int32{}, nil |
||||
} |
||||
ss := strings.Split(val, ",") |
||||
out := make([]int32, len(ss)) |
||||
for i, d := range ss { |
||||
var err error |
||||
var temp64 int64 |
||||
temp64, err = strconv.ParseInt(d, 0, 32) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
out[i] = int32(temp64) |
||||
|
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
// GetInt32Slice return the []int32 value of a flag with the given name
|
||||
func (f *FlagSet) GetInt32Slice(name string) ([]int32, error) { |
||||
val, err := f.getFlagType(name, "int32Slice", int32SliceConv) |
||||
if err != nil { |
||||
return []int32{}, err |
||||
} |
||||
return val.([]int32), nil |
||||
} |
||||
|
||||
// Int32SliceVar defines a int32Slice flag with specified name, default value, and usage string.
|
||||
// The argument p points to a []int32 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Int32SliceVar(p *[]int32, name string, value []int32, usage string) { |
||||
f.VarP(newInt32SliceValue(value, p), name, "", usage) |
||||
} |
||||
|
||||
// Int32SliceVarP is like Int32SliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Int32SliceVarP(p *[]int32, name, shorthand string, value []int32, usage string) { |
||||
f.VarP(newInt32SliceValue(value, p), name, shorthand, usage) |
||||
} |
||||
|
||||
// Int32SliceVar defines a int32[] flag with specified name, default value, and usage string.
|
||||
// The argument p points to a int32[] variable in which to store the value of the flag.
|
||||
func Int32SliceVar(p *[]int32, name string, value []int32, usage string) { |
||||
CommandLine.VarP(newInt32SliceValue(value, p), name, "", usage) |
||||
} |
||||
|
||||
// Int32SliceVarP is like Int32SliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Int32SliceVarP(p *[]int32, name, shorthand string, value []int32, usage string) { |
||||
CommandLine.VarP(newInt32SliceValue(value, p), name, shorthand, usage) |
||||
} |
||||
|
||||
// Int32Slice defines a []int32 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []int32 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Int32Slice(name string, value []int32, usage string) *[]int32 { |
||||
p := []int32{} |
||||
f.Int32SliceVarP(&p, name, "", value, usage) |
||||
return &p |
||||
} |
||||
|
||||
// Int32SliceP is like Int32Slice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Int32SliceP(name, shorthand string, value []int32, usage string) *[]int32 { |
||||
p := []int32{} |
||||
f.Int32SliceVarP(&p, name, shorthand, value, usage) |
||||
return &p |
||||
} |
||||
|
||||
// Int32Slice defines a []int32 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []int32 variable that stores the value of the flag.
|
||||
func Int32Slice(name string, value []int32, usage string) *[]int32 { |
||||
return CommandLine.Int32SliceP(name, "", value, usage) |
||||
} |
||||
|
||||
// Int32SliceP is like Int32Slice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Int32SliceP(name, shorthand string, value []int32, usage string) *[]int32 { |
||||
return CommandLine.Int32SliceP(name, shorthand, value, usage) |
||||
} |
@ -0,0 +1,166 @@ |
||||
package pflag |
||||
|
||||
import ( |
||||
"fmt" |
||||
"strconv" |
||||
"strings" |
||||
) |
||||
|
||||
// -- int64Slice Value
|
||||
type int64SliceValue struct { |
||||
value *[]int64 |
||||
changed bool |
||||
} |
||||
|
||||
func newInt64SliceValue(val []int64, p *[]int64) *int64SliceValue { |
||||
isv := new(int64SliceValue) |
||||
isv.value = p |
||||
*isv.value = val |
||||
return isv |
||||
} |
||||
|
||||
func (s *int64SliceValue) Set(val string) error { |
||||
ss := strings.Split(val, ",") |
||||
out := make([]int64, len(ss)) |
||||
for i, d := range ss { |
||||
var err error |
||||
out[i], err = strconv.ParseInt(d, 0, 64) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
} |
||||
if !s.changed { |
||||
*s.value = out |
||||
} else { |
||||
*s.value = append(*s.value, out...) |
||||
} |
||||
s.changed = true |
||||
return nil |
||||
} |
||||
|
||||
func (s *int64SliceValue) Type() string { |
||||
return "int64Slice" |
||||
} |
||||
|
||||
func (s *int64SliceValue) String() string { |
||||
out := make([]string, len(*s.value)) |
||||
for i, d := range *s.value { |
||||
out[i] = fmt.Sprintf("%d", d) |
||||
} |
||||
return "[" + strings.Join(out, ",") + "]" |
||||
} |
||||
|
||||
func (s *int64SliceValue) fromString(val string) (int64, error) { |
||||
return strconv.ParseInt(val, 0, 64) |
||||
} |
||||
|
||||
func (s *int64SliceValue) toString(val int64) string { |
||||
return fmt.Sprintf("%d", val) |
||||
} |
||||
|
||||
func (s *int64SliceValue) Append(val string) error { |
||||
i, err := s.fromString(val) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
*s.value = append(*s.value, i) |
||||
return nil |
||||
} |
||||
|
||||
func (s *int64SliceValue) Replace(val []string) error { |
||||
out := make([]int64, len(val)) |
||||
for i, d := range val { |
||||
var err error |
||||
out[i], err = s.fromString(d) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
*s.value = out |
||||
return nil |
||||
} |
||||
|
||||
func (s *int64SliceValue) GetSlice() []string { |
||||
out := make([]string, len(*s.value)) |
||||
for i, d := range *s.value { |
||||
out[i] = s.toString(d) |
||||
} |
||||
return out |
||||
} |
||||
|
||||
func int64SliceConv(val string) (interface{}, error) { |
||||
val = strings.Trim(val, "[]") |
||||
// Empty string would cause a slice with one (empty) entry
|
||||
if len(val) == 0 { |
||||
return []int64{}, nil |
||||
} |
||||
ss := strings.Split(val, ",") |
||||
out := make([]int64, len(ss)) |
||||
for i, d := range ss { |
||||
var err error |
||||
out[i], err = strconv.ParseInt(d, 0, 64) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
// GetInt64Slice return the []int64 value of a flag with the given name
|
||||
func (f *FlagSet) GetInt64Slice(name string) ([]int64, error) { |
||||
val, err := f.getFlagType(name, "int64Slice", int64SliceConv) |
||||
if err != nil { |
||||
return []int64{}, err |
||||
} |
||||
return val.([]int64), nil |
||||
} |
||||
|
||||
// Int64SliceVar defines a int64Slice flag with specified name, default value, and usage string.
|
||||
// The argument p points to a []int64 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Int64SliceVar(p *[]int64, name string, value []int64, usage string) { |
||||
f.VarP(newInt64SliceValue(value, p), name, "", usage) |
||||
} |
||||
|
||||
// Int64SliceVarP is like Int64SliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Int64SliceVarP(p *[]int64, name, shorthand string, value []int64, usage string) { |
||||
f.VarP(newInt64SliceValue(value, p), name, shorthand, usage) |
||||
} |
||||
|
||||
// Int64SliceVar defines a int64[] flag with specified name, default value, and usage string.
|
||||
// The argument p points to a int64[] variable in which to store the value of the flag.
|
||||
func Int64SliceVar(p *[]int64, name string, value []int64, usage string) { |
||||
CommandLine.VarP(newInt64SliceValue(value, p), name, "", usage) |
||||
} |
||||
|
||||
// Int64SliceVarP is like Int64SliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Int64SliceVarP(p *[]int64, name, shorthand string, value []int64, usage string) { |
||||
CommandLine.VarP(newInt64SliceValue(value, p), name, shorthand, usage) |
||||
} |
||||
|
||||
// Int64Slice defines a []int64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []int64 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Int64Slice(name string, value []int64, usage string) *[]int64 { |
||||
p := []int64{} |
||||
f.Int64SliceVarP(&p, name, "", value, usage) |
||||
return &p |
||||
} |
||||
|
||||
// Int64SliceP is like Int64Slice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Int64SliceP(name, shorthand string, value []int64, usage string) *[]int64 { |
||||
p := []int64{} |
||||
f.Int64SliceVarP(&p, name, shorthand, value, usage) |
||||
return &p |
||||
} |
||||
|
||||
// Int64Slice defines a []int64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []int64 variable that stores the value of the flag.
|
||||
func Int64Slice(name string, value []int64, usage string) *[]int64 { |
||||
return CommandLine.Int64SliceP(name, "", value, usage) |
||||
} |
||||
|
||||
// Int64SliceP is like Int64Slice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Int64SliceP(name, shorthand string, value []int64, usage string) *[]int64 { |
||||
return CommandLine.Int64SliceP(name, shorthand, value, usage) |
||||
} |
@ -0,0 +1,149 @@ |
||||
package pflag |
||||
|
||||
import ( |
||||
"bytes" |
||||
"fmt" |
||||
"strconv" |
||||
"strings" |
||||
) |
||||
|
||||
// -- stringToInt64 Value
|
||||
type stringToInt64Value struct { |
||||
value *map[string]int64 |
||||
changed bool |
||||
} |
||||
|
||||
func newStringToInt64Value(val map[string]int64, p *map[string]int64) *stringToInt64Value { |
||||
ssv := new(stringToInt64Value) |
||||
ssv.value = p |
||||
*ssv.value = val |
||||
return ssv |
||||
} |
||||
|
||||
// Format: a=1,b=2
|
||||
func (s *stringToInt64Value) Set(val string) error { |
||||
ss := strings.Split(val, ",") |
||||
out := make(map[string]int64, len(ss)) |
||||
for _, pair := range ss { |
||||
kv := strings.SplitN(pair, "=", 2) |
||||
if len(kv) != 2 { |
||||
return fmt.Errorf("%s must be formatted as key=value", pair) |
||||
} |
||||
var err error |
||||
out[kv[0]], err = strconv.ParseInt(kv[1], 10, 64) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
if !s.changed { |
||||
*s.value = out |
||||
} else { |
||||
for k, v := range out { |
||||
(*s.value)[k] = v |
||||
} |
||||
} |
||||
s.changed = true |
||||
return nil |
||||
} |
||||
|
||||
func (s *stringToInt64Value) Type() string { |
||||
return "stringToInt64" |
||||
} |
||||
|
||||
func (s *stringToInt64Value) String() string { |
||||
var buf bytes.Buffer |
||||
i := 0 |
||||
for k, v := range *s.value { |
||||
if i > 0 { |
||||
buf.WriteRune(',') |
||||
} |
||||
buf.WriteString(k) |
||||
buf.WriteRune('=') |
||||
buf.WriteString(strconv.FormatInt(v, 10)) |
||||
i++ |
||||
} |
||||
return "[" + buf.String() + "]" |
||||
} |
||||
|
||||
func stringToInt64Conv(val string) (interface{}, error) { |
||||
val = strings.Trim(val, "[]") |
||||
// An empty string would cause an empty map
|
||||
if len(val) == 0 { |
||||
return map[string]int64{}, nil |
||||
} |
||||
ss := strings.Split(val, ",") |
||||
out := make(map[string]int64, len(ss)) |
||||
for _, pair := range ss { |
||||
kv := strings.SplitN(pair, "=", 2) |
||||
if len(kv) != 2 { |
||||
return nil, fmt.Errorf("%s must be formatted as key=value", pair) |
||||
} |
||||
var err error |
||||
out[kv[0]], err = strconv.ParseInt(kv[1], 10, 64) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
// GetStringToInt64 return the map[string]int64 value of a flag with the given name
|
||||
func (f *FlagSet) GetStringToInt64(name string) (map[string]int64, error) { |
||||
val, err := f.getFlagType(name, "stringToInt64", stringToInt64Conv) |
||||
if err != nil { |
||||
return map[string]int64{}, err |
||||
} |
||||
return val.(map[string]int64), nil |
||||
} |
||||
|
||||
// StringToInt64Var defines a string flag with specified name, default value, and usage string.
|
||||
// The argument p point64s to a map[string]int64 variable in which to store the values of the multiple flags.
|
||||
// The value of each argument will not try to be separated by comma
|
||||
func (f *FlagSet) StringToInt64Var(p *map[string]int64, name string, value map[string]int64, usage string) { |
||||
f.VarP(newStringToInt64Value(value, p), name, "", usage) |
||||
} |
||||
|
||||
// StringToInt64VarP is like StringToInt64Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) StringToInt64VarP(p *map[string]int64, name, shorthand string, value map[string]int64, usage string) { |
||||
f.VarP(newStringToInt64Value(value, p), name, shorthand, usage) |
||||
} |
||||
|
||||
// StringToInt64Var defines a string flag with specified name, default value, and usage string.
|
||||
// The argument p point64s to a map[string]int64 variable in which to store the value of the flag.
|
||||
// The value of each argument will not try to be separated by comma
|
||||
func StringToInt64Var(p *map[string]int64, name string, value map[string]int64, usage string) { |
||||
CommandLine.VarP(newStringToInt64Value(value, p), name, "", usage) |
||||
} |
||||
|
||||
// StringToInt64VarP is like StringToInt64Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func StringToInt64VarP(p *map[string]int64, name, shorthand string, value map[string]int64, usage string) { |
||||
CommandLine.VarP(newStringToInt64Value(value, p), name, shorthand, usage) |
||||
} |
||||
|
||||
// StringToInt64 defines a string flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a map[string]int64 variable that stores the value of the flag.
|
||||
// The value of each argument will not try to be separated by comma
|
||||
func (f *FlagSet) StringToInt64(name string, value map[string]int64, usage string) *map[string]int64 { |
||||
p := map[string]int64{} |
||||
f.StringToInt64VarP(&p, name, "", value, usage) |
||||
return &p |
||||
} |
||||
|
||||
// StringToInt64P is like StringToInt64, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) StringToInt64P(name, shorthand string, value map[string]int64, usage string) *map[string]int64 { |
||||
p := map[string]int64{} |
||||
f.StringToInt64VarP(&p, name, shorthand, value, usage) |
||||
return &p |
||||
} |
||||
|
||||
// StringToInt64 defines a string flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a map[string]int64 variable that stores the value of the flag.
|
||||
// The value of each argument will not try to be separated by comma
|
||||
func StringToInt64(name string, value map[string]int64, usage string) *map[string]int64 { |
||||
return CommandLine.StringToInt64P(name, "", value, usage) |
||||
} |
||||
|
||||
// StringToInt64P is like StringToInt64, but accepts a shorthand letter that can be used after a single dash.
|
||||
func StringToInt64P(name, shorthand string, value map[string]int64, usage string) *map[string]int64 { |
||||
return CommandLine.StringToInt64P(name, shorthand, value, usage) |
||||
} |
Loading…
Reference in new issue