| /* | |
| * | |
| * Copyright 2019 gRPC authors. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| * | |
| */ | |
| /* | |
| Package flags provide convenience types and routines to accept specific types | |
| of flag values on the command line. | |
| */ | |
| package flags | |
| import ( | |
| "bytes" | |
| "encoding/csv" | |
| "flag" | |
| "fmt" | |
| "strconv" | |
| "strings" | |
| "time" | |
| ) | |
| // stringFlagWithAllowedValues represents a string flag which can only take a | |
| // predefined set of values. | |
| type stringFlagWithAllowedValues struct { | |
| val string | |
| allowed []string | |
| } | |
| // StringWithAllowedValues returns a flag variable of type | |
| // stringFlagWithAllowedValues configured with the provided parameters. | |
| // 'allowed` is the set of values that this flag can be set to. | |
| func StringWithAllowedValues(name, defaultVal, usage string, allowed []string) *string { | |
| as := &stringFlagWithAllowedValues{defaultVal, allowed} | |
| flag.CommandLine.Var(as, name, usage) | |
| return &as.val | |
| } | |
| // String implements the flag.Value interface. | |
| func (as *stringFlagWithAllowedValues) String() string { | |
| return as.val | |
| } | |
| // Set implements the flag.Value interface. | |
| func (as *stringFlagWithAllowedValues) Set(val string) error { | |
| for _, a := range as.allowed { | |
| if a == val { | |
| as.val = val | |
| return nil | |
| } | |
| } | |
| return fmt.Errorf("want one of: %v", strings.Join(as.allowed, ", ")) | |
| } | |
| type durationSliceValue []time.Duration | |
| // DurationSlice returns a flag representing a slice of time.Duration objects. | |
| func DurationSlice(name string, defaultVal []time.Duration, usage string) *[]time.Duration { | |
| ds := make([]time.Duration, len(defaultVal)) | |
| copy(ds, defaultVal) | |
| dsv := (*durationSliceValue)(&ds) | |
| flag.CommandLine.Var(dsv, name, usage) | |
| return &ds | |
| } | |
| // Set implements the flag.Value interface. | |
| func (dsv *durationSliceValue) Set(s string) error { | |
| ds := strings.Split(s, ",") | |
| var dd []time.Duration | |
| for _, n := range ds { | |
| d, err := time.ParseDuration(n) | |
| if err != nil { | |
| return err | |
| } | |
| dd = append(dd, d) | |
| } | |
| *dsv = durationSliceValue(dd) | |
| return nil | |
| } | |
| // String implements the flag.Value interface. | |
| func (dsv *durationSliceValue) String() string { | |
| var b bytes.Buffer | |
| for i, d := range *dsv { | |
| if i > 0 { | |
| b.WriteRune(',') | |
| } | |
| b.WriteString(d.String()) | |
| } | |
| return b.String() | |
| } | |
| type intSliceValue []int | |
| // IntSlice returns a flag representing a slice of ints. | |
| func IntSlice(name string, defaultVal []int, usage string) *[]int { | |
| is := make([]int, len(defaultVal)) | |
| copy(is, defaultVal) | |
| isv := (*intSliceValue)(&is) | |
| flag.CommandLine.Var(isv, name, usage) | |
| return &is | |
| } | |
| // Set implements the flag.Value interface. | |
| func (isv *intSliceValue) Set(s string) error { | |
| is := strings.Split(s, ",") | |
| var ret []int | |
| for _, n := range is { | |
| i, err := strconv.Atoi(n) | |
| if err != nil { | |
| return err | |
| } | |
| ret = append(ret, i) | |
| } | |
| *isv = intSliceValue(ret) | |
| return nil | |
| } | |
| // String implements the flag.Value interface. | |
| func (isv *intSliceValue) String() string { | |
| var b bytes.Buffer | |
| for i, n := range *isv { | |
| if i > 0 { | |
| b.WriteRune(',') | |
| } | |
| b.WriteString(strconv.Itoa(n)) | |
| } | |
| return b.String() | |
| } | |
| type stringSliceValue []string | |
| // StringSlice returns a flag representing a slice of strings. | |
| func StringSlice(name string, defaultVal []string, usage string) *[]string { | |
| ss := make([]string, len(defaultVal)) | |
| copy(ss, defaultVal) | |
| ssv := (*stringSliceValue)(&ss) | |
| flag.CommandLine.Var(ssv, name, usage) | |
| return &ss | |
| } | |
| // escapedCommaSplit splits a comma-separated list of strings in the same way | |
| // CSV files work (escaping a comma requires double-quotes). | |
| func escapedCommaSplit(str string) ([]string, error) { | |
| r := csv.NewReader(strings.NewReader(str)) | |
| ret, err := r.Read() | |
| if err != nil { | |
| return nil, err | |
| } | |
| return ret, nil | |
| } | |
| // Set implements the flag.Value interface. | |
| func (ss *stringSliceValue) Set(str string) error { | |
| var err error | |
| *ss, err = escapedCommaSplit(str) | |
| if err != nil { | |
| return err | |
| } | |
| return nil | |
| } | |
| // String implements the flag.Value interface. | |
| func (ss *stringSliceValue) String() string { | |
| return strings.Join(*ss, ",") | |
| } |