github.com/containerd/nerdctl@v1.7.7/pkg/strutil/strutil.go (about) 1 /* 2 Copyright The containerd 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 /* 18 Portions from https://github.com/moby/moby/blob/v20.10.0-rc2/runconfig/opts/parse.go 19 Copyright (C) Docker/Moby authors. 20 Licensed under the Apache License, Version 2.0 21 NOTICE: https://github.com/moby/moby/blob/v20.10.0-rc2/NOTICE 22 */ 23 24 /* 25 Portions from https://github.com/moby/buildkit/blob/v0.9.1/cmd/buildkitd/config.go#L35-L42 26 Copyright (C) BuildKit authors. 27 Licensed under the Apache License, Version 2.0 28 */ 29 30 package strutil 31 32 import ( 33 "encoding/csv" 34 "fmt" 35 "reflect" 36 "strconv" 37 "strings" 38 39 "github.com/containerd/errdefs" 40 ) 41 42 // ConvertKVStringsToMap is from https://github.com/moby/moby/blob/v20.10.0-rc2/runconfig/opts/parse.go 43 // 44 // ConvertKVStringsToMap converts ["key=value"] to {"key":"value"} 45 func ConvertKVStringsToMap(values []string) map[string]string { 46 result := make(map[string]string, len(values)) 47 for _, value := range values { 48 kv := strings.SplitN(value, "=", 2) 49 if len(kv) == 1 { 50 result[kv[0]] = "" 51 } else { 52 result[kv[0]] = kv[1] 53 } 54 } 55 56 return result 57 } 58 59 // InStringSlice checks whether a string is inside a string slice. 60 // Comparison is case insensitive. 61 // 62 // From https://github.com/containerd/containerd/blob/7c6d710bcfc81a30ac1e8cbb2e6a4c294184f7b7/pkg/cri/util/strings.go#L21-L30 63 func InStringSlice(ss []string, str string) bool { 64 for _, s := range ss { 65 if strings.EqualFold(s, str) { 66 return true 67 } 68 } 69 return false 70 } 71 72 func DedupeStrSlice(in []string) []string { 73 m := make(map[string]struct{}) 74 var res []string 75 for _, s := range in { 76 if _, ok := m[s]; !ok { 77 res = append(res, s) 78 m[s] = struct{}{} 79 } 80 } 81 return res 82 } 83 84 // SliceToSet converts a slice of strings into a set. 85 // In Go, a set is often represented as a map with keys as the set elements and values as boolean. 86 // This function iterates over the slice, adding each string as a key in the map. 87 // The corresponding map value is set to true, serving as a placeholder. 88 // The resulting map can be used to quickly check the presence of an element in the set. 89 func SliceToSet(in []string) map[string]bool { 90 set := make(map[string]bool) 91 for _, s := range in { 92 set[s] = true 93 } 94 return set 95 } 96 97 // ParseCSVMap parses a string like "foo=x,bar=y" into a map 98 func ParseCSVMap(s string) (map[string]string, error) { 99 csvR := csv.NewReader(strings.NewReader(s)) 100 // s can contains quotes, but the csv reader needs LazyQuotes to recognize quotes as values. 101 csvR.LazyQuotes = true 102 ra, err := csvR.ReadAll() 103 if err != nil { 104 return nil, fmt.Errorf("cannot parse %q: %w", s, err) 105 } 106 if len(ra) != 1 { 107 return nil, fmt.Errorf("expected a single line, got %d lines: %w", len(ra), errdefs.ErrInvalidArgument) 108 } 109 fields := ra[0] 110 m := make(map[string]string) 111 for _, field := range fields { 112 kv := strings.SplitN(field, "=", 2) 113 if len(kv) == 2 { 114 m[kv[0]] = kv[1] 115 } else { 116 m[kv[0]] = "" 117 } 118 } 119 return m, nil 120 } 121 122 func TrimStrSliceRight(base, extra []string) []string { 123 for i := 0; i < len(base); i++ { 124 if reflect.DeepEqual(base[i:], extra) { 125 return base[:i] 126 } 127 } 128 return base 129 } 130 131 func ReverseStrSlice(in []string) []string { 132 out := make([]string, len(in)) 133 for i, v := range in { 134 out[len(in)-i-1] = v 135 } 136 return out 137 } 138 139 // ParseBoolOrAuto returns (nil, nil) if s is "auto" 140 // https://github.com/moby/buildkit/blob/v0.9.1/cmd/buildkitd/config.go#L35-L42 141 func ParseBoolOrAuto(s string) (*bool, error) { 142 if s == "" || strings.ToLower(s) == "auto" { 143 return nil, nil 144 } 145 b, err := strconv.ParseBool(s) 146 return &b, err 147 }