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  }