get.porter.sh/porter@v1.3.0/pkg/exec/builder/flags.go (about)

     1  package builder
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  )
     7  
     8  // Flag represents a flag passed to a mixin command.
     9  type Flag struct {
    10  	Name   string
    11  	Values []string
    12  }
    13  
    14  type Dashes struct {
    15  	Long  string
    16  	Short string
    17  }
    18  
    19  // NewFlag creates an instance of a Flag.
    20  func NewFlag(name string, values ...string) Flag {
    21  	f := Flag{
    22  		Name: name,
    23  	}
    24  	if len(values) > 0 {
    25  		f.Values = make([]string, len(values))
    26  		copy(f.Values, values)
    27  	}
    28  	return f
    29  }
    30  
    31  // ToSlice converts to a string array suitable of command arguments suitable for passing to exec.Command
    32  func (flag Flag) ToSlice(dashes Dashes) []string {
    33  	var flagName string
    34  	dash := dashes.Long
    35  	if len(flag.Name) == 1 {
    36  		dash = dashes.Short
    37  	}
    38  	flagName = fmt.Sprintf("%s%s", dash, flag.Name)
    39  
    40  	result := make([]string, 0, len(flag.Values)+1)
    41  	if len(flag.Values) == 0 {
    42  		result = append(result, flagName)
    43  	} else {
    44  		for _, value := range flag.Values {
    45  			result = append(result, flagName)
    46  			result = append(result, value)
    47  		}
    48  	}
    49  	return result
    50  }
    51  
    52  type Flags []Flag
    53  
    54  // ToSlice converts to a string array suitable of command arguments suitable for passing to exec.Command
    55  func (flags *Flags) ToSlice(dashes Dashes) []string {
    56  	result := make([]string, 0, 2*len(*flags))
    57  
    58  	sort.Sort(flags)
    59  	for _, flag := range *flags {
    60  		result = append(result, flag.ToSlice(dashes)...)
    61  	}
    62  
    63  	return result
    64  }
    65  
    66  // UnmarshalYAML takes input like this
    67  // flags:
    68  //   flag1: value
    69  //   flag2: value
    70  //   flag3:
    71  //   - value1
    72  //   - value2
    73  //
    74  // and turns it into this:
    75  //
    76  // []Flags{ {"flag1", []string{"value"}}, {"flag2", []string{"value"}}, {"flag3", []string{"value1", "value2"} }
    77  func (flags *Flags) UnmarshalYAML(unmarshal func(interface{}) error) error {
    78  	flagMap := map[string]interface{}{}
    79  	err := unmarshal(&flagMap)
    80  	if err != nil {
    81  		return fmt.Errorf("could not unmarshal yaml into Step.Flags: %w", err)
    82  	}
    83  
    84  	*flags = make(Flags, 0, len(flagMap))
    85  	for k, v := range flagMap {
    86  		f := Flag{}
    87  		f.Name = k
    88  
    89  		switch t := v.(type) {
    90  		case []interface{}:
    91  			f.Values = make([]string, len(t))
    92  			for i := range t {
    93  				iv, ok := t[i].(string)
    94  				if !ok {
    95  					return fmt.Errorf("invalid yaml type for flag %s: %T", f.Name, t[i])
    96  				}
    97  				f.Values[i] = iv
    98  			}
    99  		case nil:
   100  			// do nothing
   101  		default:
   102  			f.Values = make([]string, 1)
   103  			f.Values[0] = fmt.Sprintf("%v", v)
   104  		}
   105  
   106  		*flags = append(*flags, f)
   107  	}
   108  
   109  	return nil
   110  }
   111  
   112  // MarshalYAML writes out flags back into the proper format for mixin flags.
   113  // Input:
   114  // []Flags{ {"flag1", []string{"value"}}, {"flag2", []string{"value"}}, {"flag3", []string{"value1", "value2"} }
   115  //
   116  // Is turned into
   117  //
   118  // flags:
   119  //   flag1: value
   120  //   flag2: value
   121  //   flag3:
   122  //   - value1
   123  //   - value2
   124  func (flags Flags) MarshalYAML() (interface{}, error) {
   125  	result := make(map[string]interface{}, len(flags))
   126  
   127  	for _, flag := range flags {
   128  		if len(flag.Values) == 1 {
   129  			result[flag.Name] = flag.Values[0]
   130  		} else {
   131  			result[flag.Name] = flag.Values
   132  		}
   133  	}
   134  
   135  	return result, nil
   136  }
   137  
   138  func (flags Flags) Len() int {
   139  	return len(flags)
   140  }
   141  
   142  func (flags Flags) Swap(i, j int) {
   143  	flags[i], flags[j] = flags[j], flags[i]
   144  }
   145  
   146  func (flags Flags) Less(i, j int) bool {
   147  	return flags[i].Name < flags[j].Name
   148  }