github.com/joey-fossa/fossa-cli@v0.7.34-0.20190708193710-569f1e8679f0/buildtools/dep/dep.go (about)

     1  // Package dep provides functions for working with the dep tool.
     2  package dep
     3  
     4  import (
     5  	"path"
     6  	"strings"
     7  
     8  	"github.com/pkg/errors"
     9  
    10  	"github.com/fossas/fossa-cli/buildtools"
    11  	"github.com/fossas/fossa-cli/files"
    12  	"github.com/fossas/fossa-cli/pkg"
    13  )
    14  
    15  // Resolver contains both the lockfile and manifest information. Resolver implements golang.Resolver.
    16  type Resolver struct {
    17  	manifest manifest
    18  	lockfile lockfile
    19  }
    20  
    21  // manifest contains the ignored packages in a dep toml file. manifest implements golang.Resolver.
    22  type manifest struct {
    23  	Ignored []string
    24  }
    25  
    26  // lockfile contains the Projects in a dep lockfile and a corresponding map for retrieving project data.
    27  type lockfile struct {
    28  	Projects   []Project
    29  	normalized map[string]pkg.Import
    30  }
    31  
    32  // Project is a single imported repository within a dep project.
    33  type Project struct {
    34  	Name     string
    35  	Packages []string
    36  	Revision string
    37  	Version  string
    38  }
    39  
    40  // Resolve returns the revision of an imported Go package contained within the
    41  // lockfile and checks to see if it should be ignored. If the package cannot be
    42  // ignored and is not found, buildtools.ErrNoRevisionForPackage is returned.
    43  func (r Resolver) Resolve(importpath string) (pkg.Import, error) {
    44  	if r.manifest.isIgnored(importpath) {
    45  		return pkg.Import{}, buildtools.ErrPackageIsIgnored
    46  	}
    47  
    48  	revision, ok := r.lockfile.normalized[importpath]
    49  	if !ok {
    50  		return pkg.Import{}, buildtools.ErrNoRevisionForPackage
    51  	}
    52  
    53  	return revision, nil
    54  }
    55  
    56  // isIgnored checks if a Go package can be ignored according to a dep manifest.
    57  func (m manifest) isIgnored(importpath string) bool {
    58  	for _, ignoredPackage := range m.Ignored {
    59  		if strings.HasSuffix(ignoredPackage, "*") {
    60  			ignoredPrefix := ignoredPackage[:len(ignoredPackage)-1]
    61  			if strings.HasPrefix(importpath, ignoredPrefix) {
    62  				return true
    63  			}
    64  		}
    65  
    66  		if ignoredPackage == importpath {
    67  			return true
    68  		}
    69  	}
    70  
    71  	return false
    72  }
    73  
    74  // New constructs a golang.Resolver given the path to the manifest and lockfile.
    75  func New(lockfilePath string, manifestPath string) (Resolver, error) {
    76  	var err error
    77  
    78  	resolver := Resolver{}
    79  	resolver.lockfile, err = readLockfile(lockfilePath)
    80  	if err != nil {
    81  		return Resolver{}, err
    82  	}
    83  
    84  	resolver.manifest, err = readManifest(manifestPath)
    85  	if err != nil {
    86  		return Resolver{}, err
    87  	}
    88  
    89  	return resolver, nil
    90  }
    91  
    92  // readLockfile returns a lockfile object using the provided filepath.
    93  func readLockfile(filepath string) (lockfile, error) {
    94  	var lock lockfile
    95  
    96  	err := files.ReadTOML(&lock, filepath)
    97  	if err != nil {
    98  		return lockfile{}, errors.Wrap(err, "No lockfile Gopkg.lock found")
    99  	}
   100  
   101  	normalized := make(map[string]pkg.Import)
   102  	for _, project := range lock.Projects {
   103  		for _, pk := range project.Packages {
   104  			revision := project.Version
   105  			if revision == "" {
   106  				revision = project.Revision
   107  			}
   108  			importpath := path.Join(project.Name, pk)
   109  			normalized[importpath] = pkg.Import{
   110  				Target: project.Version,
   111  				Resolved: pkg.ID{
   112  					Type:     pkg.Go,
   113  					Name:     importpath,
   114  					Revision: revision,
   115  					Location: "",
   116  				},
   117  			}
   118  		}
   119  	}
   120  
   121  	lock.normalized = normalized
   122  	return lock, nil
   123  }
   124  
   125  // readManifest returns a manifest using the provided filepath.
   126  func readManifest(filepath string) (manifest, error) {
   127  	var man manifest
   128  	err := files.ReadTOML(&man, filepath)
   129  	if err != nil {
   130  		return manifest{}, errors.Wrap(err, "No manifest Gopkg.toml found")
   131  	}
   132  
   133  	return man, nil
   134  }