github.com/jfrog/jfrog-cli-go@v1.22.1-0.20200318093948-4826ef344ffd/artifactory/utils/pip/dependencies/dependencies.go (about)

     1  package dependencies
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"github.com/jfrog/jfrog-client-go/artifactory"
     7  	"github.com/jfrog/jfrog-client-go/artifactory/buildinfo"
     8  	serviceutils "github.com/jfrog/jfrog-client-go/artifactory/services/utils"
     9  	"github.com/jfrog/jfrog-client-go/utils/errorutils"
    10  	"github.com/jfrog/jfrog-client-go/utils/log"
    11  	"strings"
    12  )
    13  
    14  // Populate project's dependencies with checksums and file names.
    15  // If the dependency was downloaded in this pip-install execution, checksum will be fetched from Artifactory.
    16  // Otherwise, check if exists in cache.
    17  // Return dependency-names of all dependencies which its information could not be obtained.
    18  func AddDepsInfoAndReturnMissingDeps(dependenciesMap map[string]*buildinfo.Dependency, dependenciesCache *DependenciesCache, dependencyToFileMap map[string]string, servicesManager *artifactory.ArtifactoryServicesManager, repository string) ([]string, error) {
    19  	var missingDeps []string
    20  	// Iterate dependencies map to update info.
    21  	for depName := range dependenciesMap {
    22  		// Get dependency info.
    23  		depFileName, depChecksum, err := getDependencyInfo(depName, repository, dependenciesCache, dependencyToFileMap, servicesManager)
    24  		if err != nil {
    25  			return nil, err
    26  		}
    27  
    28  		// Check if info not found.
    29  		if depFileName == "" || depChecksum == nil {
    30  			// Dependency either wasn't downloaded in this run nor stored in cache.
    31  			missingDeps = append(missingDeps, depName)
    32  
    33  			// dependenciesMapT should contain only dependencies with checksums.
    34  			delete(dependenciesMap, depName)
    35  
    36  			continue
    37  		}
    38  		fileType := ""
    39  		// Update dependency info.
    40  		dependenciesMap[depName].Id = depFileName
    41  		if i := strings.LastIndex(depFileName, "."); i != -1 {
    42  			fileType = depFileName[i+1:]
    43  		}
    44  		dependenciesMap[depName].Type = fileType
    45  		dependenciesMap[depName].Checksum = depChecksum
    46  	}
    47  
    48  	return missingDeps, nil
    49  }
    50  
    51  // Get dependency information.
    52  // If dependency was downloaded in this pip-install execution, fetch info from Artifactory.
    53  // Otherwise, fetch info from cache.
    54  func getDependencyInfo(depName, repository string, dependenciesCache *DependenciesCache, dependencyToFileMap map[string]string, servicesManager *artifactory.ArtifactoryServicesManager) (string, *buildinfo.Checksum, error) {
    55  	// Check if this dependency was updated during this pip-install execution, and we have its file-name.
    56  	// If updated - fetch checksum from Artifactory, regardless of what was previously stored in cache.
    57  	depFileName, ok := dependencyToFileMap[depName]
    58  	if ok && depFileName != "" {
    59  		checksum, err := getDependencyChecksumFromArtifactory(servicesManager, repository, depFileName)
    60  		return depFileName, checksum, err
    61  	}
    62  
    63  	// Check cache for dependency checksum.
    64  	if dependenciesCache != nil {
    65  		dep := dependenciesCache.GetDependency(depName)
    66  		if dep != nil {
    67  			// Checksum found in cache, return info
    68  			return dep.Id, dep.Checksum, nil
    69  		}
    70  	}
    71  
    72  	return "", nil, nil
    73  }
    74  
    75  // Fetch checksum for file from Artifactory.
    76  // If the file isn't found, or md5 or sha1 are missing, return nil.
    77  func getDependencyChecksumFromArtifactory(servicesManager *artifactory.ArtifactoryServicesManager, repository, dependencyFile string) (*buildinfo.Checksum, error) {
    78  	log.Debug(fmt.Sprintf("Fetching checksums for: %s", dependencyFile))
    79  	result, err := servicesManager.Aql(serviceutils.CreateAqlQueryForPypi(repository, dependencyFile))
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	parsedResult := new(aqlResult)
    85  	err = json.Unmarshal(result, parsedResult)
    86  	if err = errorutils.CheckError(err); err != nil {
    87  		return nil, err
    88  	}
    89  	if len(parsedResult.Results) == 0 {
    90  		log.Debug(fmt.Sprintf("File: %s could not be found in repository: %s", dependencyFile, repository))
    91  		return nil, nil
    92  	}
    93  
    94  	// Verify checksum exist.
    95  	sha1 := parsedResult.Results[0].Actual_sha1
    96  	md5 := parsedResult.Results[0].Actual_md5
    97  	if sha1 == "" || md5 == "" {
    98  		// Missing checksum.
    99  		log.Debug(fmt.Sprintf("Missing checksums for file: %s, sha1: '%s', md5: '%s'", dependencyFile, sha1, md5))
   100  		return nil, nil
   101  	}
   102  
   103  	// Update checksum.
   104  	checksum := &buildinfo.Checksum{Sha1: sha1, Md5: md5}
   105  	log.Debug(fmt.Sprintf("Found checksums for file: %s, sha1: '%s', md5: '%s'", dependencyFile, sha1, md5))
   106  
   107  	return checksum, nil
   108  }
   109  
   110  type aqlResult struct {
   111  	Results []*results `json:"results,omitempty"`
   112  }
   113  
   114  type results struct {
   115  	Actual_md5  string `json:"actual_md5,omitempty"`
   116  	Actual_sha1 string `json:"actual_sha1,omitempty"`
   117  }