github.com/panekj/cli@v0.0.0-20230304125325-467dd2f3797e/opts/config.go (about)

     1  package opts
     2  
     3  import (
     4  	"encoding/csv"
     5  	"fmt"
     6  	"os"
     7  	"strconv"
     8  	"strings"
     9  
    10  	swarmtypes "github.com/docker/docker/api/types/swarm"
    11  )
    12  
    13  // ConfigOpt is a Value type for parsing configs
    14  type ConfigOpt struct {
    15  	values []*swarmtypes.ConfigReference
    16  }
    17  
    18  // Set a new config value
    19  func (o *ConfigOpt) Set(value string) error {
    20  	csvReader := csv.NewReader(strings.NewReader(value))
    21  	fields, err := csvReader.Read()
    22  	if err != nil {
    23  		return err
    24  	}
    25  
    26  	options := &swarmtypes.ConfigReference{
    27  		File: &swarmtypes.ConfigReferenceFileTarget{
    28  			UID:  "0",
    29  			GID:  "0",
    30  			Mode: 0o444,
    31  		},
    32  	}
    33  
    34  	// support a simple syntax of --config foo
    35  	if len(fields) == 1 && !strings.Contains(fields[0], "=") {
    36  		options.File.Name = fields[0]
    37  		options.ConfigName = fields[0]
    38  		o.values = append(o.values, options)
    39  		return nil
    40  	}
    41  
    42  	for _, field := range fields {
    43  		key, val, ok := strings.Cut(field, "=")
    44  		if !ok || key == "" {
    45  			return fmt.Errorf("invalid field '%s' must be a key=value pair", field)
    46  		}
    47  
    48  		// TODO(thaJeztah): these options should not be case-insensitive.
    49  		switch strings.ToLower(key) {
    50  		case "source", "src":
    51  			options.ConfigName = val
    52  		case "target":
    53  			options.File.Name = val
    54  		case "uid":
    55  			options.File.UID = val
    56  		case "gid":
    57  			options.File.GID = val
    58  		case "mode":
    59  			m, err := strconv.ParseUint(val, 0, 32)
    60  			if err != nil {
    61  				return fmt.Errorf("invalid mode specified: %v", err)
    62  			}
    63  
    64  			options.File.Mode = os.FileMode(m)
    65  		default:
    66  			return fmt.Errorf("invalid field in config request: %s", key)
    67  		}
    68  	}
    69  
    70  	if options.ConfigName == "" {
    71  		return fmt.Errorf("source is required")
    72  	}
    73  	if options.File.Name == "" {
    74  		options.File.Name = options.ConfigName
    75  	}
    76  
    77  	o.values = append(o.values, options)
    78  	return nil
    79  }
    80  
    81  // Type returns the type of this option
    82  func (o *ConfigOpt) Type() string {
    83  	return "config"
    84  }
    85  
    86  // String returns a string repr of this option
    87  func (o *ConfigOpt) String() string {
    88  	configs := []string{}
    89  	for _, config := range o.values {
    90  		repr := fmt.Sprintf("%s -> %s", config.ConfigName, config.File.Name)
    91  		configs = append(configs, repr)
    92  	}
    93  	return strings.Join(configs, ", ")
    94  }
    95  
    96  // Value returns the config requests
    97  func (o *ConfigOpt) Value() []*swarmtypes.ConfigReference {
    98  	return o.values
    99  }