| /* |
| * |
| * 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, ",") |
| } |