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

     1  package cargo
     2  
     3  import (
     4  	"path/filepath"
     5  	"strings"
     6  
     7  	"github.com/apex/log"
     8  
     9  	"github.com/fossas/fossa-cli/errors"
    10  	"github.com/fossas/fossa-cli/files"
    11  	"github.com/fossas/fossa-cli/graph"
    12  	"github.com/fossas/fossa-cli/pkg"
    13  )
    14  
    15  type manifest struct {
    16  	Workspace         workspace
    17  	Dependencies      map[string]interface{} `toml:"dependencies"`
    18  	BuildDependencies map[string]interface{} `toml:"build-dependencies"`
    19  	Package           Package
    20  }
    21  
    22  type workspace struct {
    23  	Members []string
    24  }
    25  
    26  type lockfile struct {
    27  	Packages []Package `toml:"package"`
    28  }
    29  
    30  // Package is a single imported repository within a dep project.
    31  type Package struct {
    32  	Name         string
    33  	Dependencies []string
    34  	Version      string
    35  	Source       string
    36  }
    37  
    38  // LockfileDependencies uses a lockfile and the associated manifest file to create a dependency
    39  // graph. This method approximates the direct dependencies by selecting all dependencies
    40  // in the manifest file as direct dependencies and determines the version from the lockfile.
    41  func LockfileDependencies(lockfilePath string, dir string) (graph.Deps, error) {
    42  	var lock lockfile
    43  	err := files.ReadTOML(&lock, filepath.Join(dir, lockfilePath))
    44  	if err != nil {
    45  		return graph.Deps{}, errors.Wrap(err, "No lockfile Cargo.lock found")
    46  	}
    47  
    48  	IDMap := make(map[string]pkg.ID)
    49  	for _, dep := range lock.Packages {
    50  		IDMap[dep.Name] = pkg.ID{
    51  			Type:     pkg.Rust,
    52  			Name:     dep.Name,
    53  			Revision: dep.Version,
    54  			Location: dep.Source,
    55  		}
    56  	}
    57  
    58  	transitiveDependenices := make(map[pkg.ID]pkg.Package)
    59  	for _, dep := range lock.Packages {
    60  		imports := []pkg.Import{}
    61  		for _, trans := range dep.Dependencies {
    62  			transDep := strings.Split(trans, " ")
    63  			imports = append(imports, pkg.Import{
    64  				Target:   transDep[0],
    65  				Resolved: IDMap[transDep[0]],
    66  			})
    67  		}
    68  
    69  		transitiveDependenices[IDMap[dep.Name]] = pkg.Package{
    70  			ID:      IDMap[dep.Name],
    71  			Imports: imports,
    72  		}
    73  	}
    74  
    75  	manifests := []manifest{}
    76  	var man manifest
    77  	err = files.ReadTOML(&man, filepath.Join(dir, "Cargo.toml"))
    78  	if err != nil {
    79  		log.Warnf("manifest file `Cargo.toml` was not found in directory: %s. direct dependencies may be incorrect. error: %+v", dir, err)
    80  	}
    81  	manifests = append(manifests, man)
    82  
    83  	for _, member := range man.Workspace.Members {
    84  		memberManifest := manifest{}
    85  		memberFile := filepath.Join(dir, member, "Cargo.toml")
    86  		err = files.ReadTOML(&memberManifest, memberFile)
    87  		if err != nil {
    88  			log.Warnf("member manifest file `%s` was not able to be read. direct dependencies may be incorrect. error: %+v", memberFile, err)
    89  			continue
    90  		}
    91  		manifests = append(manifests, memberManifest)
    92  	}
    93  
    94  	imports := []pkg.Import{}
    95  	for _, manifest := range manifests {
    96  		for dep := range manifest.Dependencies {
    97  			imports = append(imports, pkg.Import{
    98  				Target:   dep,
    99  				Resolved: IDMap[dep],
   100  			})
   101  		}
   102  		for dep := range manifest.BuildDependencies {
   103  			imports = append(imports, pkg.Import{
   104  				Target:   dep,
   105  				Resolved: IDMap[dep],
   106  			})
   107  		}
   108  	}
   109  
   110  	return graph.Deps{
   111  		Direct:     imports,
   112  		Transitive: transitiveDependenices,
   113  	}, nil
   114  }