istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tools/bug-report/pkg/util/path/path.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package path 16 17 import ( 18 "path/filepath" 19 "strings" 20 ) 21 22 var ( 23 // pathSeparator is the separator between path elements. 24 pathSeparator = "/" 25 // escapedPathSeparator is what to use when the path shouldn't separate 26 escapedPathSeparator = "\\" + pathSeparator 27 ) 28 29 // Path is a path in slice form. 30 type Path []string 31 32 // FromString converts a string path of form a.b.c to a string slice representation. 33 func FromString(path string) Path { 34 path = filepath.Clean(path) 35 path = strings.TrimPrefix(path, pathSeparator) 36 path = strings.TrimSuffix(path, pathSeparator) 37 pv := splitEscaped(path, []rune(pathSeparator)[0]) 38 var r []string 39 for _, str := range pv { 40 if str != "" { 41 str = strings.ReplaceAll(str, escapedPathSeparator, pathSeparator) 42 // Is str of the form node[expr], convert to "node", "[expr]"? 43 nBracket := strings.IndexRune(str, '[') 44 if nBracket > 0 { 45 r = append(r, str[:nBracket], str[nBracket:]) 46 } else { 47 // str is "[expr]" or "node" 48 r = append(r, str) 49 } 50 } 51 } 52 return r 53 } 54 55 // String converts a string slice path representation of form ["a", "b", "c"] to a string representation like "a.b.c". 56 func (p Path) String() string { 57 return strings.Join(p, pathSeparator) 58 } 59 60 // splitEscaped splits a string using the rune r as a separator. It does not split on r if it's prefixed by \. 61 func splitEscaped(s string, r rune) []string { 62 var prev rune 63 if len(s) == 0 { 64 return []string{} 65 } 66 prevIdx := 0 67 var out []string 68 for i, c := range s { 69 if c == r && (i == 0 || (i > 0 && prev != '\\')) { 70 out = append(out, s[prevIdx:i]) 71 prevIdx = i + 1 72 } 73 prev = c 74 } 75 out = append(out, s[prevIdx:]) 76 return out 77 }