github.com/jfrog/jfrog-cli-core/v2@v2.52.0/artifactory/utils/repositoryutils.go (about) 1 package utils 2 3 import ( 4 "github.com/jfrog/gofrog/datastructures" 5 "golang.org/x/exp/slices" 6 "path" 7 "strings" 8 9 "github.com/jfrog/jfrog-cli-core/v2/utils/config" 10 11 "github.com/jfrog/jfrog-client-go/artifactory" 12 "github.com/jfrog/jfrog-client-go/artifactory/services" 13 clientUtils "github.com/jfrog/jfrog-client-go/artifactory/services/utils" 14 "github.com/jfrog/jfrog-client-go/utils/errorutils" 15 ) 16 17 const buildInfoPackageType = "buildinfo" 18 19 type RepoType int 20 21 const ( 22 Local RepoType = iota 23 Remote 24 Virtual 25 Federated 26 Unknown 27 ) 28 29 var RepoTypes = []string{ 30 "local", 31 "remote", 32 "virtual", 33 "federated", 34 } 35 36 func (repoType RepoType) String() string { 37 return RepoTypes[repoType] 38 } 39 40 func RepoTypeFromString(repoTypeStr string) RepoType { 41 switch strings.ToLower(repoTypeStr) { 42 case Local.String(): 43 return Local 44 case Remote.String(): 45 return Remote 46 case Virtual.String(): 47 return Virtual 48 case Federated.String(): 49 return Federated 50 } 51 return Unknown 52 } 53 54 // System repositories in Artifactory to filter in filterRepositoryNames. 55 // This is important especially for transfer-config, to prevent rewriting these repositories, which causes unexpected exceptions. 56 var blacklistedRepositories = []string{ 57 "jfrog-usage-logs", "jfrog-billing-logs", "jfrog-logs", "artifactory-pipe-info", "auto-trashcan", "jfrog-support-bundle", "_intransit", "artifactory-edge-uploads", 58 } 59 60 // GetRepositories returns the names of local, remote, virtual or federated repositories filtered by their type. 61 // artDetails - Artifactory server details 62 // repoTypes - Repository types to filter. If empty - return all repository types. 63 func GetRepositories(artDetails *config.ServerDetails, repoTypes ...RepoType) ([]string, error) { 64 sm, err := CreateServiceManager(artDetails, 3, 0, false) 65 if err != nil { 66 return nil, err 67 } 68 repos := []string{} 69 for _, repoType := range repoTypes { 70 filteredRepos, err := GetFilteredRepositoriesByNameAndType(sm, nil, nil, repoType) 71 if err != nil { 72 return repos, err 73 } 74 repos = append(repos, filteredRepos...) 75 } 76 77 return repos, nil 78 } 79 80 // Since we can't search dependencies in a remote repository, we will turn the search to the repository's cache. 81 // Local/Virtual repository name will be returned as is. 82 func GetRepoNameForDependenciesSearch(repoName string, serviceManager artifactory.ArtifactoryServicesManager) (string, error) { 83 isRemote, err := IsRemoteRepo(repoName, serviceManager) 84 if err != nil { 85 return "", err 86 } 87 if isRemote { 88 repoName += "-cache" 89 } 90 return repoName, err 91 } 92 93 func IsRemoteRepo(repoName string, serviceManager artifactory.ArtifactoryServicesManager) (bool, error) { 94 repoDetails := &services.RepositoryDetails{} 95 err := serviceManager.GetRepository(repoName, &repoDetails) 96 if err != nil { 97 return false, errorutils.CheckErrorf("failed to get details for repository '" + repoName + "'. Error:\n" + err.Error()) 98 } 99 return repoDetails.GetRepoType() == "remote", nil 100 } 101 102 // GetFilteredRepositoriesByName returns the names of local, remote, virtual and federated repositories filtered by their names. 103 // includePatterns - patterns of repository names (can contain wildcards) to include in the results. A repository's name 104 // must match at least one of these patterns in order to be included in the results. If includePatterns' length is zero, 105 // all repositories are included. 106 // excludePatterns - patterns of repository names (can contain wildcards) to exclude from the results. A repository's name 107 // must NOT match any of these patterns in order to be included in the results. 108 func GetFilteredRepositoriesByName(servicesManager artifactory.ArtifactoryServicesManager, includePatterns, excludePatterns []string) ([]string, error) { 109 repoDetailsList, err := servicesManager.GetAllRepositories() 110 if err != nil { 111 return nil, err 112 } 113 114 return getFilteredRepositories(repoDetailsList, includePatterns, excludePatterns) 115 } 116 117 // GetFilteredRepositoriesByNameAndType returns the names of local, remote, virtual and federated repositories filtered by their names and type. 118 // includePatterns - patterns of repository names (can contain wildcards) to include in the results. A repository's name 119 // must match at least one of these patterns in order to be included in the results. If includePatterns' length is zero, 120 // all repositories are included. 121 // excludePatterns - patterns of repository names (can contain wildcards) to exclude from the results. A repository's name 122 // must NOT match any of these patterns in order to be included in the results. 123 // repoType - only repositories of this type will be returned. 124 func GetFilteredRepositoriesByNameAndType(servicesManager artifactory.ArtifactoryServicesManager, includePatterns, excludePatterns []string, repoType RepoType) ([]string, error) { 125 repoDetailsList, err := servicesManager.GetAllRepositoriesFiltered(services.RepositoriesFilterParams{RepoType: repoType.String()}) 126 if err != nil { 127 return nil, err 128 } 129 130 return getFilteredRepositories(repoDetailsList, includePatterns, excludePatterns) 131 } 132 133 func getFilteredRepositories(repoDetailsList *[]services.RepositoryDetails, includePatterns, excludePatterns []string) ([]string, error) { 134 var repoKeys []string 135 for _, repoDetails := range *repoDetailsList { 136 repoKeys = append(repoKeys, repoDetails.Key) 137 } 138 139 return filterRepositoryNames(&repoKeys, includePatterns, excludePatterns) 140 } 141 142 // GetFilteredBuildInfoRepositories returns the names of all build-info repositories filtered by their names. 143 // storageInfo - storage info response from Artifactory 144 // includePatterns - patterns of repository names (can contain wildcards) to include in the results. A repository's name 145 // must match at least one of these patterns in order to be included in the results. If includePatterns' length is zero, 146 // all repositories are included. 147 // excludePatterns - patterns of repository names (can contain wildcards) to exclude from the results. A repository's name 148 // must NOT match any of these patterns in order to be included in the results. 149 func GetFilteredBuildInfoRepositories(storageInfo *clientUtils.StorageInfo, includePatterns, excludePatterns []string) ([]string, error) { 150 var repoKeys []string 151 for _, repoSummary := range storageInfo.RepositoriesSummaryList { 152 if strings.ToLower(repoSummary.PackageType) == buildInfoPackageType { 153 repoKeys = append(repoKeys, repoSummary.RepoKey) 154 } 155 } 156 return filterRepositoryNames(&repoKeys, includePatterns, excludePatterns) 157 } 158 159 // Filter repositories by name and return a list of repository names 160 // repos - The repository keys to filter 161 // includePatterns - Repositories inclusion wildcard pattern 162 // excludePatterns - Repositories exclusion wildcard pattern 163 func filterRepositoryNames(repoKeys *[]string, includePatterns, excludePatterns []string) ([]string, error) { 164 includedRepos := datastructures.MakeSet[string]() 165 includeExcludeFilter := &IncludeExcludeFilter{ 166 IncludePatterns: includePatterns, 167 ExcludePatterns: excludePatterns, 168 } 169 for _, repoKey := range *repoKeys { 170 repoIncluded, err := includeExcludeFilter.ShouldIncludeRepository(repoKey) 171 if err != nil { 172 return nil, err 173 } 174 if repoIncluded { 175 includedRepos.Add(repoKey) 176 } 177 } 178 return includedRepos.ToSlice(), nil 179 } 180 181 type IncludeExcludeFilter struct { 182 IncludePatterns []string 183 ExcludePatterns []string 184 } 185 186 func (ief *IncludeExcludeFilter) ShouldIncludeRepository(repoKey string) (bool, error) { 187 if slices.Contains(blacklistedRepositories, repoKey) { 188 // This repository is blacklisted. 189 return false, nil 190 } 191 return ief.ShouldIncludeItem(repoKey) 192 } 193 194 func (ief *IncludeExcludeFilter) ShouldIncludeItem(item string) (bool, error) { 195 // If includePattens is empty, include all. 196 repoIncluded := len(ief.IncludePatterns) == 0 197 198 // Check if this item name matches any include pattern. 199 for _, includePattern := range ief.IncludePatterns { 200 matched, err := path.Match(includePattern, item) 201 if err != nil { 202 return false, err 203 } 204 if matched { 205 repoIncluded = true 206 break 207 } 208 } 209 210 if !repoIncluded { 211 return false, nil 212 } 213 214 // Check if this item name matches any exclude pattern. 215 for _, excludePattern := range ief.ExcludePatterns { 216 matched, err := path.Match(excludePattern, item) 217 if err != nil { 218 return false, err 219 } 220 if matched { 221 return false, nil 222 } 223 } 224 225 return true, nil 226 }