github.com/osievert/jfrog-cli-core@v1.2.7/artifactory/utils/pip/dependencies/dependencies.go (about)

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