github.com/GuanceCloud/cliutils@v1.1.21/pipeline/ptinput/funcs/fn_kv.go (about) 1 // Unless explicitly stated otherwise all files in this repository are licensed 2 // under the MIT License. 3 // This product includes software developed at Guance Cloud (https://www.guance.com/). 4 // Copyright 2021-present Guance, Inc. 5 6 package funcs 7 8 import ( 9 "fmt" 10 "regexp" 11 "strings" 12 "sync" 13 14 "github.com/GuanceCloud/cliutils/pipeline/ptinput" 15 "github.com/GuanceCloud/platypus/pkg/ast" 16 "github.com/GuanceCloud/platypus/pkg/engine/runtime" 17 "github.com/GuanceCloud/platypus/pkg/errchain" 18 ) 19 20 var ( 21 _defaultFieldSplitPattern = regexp.MustCompile(" ") 22 _defaultValueSplitPattern = regexp.MustCompile("=") 23 ) 24 25 var _regexpCache = reCache{ 26 m: map[string]*regexp.Regexp{}, 27 } 28 29 type reCache struct { 30 m map[string]*regexp.Regexp 31 sync.RWMutex 32 } 33 34 func (c *reCache) set(p string) error { 35 c.Lock() 36 defer c.Unlock() 37 38 if c.m == nil { 39 return fmt.Errorf("nil ptr") 40 } 41 42 if r, err := regexp.Compile(p); err != nil { 43 return err 44 } else { 45 c.m[p] = r 46 } 47 48 return nil 49 } 50 51 func (c *reCache) get(p string) (*regexp.Regexp, bool) { 52 c.RLock() 53 defer c.RUnlock() 54 if c.m != nil { 55 v, ok := c.m[p] 56 return v, ok 57 } 58 59 return nil, false 60 } 61 62 func KVSplitChecking(ctx *runtime.Task, funcExpr *ast.CallExpr) *errchain.PlError { 63 if err := normalizeFuncArgsDeprecated(funcExpr, []string{ 64 "key", "field_split_pattern", "value_split_pattern", 65 "trim_key", "trim_value", "include_keys", "prefix", 66 }, 1); err != nil { 67 return runtime.NewRunError(ctx, err.Error(), funcExpr.NamePos) 68 } 69 70 if _, err := getKeyName(funcExpr.Param[0]); err != nil { 71 return runtime.NewRunError(ctx, err.Error(), funcExpr.Param[0].StartPos()) 72 } 73 74 // field_split_pattern 75 if funcExpr.Param[1] != nil { 76 switch funcExpr.Param[1].NodeType { //nolint:exhaustive 77 case ast.TypeStringLiteral: 78 p := funcExpr.Param[1].StringLiteral().Val 79 if err := _regexpCache.set(p); err != nil { 80 return runtime.NewRunError(ctx, err.Error(), funcExpr.Param[1].StartPos()) 81 } 82 default: 83 return runtime.NewRunError(ctx, fmt.Sprintf("param field_split_pattern expect StringLiteral, got %s", 84 funcExpr.Param[0].NodeType), funcExpr.NamePos) 85 } 86 } 87 88 // value_split_pattern 89 if funcExpr.Param[2] != nil { 90 switch funcExpr.Param[2].NodeType { //nolint:exhaustive 91 case ast.TypeStringLiteral: 92 p := funcExpr.Param[2].StringLiteral().Val 93 if err := _regexpCache.set(p); err != nil { 94 return runtime.NewRunError(ctx, err.Error(), funcExpr.Param[2].StartPos()) 95 } 96 default: 97 return runtime.NewRunError(ctx, fmt.Sprintf("param value_split_pattern expect StringLiteral, got %s", 98 funcExpr.Param[2].NodeType), funcExpr.NamePos) 99 } 100 } 101 102 if funcExpr.Param[3] != nil { 103 switch funcExpr.Param[3].NodeType { //nolint:exhaustive 104 case ast.TypeStringLiteral: 105 default: 106 return runtime.NewRunError(ctx, fmt.Sprintf("param trim_key expect StringLiteral, got %s", 107 funcExpr.Param[3].NodeType), funcExpr.NamePos) 108 } 109 } 110 111 if funcExpr.Param[4] != nil { 112 switch funcExpr.Param[4].NodeType { //nolint:exhaustive 113 case ast.TypeStringLiteral: 114 default: 115 return runtime.NewRunError(ctx, fmt.Sprintf("param trim_value expect StringLiteral, got %s", 116 funcExpr.Param[4].NodeType), funcExpr.NamePos) 117 } 118 } 119 120 if funcExpr.Param[5] != nil { 121 switch funcExpr.Param[5].NodeType { //nolint:exhaustive 122 case ast.TypeListLiteral, ast.TypeIdentifier: 123 default: 124 return runtime.NewRunError(ctx, fmt.Sprintf("param include_keys expect ListInitExpr or Identifier, got %s", 125 funcExpr.Param[5].NodeType), funcExpr.NamePos) 126 } 127 } 128 129 if funcExpr.Param[6] != nil { 130 switch funcExpr.Param[6].NodeType { //nolint:exhaustive 131 case ast.TypeStringLiteral: 132 default: 133 return runtime.NewRunError(ctx, fmt.Sprintf("param prefix expect StringLiteral, got %s", 134 funcExpr.Param[6].NodeType), funcExpr.NamePos) 135 } 136 } 137 return nil 138 } 139 140 func KVSplit(ctx *runtime.Task, funcExpr *ast.CallExpr) *errchain.PlError { 141 key, err := getKeyName(funcExpr.Param[0]) 142 if err != nil { 143 return runtime.NewRunError(ctx, err.Error(), funcExpr.Param[0].StartPos()) 144 } 145 146 val, err := ctx.GetKeyConv2Str(key) 147 if err != nil { 148 ctx.Regs.ReturnAppend(false, ast.Bool) 149 return nil 150 } 151 152 var fieldSplit, valueSplit *regexp.Regexp 153 154 // field_split_pattern 155 if funcExpr.Param[1] != nil { 156 switch funcExpr.Param[1].NodeType { //nolint:exhaustive 157 case ast.TypeStringLiteral: 158 p := funcExpr.Param[1].StringLiteral().Val 159 var ok bool 160 161 fieldSplit, ok = _regexpCache.get(p) 162 if !ok { 163 l.Debugf("field split pattern %s not found", p) 164 ctx.Regs.ReturnAppend(false, ast.Bool) 165 return nil 166 } 167 default: 168 return runtime.NewRunError(ctx, fmt.Sprintf("param field_split_pattern expect StringLiteral, got %s", 169 funcExpr.Param[0].NodeType), funcExpr.NamePos) 170 } 171 } 172 173 if funcExpr.Param[2] != nil { 174 switch funcExpr.Param[2].NodeType { //nolint:exhaustive 175 case ast.TypeStringLiteral: 176 p := funcExpr.Param[2].StringLiteral().Val 177 178 var ok bool 179 180 valueSplit, ok = _regexpCache.get(p) 181 if !ok { 182 l.Debugf("value split pattern %s not found", p) 183 ctx.Regs.ReturnAppend(false, ast.Bool) 184 return nil 185 } 186 default: 187 return runtime.NewRunError(ctx, fmt.Sprintf("param value_split_pattern expect StringLiteral, got %s", 188 funcExpr.Param[2].NodeType), funcExpr.NamePos) 189 } 190 } 191 192 var trimKey, trimValue string 193 if funcExpr.Param[3] != nil { 194 switch funcExpr.Param[3].NodeType { //nolint:exhaustive 195 case ast.TypeStringLiteral: 196 trimKey = funcExpr.Param[3].StringLiteral().Val 197 default: 198 return runtime.NewRunError(ctx, fmt.Sprintf("param trim_key expect StringLiteral, got %s", 199 funcExpr.Param[3].NodeType), funcExpr.NamePos) 200 } 201 } 202 203 if funcExpr.Param[4] != nil { 204 switch funcExpr.Param[4].NodeType { //nolint:exhaustive 205 case ast.TypeStringLiteral: 206 trimValue = funcExpr.Param[4].StringLiteral().Val 207 default: 208 return runtime.NewRunError(ctx, fmt.Sprintf("param trim_value expect StringLiteral, got %s", 209 funcExpr.Param[4].NodeType), funcExpr.NamePos) 210 } 211 } 212 213 var includeKeys []string 214 if funcExpr.Param[5] != nil { 215 switch funcExpr.Param[5].NodeType { //nolint:exhaustive 216 case ast.TypeListLiteral, ast.TypeIdentifier: 217 v, dt, err := runtime.RunStmt(ctx, funcExpr.Param[5]) 218 if err != nil { 219 return err 220 } 221 if dt != ast.List { 222 break 223 } 224 switch v := v.(type) { 225 case []any: 226 for _, k := range v { 227 if k, ok := k.(string); ok { 228 includeKeys = append(includeKeys, k) 229 } 230 } 231 default: 232 } 233 234 default: 235 return runtime.NewRunError(ctx, fmt.Sprintf("param include_keys expect ListInitExpr or Identifier, got %s", 236 funcExpr.Param[5].NodeType), funcExpr.NamePos) 237 } 238 } 239 240 if len(includeKeys) == 0 { 241 ctx.Regs.ReturnAppend(false, ast.Bool) 242 return nil 243 } 244 245 var prefix string 246 if funcExpr.Param[6] != nil { 247 switch funcExpr.Param[6].NodeType { //nolint:exhaustive 248 case ast.TypeStringLiteral: 249 prefix = funcExpr.Param[6].StringLiteral().Val 250 default: 251 return runtime.NewRunError(ctx, fmt.Sprintf("param prefix expect StringLiteral, got %s", 252 funcExpr.Param[6].NodeType), funcExpr.NamePos) 253 } 254 } 255 256 result := kvSplit(val, includeKeys, fieldSplit, valueSplit, trimKey, trimValue, prefix) 257 if len(result) == 0 { 258 ctx.Regs.ReturnAppend(false, ast.Bool) 259 return nil 260 } 261 262 for k, v := range result { 263 _ = addKey2PtWithVal(ctx.InData(), k, v, ast.String, ptinput.KindPtDefault) 264 } 265 266 ctx.Regs.ReturnAppend(true, ast.Bool) 267 return nil 268 } 269 270 func kvSplit(str string, includeKeys []string, fieldSplit, valueSplit *regexp.Regexp, 271 trimKey, trimValue, prefix string, 272 ) map[string]string { 273 if str == "" { 274 return nil 275 } 276 277 if fieldSplit == nil { 278 fieldSplit = _defaultFieldSplitPattern 279 } 280 281 if valueSplit == nil { 282 valueSplit = _defaultValueSplitPattern 283 } 284 285 ks := map[string]struct{}{} 286 287 for _, v := range includeKeys { 288 ks[v] = struct{}{} 289 } 290 291 result := map[string]string{} 292 fields := fieldSplit.Split(str, -1) 293 for _, field := range fields { 294 keyValue := valueSplit.Split(field, 2) 295 296 if len(keyValue) == 2 { 297 // trim key 298 if tk := strings.Trim(keyValue[0], trimKey); tk != "" { 299 keyValue[0] = tk 300 } else { 301 continue 302 } 303 304 // !include ? continue : ; 305 if len(ks) > 0 { 306 if _, ok := ks[keyValue[0]]; !ok { 307 continue 308 } 309 } 310 311 // trim value 312 if trimValue != "" { 313 keyValue[1] = strings.Trim(keyValue[1], trimValue) 314 } 315 316 // prefix + key 317 if prefix != "" { 318 keyValue[0] = prefix + keyValue[0] 319 } 320 321 // append to result 322 result[keyValue[0]] = keyValue[1] 323 } 324 } 325 return result 326 }