vitess.io/vitess@v0.16.2/go/flagutil/optional.go (about)

     1  /*
     2  Copyright 2021 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package flagutil
    18  
    19  import (
    20  	"errors"
    21  	"strconv"
    22  
    23  	"github.com/spf13/pflag"
    24  )
    25  
    26  // OptionalFlag augements the pflag.Value interface with a method to determine
    27  // if a flag was set explicitly on the comand-line.
    28  //
    29  // Though not part of the interface, because the return type would be different
    30  // for each implementation, by convention, each implementation should define a
    31  // Get() method to access the underlying value.
    32  //
    33  // TODO (ajm188) - replace this interface with a generic type.
    34  // c.f. https://github.com/vitessio/vitess/issues/11154.
    35  type OptionalFlag interface {
    36  	pflag.Value
    37  	IsSet() bool
    38  }
    39  
    40  var (
    41  	_ OptionalFlag = (*OptionalFloat64)(nil)
    42  	_ OptionalFlag = (*OptionalString)(nil)
    43  )
    44  
    45  // OptionalFloat64 implements OptionalFlag for float64 values.
    46  type OptionalFloat64 struct {
    47  	val float64
    48  	set bool
    49  }
    50  
    51  // NewOptionalFloat64 returns an OptionalFloat64 with the specified value as its
    52  // starting value.
    53  func NewOptionalFloat64(val float64) *OptionalFloat64 {
    54  	return &OptionalFloat64{
    55  		val: val,
    56  		set: false,
    57  	}
    58  }
    59  
    60  // Set is part of the pflag.Value interface.
    61  func (f *OptionalFloat64) Set(arg string) error {
    62  	v, err := strconv.ParseFloat(arg, 64)
    63  	if err != nil {
    64  		return numError(err)
    65  	}
    66  
    67  	f.val = v
    68  	f.set = true
    69  
    70  	return nil
    71  }
    72  
    73  // String is part of the pflag.Value interface.
    74  func (f *OptionalFloat64) String() string {
    75  	return strconv.FormatFloat(f.val, 'g', -1, 64)
    76  }
    77  
    78  // Type is part of the pflag.Value interface.
    79  func (f *OptionalFloat64) Type() string {
    80  	return "float64"
    81  }
    82  
    83  // Get returns the underlying float64 value of this flag. If the flag was not
    84  // explicitly set, this will be the initial value passed to the constructor.
    85  func (f *OptionalFloat64) Get() float64 {
    86  	return f.val
    87  }
    88  
    89  // IsSet is part of the OptionalFlag interface.
    90  func (f *OptionalFloat64) IsSet() bool {
    91  	return f.set
    92  }
    93  
    94  // OptionalString implements OptionalFlag for string values.
    95  type OptionalString struct {
    96  	val string
    97  	set bool
    98  }
    99  
   100  // NewOptionalString returns an OptionalString with the specified value as its
   101  // starting value.
   102  func NewOptionalString(val string) *OptionalString {
   103  	return &OptionalString{
   104  		val: val,
   105  		set: false,
   106  	}
   107  }
   108  
   109  // Set is part of the pflag.Value interface.
   110  func (f *OptionalString) Set(arg string) error {
   111  	f.val = arg
   112  	f.set = true
   113  	return nil
   114  }
   115  
   116  // String is part of the pflag.Value interface.
   117  func (f *OptionalString) String() string {
   118  	return f.val
   119  }
   120  
   121  // Type is part of the pflag.Value interface.
   122  func (f *OptionalString) Type() string {
   123  	return "string"
   124  }
   125  
   126  // Get returns the underlying string value of this flag. If the flag was not
   127  // explicitly set, this will be the initial value passed to the constructor.
   128  func (f *OptionalString) Get() string {
   129  	return f.val
   130  }
   131  
   132  // IsSet is part of the OptionalFlag interface.
   133  func (f *OptionalString) IsSet() bool {
   134  	return f.set
   135  }
   136  
   137  // lifted directly from package flag to make the behavior of numeric parsing
   138  // consistent with the standard library for our custom optional types.
   139  var (
   140  	errParse = errors.New("parse error")
   141  	errRange = errors.New("value out of range")
   142  )
   143  
   144  // lifted directly from package flag to make the behavior of numeric parsing
   145  // consistent with the standard library for our custom optional types.
   146  func numError(err error) error {
   147  	ne, ok := err.(*strconv.NumError)
   148  	if !ok {
   149  		return err
   150  	}
   151  
   152  	switch ne.Err {
   153  	case strconv.ErrSyntax:
   154  		return errParse
   155  	case strconv.ErrRange:
   156  		return errRange
   157  	default:
   158  		return err
   159  	}
   160  }