github.1git.de/docker/cli@v26.1.3+incompatible/cli/command/swarm/ipnet_slice.go (about)

     1  package swarm
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/csv"
     6  	"fmt"
     7  	"io"
     8  	"net"
     9  	"strings"
    10  )
    11  
    12  // -- ipNetSlice Value
    13  type ipNetSliceValue struct {
    14  	value   *[]net.IPNet
    15  	changed bool
    16  }
    17  
    18  func newIPNetSliceValue(val []net.IPNet, p *[]net.IPNet) *ipNetSliceValue {
    19  	ipnsv := new(ipNetSliceValue)
    20  	ipnsv.value = p
    21  	*ipnsv.value = val
    22  	return ipnsv
    23  }
    24  
    25  // Set converts, and assigns, the comma-separated IPNet argument string representation as the []net.IPNet value of this flag.
    26  // If Set is called on a flag that already has a []net.IPNet assigned, the newly converted values will be appended.
    27  func (s *ipNetSliceValue) Set(val string) error {
    28  	// remove all quote characters
    29  	rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "")
    30  
    31  	// read flag arguments with CSV parser
    32  	ipNetStrSlice, err := readAsCSV(rmQuote.Replace(val))
    33  	if err != nil && err != io.EOF {
    34  		return err
    35  	}
    36  
    37  	// parse ip values into slice
    38  	out := make([]net.IPNet, 0, len(ipNetStrSlice))
    39  	for _, ipNetStr := range ipNetStrSlice {
    40  		_, n, err := net.ParseCIDR(strings.TrimSpace(ipNetStr))
    41  		if err != nil {
    42  			return fmt.Errorf("invalid string being converted to CIDR: %s", ipNetStr)
    43  		}
    44  		out = append(out, *n)
    45  	}
    46  
    47  	if !s.changed {
    48  		*s.value = out
    49  	} else {
    50  		*s.value = append(*s.value, out...)
    51  	}
    52  
    53  	s.changed = true
    54  
    55  	return nil
    56  }
    57  
    58  // Type returns a string that uniquely represents this flag's type.
    59  func (s *ipNetSliceValue) Type() string {
    60  	return "ipNetSlice"
    61  }
    62  
    63  // String defines a "native" format for this net.IPNet slice flag value.
    64  func (s *ipNetSliceValue) String() string {
    65  	ipNetStrSlice := make([]string, len(*s.value))
    66  	for i, n := range *s.value {
    67  		ipNetStrSlice[i] = n.String()
    68  	}
    69  
    70  	out, _ := writeAsCSV(ipNetStrSlice)
    71  	return "[" + out + "]"
    72  }
    73  
    74  func readAsCSV(val string) ([]string, error) {
    75  	if val == "" {
    76  		return []string{}, nil
    77  	}
    78  	stringReader := strings.NewReader(val)
    79  	csvReader := csv.NewReader(stringReader)
    80  	return csvReader.Read()
    81  }
    82  
    83  func writeAsCSV(vals []string) (string, error) {
    84  	b := &bytes.Buffer{}
    85  	w := csv.NewWriter(b)
    86  	err := w.Write(vals)
    87  	if err != nil {
    88  		return "", err
    89  	}
    90  	w.Flush()
    91  	return strings.TrimSuffix(b.String(), "\n"), nil
    92  }