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  }