github.com/cobalt77/jfrog-client-go@v0.14.5/artifactory/services/utils/repopathfile.go (about) 1 package utils 2 3 import ( 4 "regexp" 5 "strings" 6 7 "github.com/cobalt77/jfrog-client-go/utils" 8 ) 9 10 // We need to translate the provided download pattern to an AQL query. 11 // In Artifactory, for each artifact the name and path of the artifact are saved separately. 12 // We therefore need to build an AQL query that covers all possible repositories, paths and names the provided 13 // pattern can include. 14 // For example, the pattern repo/a/* can include the two following file: 15 // repo/a/file1.tgz and also repo/a/b/file2.tgz 16 // To achieve that, this function parses the pattern by splitting it by its * characters. 17 // The end result is a list of RepoPathFile structs. 18 // Each struct represent a possible repository, path and file name triple to be included in AQL query with an "or" relationship. 19 type RepoPathFile struct { 20 repo string 21 path string 22 file string 23 } 24 25 var asteriskRegexp = regexp.MustCompile(`\*`) 26 27 func createRepoPathFileTriples(pattern string, recursive bool) []RepoPathFile { 28 firstSlashIndex := strings.Index(pattern, "/") 29 asteriskIndices := asteriskRegexp.FindAllStringIndex(pattern, -1) 30 31 if asteriskIndices != nil && !utils.IsSlashPrecedeAsterisk(asteriskIndices[0][0], firstSlashIndex) { 32 var triples []RepoPathFile 33 var lastRepoAsteriskIndex int 34 for _, asteriskIndex := range asteriskIndices { 35 if utils.IsSlashPrecedeAsterisk(asteriskIndex[0], firstSlashIndex) { 36 break 37 } 38 repo := pattern[:asteriskIndex[0]+1] // '<repo>*' 39 newPattern := pattern[asteriskIndex[0]:] // '*<pattern>' 40 newPattern = strings.TrimPrefix(newPattern, "*/") 41 triples = append(triples, createPathFilePairs(repo, newPattern, recursive)...) 42 lastRepoAsteriskIndex = asteriskIndex[1] 43 } 44 45 // Handle characters between last asterisk before first slash: "a*handle-it/" 46 if lastRepoAsteriskIndex < firstSlashIndex { 47 repo := pattern[:firstSlashIndex] // '<repo>*' 48 newPattern := pattern[firstSlashIndex+1:] // '*<pattern>' 49 triples = append(triples, createPathFilePairs(repo, newPattern, recursive)...) 50 } else if firstSlashIndex < 0 && !strings.HasSuffix(pattern, "*") { 51 // Handle characters after last asterisk "a*handle-it" 52 triples = append(triples, createPathFilePairs(pattern, "*", recursive)...) 53 } 54 return triples 55 } 56 57 if firstSlashIndex < 0 { 58 return createPathFilePairs(pattern, "*", recursive) 59 } 60 repo := pattern[:firstSlashIndex] 61 pattern = pattern[firstSlashIndex+1:] 62 return createPathFilePairs(repo, pattern, recursive) 63 } 64 65 func createPathFilePairs(repo, pattern string, recursive bool) []RepoPathFile { 66 if pattern == "*" { 67 return []RepoPathFile{{repo, getDefaultPath(recursive), "*"}} 68 } 69 70 path, name, triples := handleNonRecursiveTriples(repo, pattern, recursive) 71 if !recursive { 72 return triples 73 } 74 if name == "*" { 75 return append(triples, RepoPathFile{repo, path + "/*", "*"}) 76 } 77 78 nameSplit := strings.Split(name, "*") 79 for i := 0; i < len(nameSplit)-1; i++ { 80 str := "" 81 for j, namePart := range nameSplit { 82 if j > 0 { 83 str += "*" 84 } 85 if j == i { 86 str += nameSplit[i] + "*/" 87 } else { 88 str += namePart 89 } 90 } 91 slashSplit := strings.Split(str, "/") 92 filePath := slashSplit[0] 93 fileName := slashSplit[1] 94 if fileName == "" { 95 fileName = "*" 96 } 97 if path != "" && !strings.HasSuffix(path, "/") { 98 path += "/" 99 } 100 triples = append(triples, RepoPathFile{repo, path + filePath, fileName}) 101 } 102 return triples 103 } 104 105 func handleNonRecursiveTriples(repo, pattern string, recursive bool) (string, string, []RepoPathFile) { 106 slashIndex := strings.LastIndex(pattern, "/") 107 if slashIndex < 0 { 108 // Optimization - If pattern starts with `*`, we'll have a triple with <repo>*<file>. 109 // In that case we'd prefer to avoid <repo>.<file>. 110 if recursive && strings.HasPrefix(pattern, "*") { 111 return "", pattern, []RepoPathFile{} 112 } 113 return "", pattern, []RepoPathFile{{repo, ".", pattern}} 114 } 115 path := pattern[:slashIndex] 116 name := pattern[slashIndex+1:] 117 return path, name, []RepoPathFile{{repo, path, name}} 118 } 119 120 func getDefaultPath(recursive bool) string { 121 if recursive { 122 return "*" 123 } 124 return "." 125 }