diff --git a/cmd/bom/cmd/generate.go b/cmd/bom/cmd/generate.go index a29e45d28d7..6bffb53d66c 100644 --- a/cmd/bom/cmd/generate.go +++ b/cmd/bom/cmd/generate.go @@ -71,6 +71,7 @@ type generateOptions struct { analyze bool noGitignore bool noGoModules bool + noGoTransient bool namespace string outputFile string images []string @@ -161,6 +162,12 @@ func init() { false, "don't perform go.mod analysis, sbom will not include data about go packages", ) + generateCmd.PersistentFlags().BoolVar( + &genOpts.noGoTransient, + "no-transient", + false, + "don't include transient go dependencies, only direct deps from go.mod", + ) generateCmd.PersistentFlags().StringVarP( &genOpts.namespace, @@ -203,6 +210,7 @@ func generateBOM(opts *generateOptions) error { Namespace: opts.namespace, AnalyseLayers: opts.analyze, ProcessGoModules: !opts.noGoModules, + OnlyDirectDeps: !opts.noGoTransient, } // We only replace the ignore patterns one or more where defined diff --git a/pkg/license/download.go b/pkg/license/download.go index 26ad2614f54..64efc9727bb 100644 --- a/pkg/license/download.go +++ b/pkg/license/download.go @@ -67,19 +67,23 @@ type DownloaderOptions struct { func (do *DownloaderOptions) Validate() error { // If we are using a cache if do.EnableCache { - // Is we have a cache dir, check if it exists - if do.CacheDir != "" { - if !util.Exists(do.CacheDir) { - return errors.New("the specified cache directory does not exist: " + do.CacheDir) - } - } - // And no cache dir was specified + // and no cache dir was specified if do.CacheDir == "" { + // use a temporary dir dir, err := os.MkdirTemp(os.TempDir(), "license-cache-") + do.CacheDir = dir if err != nil { return errors.Wrap(err, "creating temporary directory") } - do.CacheDir = dir + } else if !util.Exists(do.CacheDir) { + if err := os.MkdirAll(do.CacheDir, os.FileMode(0o755)); err != nil { + return errors.Wrap(err, "creating license downloader cache") + } + } + + // Is we have a cache dir, check if it exists + if !util.Exists(do.CacheDir) { + return errors.New("the specified cache directory does not exist: " + do.CacheDir) } } return nil diff --git a/pkg/license/implementation.go b/pkg/license/implementation.go index cb5c8ac3532..87a214ed0d9 100644 --- a/pkg/license/implementation.go +++ b/pkg/license/implementation.go @@ -45,7 +45,7 @@ func (d *ReaderDefaultImpl) ClassifyFile(path string) (licenseTag string, moreTa // Get the classsification matches, err := d.Classifier().MatchFrom(file) if len(matches) == 0 { - logrus.Warn("File does not match a known license: " + path) + logrus.Debugf("File does not match a known license: %s", path) } var highestConf float64 moreTags = []string{} @@ -81,10 +81,12 @@ func (d *ReaderDefaultImpl) ClassifyLicenseFiles(paths []string) ( // Apend to the return results licenseList = append(licenseList, ClassifyResult{f, license}) } - logrus.Infof( - "License classifier recognized %d/%d (%d%%) os the files", - len(licenseList), len(paths), (len(licenseList)/len(paths))*100, - ) + if len(paths) > 0 { + logrus.Infof( + "License classifier recognized %d/%d (%d%%) os the files", + len(licenseList), len(paths), (len(licenseList)/len(paths))*100, + ) + } return licenseList, unrecognizedPaths, nil } @@ -102,7 +104,7 @@ func (d *ReaderDefaultImpl) LicenseFromFile(path string) (license *License, err } if label == "" { - logrus.Info("File does not contain a known license: " + path) + logrus.Debugf("File does not contain a known license: %s", path) return nil, nil } @@ -170,7 +172,7 @@ func (d *ReaderDefaultImpl) Initialize(opts *ReaderOptions) error { logrus.Infof("Writing license data to %s", opts.CachePath()) // Write the licenses to disk as th classifier will need them - if err := catalog.WriteLicensesAsText(opts.LicensesPath()); err != nil { + if err := catalog.WriteLicensesAsText(opts.CachePath()); err != nil { return errors.Wrap(err, "writing license data to disk") } diff --git a/pkg/spdx/builder.go b/pkg/spdx/builder.go index f397d84b20e..2ebdf1d78c1 100644 --- a/pkg/spdx/builder.go +++ b/pkg/spdx/builder.go @@ -64,8 +64,10 @@ type DocGenerateOptions struct { AnalyseLayers bool // A flag that controls if deep layer analysis should be performed NoGitignore bool // Do not read exclusions from gitignore file ProcessGoModules bool // Analyze go.mod to include data about packages + OnlyDirectDeps bool // Only include direct dependencies from go.mod OutputFile string // Output location Namespace string // Namespace for the document (a unique URI) + ScanLicenses bool // Try to llok into files to determine their license Tarballs []string // A slice of tar paths Files []string // A slice of naked files to include in the bom Images []string // A slice of docker images diff --git a/pkg/spdx/gomod.go b/pkg/spdx/gomod.go index c47b0024829..fca19756101 100644 --- a/pkg/spdx/gomod.go +++ b/pkg/spdx/gomod.go @@ -17,30 +17,36 @@ limitations under the License. package spdx import ( + "encoding/json" "os" + "os/exec" "path/filepath" "regexp" + "strings" + "github.com/nozzle/throttler" "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/mod/modfile" "golang.org/x/tools/go/vcs" "k8s.io/release/pkg/license" + "sigs.k8s.io/release-utils/command" "sigs.k8s.io/release-utils/util" ) const ( downloadDir = spdxTempDir + "/gomod-scanner" GoModFileName = "go.mod" + GoSumFileName = "go.sum" + goModRevPtn = `v\d+\.\d+\.\d+-[0-9.]+-([a-f0-9]+)` // Match revisions in go modules ) +var goModRevRe *regexp.Regexp + // NewGoModule returns a new go module from the specified path func NewGoModuleFromPath(path string) (*GoModule, error) { mod := NewGoModule() mod.opts.Path = path - if err := mod.Open(); err != nil { - return nil, errors.Wrap(err, "opening new module path") - } return mod, nil } @@ -60,15 +66,23 @@ type GoModule struct { } type GoModuleOptions struct { - Path string // Path to the dir where go.mod resides + Path string // Path to the dir where go.mod resides + OnlyDirectDeps bool // Only include direct dependencies from go.mod + ScanLicenses bool // Scan licenses from everypossible place unless false +} + +// Options returns a pointer to the module options set +func (mod *GoModule) Options() *GoModuleOptions { + return mod.opts } // GoPackage basic pkg data we need type GoPackage struct { - ImportPath string - Revision string - LocalDir string - LicenseID string + ImportPath string + Revision string + LocalDir string + LocalInstall string + LicenseID string } // SPDXPackage builds a spdx package from the go package data @@ -78,10 +92,10 @@ func (pkg *GoPackage) ToSPDXPackage() (*Package, error) { return nil, errors.Wrap(err, "building repository from package import path") } spdxPackage := NewPackage() - spdxPackage.Name = pkg.ImportPath + spdxPackage.Name = pkg.ImportPath + "@" + strings.TrimSuffix(pkg.Revision, "+incompatible") spdxPackage.DownloadLocation = repo.Repo spdxPackage.LicenseConcluded = pkg.LicenseID - spdxPackage.Version = pkg.Revision + spdxPackage.Version = strings.TrimSuffix(pkg.Revision, "+incompatible") return spdxPackage, nil } @@ -103,7 +117,12 @@ func (mod *GoModule) Open() error { mod.GoMod = gomod // Build the package list - pkgs, err := mod.impl.BuildPackageList(mod.GoMod) + var pkgs []*GoPackage + if mod.Options().OnlyDirectDeps { + pkgs, err = mod.impl.BuildPackageList(mod.GoMod) + } else { + pkgs, err = mod.BuildFullPackageList(mod.GoMod) + } if err != nil { return errors.Wrap(err, "building module package list") } @@ -120,7 +139,7 @@ func (mod *GoModule) RemoveDownloads() error { func (mod *GoModule) DownloadPackages() error { logrus.Infof("Downloading source code for %d packages", len(mod.Packages)) if mod.Packages == nil { - return errors.New("Unable to download packages, package list is nil") + return errors.New("unable to download packages, package list is nil") } for _, pkg := range mod.Packages { @@ -134,7 +153,7 @@ func (mod *GoModule) DownloadPackages() error { // ScanLicenses scans the licenses and populats the fields func (mod *GoModule) ScanLicenses() error { if mod.Packages == nil { - return errors.New("Unable to scan lincese files, package list is nil") + return errors.New("unable to scan lincese files, package list is nil") } reader, err := mod.impl.LicenseReader() @@ -142,26 +161,116 @@ func (mod *GoModule) ScanLicenses() error { return errors.Wrap(err, "creating license scanner") } + // Create a new Throttler that will get `parallelDownloads` urls at a time + t := throttler.New(10, len(mod.Packages)) // Do a quick re-check for missing downloads // todo: paralelize this. urgently. for _, pkg := range mod.Packages { - // Call download with no force in case local data is missing - if err := mod.impl.DownloadPackage(pkg, mod.opts, false); err != nil { - // If we're unable to download the module we dont treat it as - // fatal, package will remain without license info but we go - // on scanning the rest of the packages. - logrus.Error(err) - continue - } + // Launch a goroutine to fetch the package contents + go func(curPkg *GoPackage) { + logrus.WithField( + "package", curPkg.ImportPath).Infof( + "Downloading package (%d total)", len(mod.Packages), + ) + defer t.Done(err) + if curPkg.LocalInstall == "" { + // Call download with no force in case local data is missing + if err2 := mod.impl.DownloadPackage(curPkg, mod.opts, false); err2 != nil { + // If we're unable to download the module we dont treat it as + // fatal, package will remain without license info but we go + // on scanning the rest of the packages. + logrus.WithField("package", curPkg.ImportPath).Error(err2) + return + } + } else { + logrus.WithField("package", curPkg.ImportPath).Infof( + "There is a local copy of %s@%s", curPkg.ImportPath, curPkg.Revision, + ) + } - if err := mod.impl.ScanPackageLicense(pkg, reader, mod.opts); err != nil { - return errors.Wrapf(err, "scanning package %s for licensing info", pkg.ImportPath) - } + if err = mod.impl.ScanPackageLicense(curPkg, reader, mod.opts); err != nil { + logrus.WithField("package", curPkg.ImportPath).Errorf( + "scanning package %s for licensing info", curPkg.ImportPath, + ) + } + }(pkg) + t.Throttle() + } + + if t.Err() != nil { + return t.Err() } return nil } +// BuildFullPackageList return the complete of packages imported into +// the module, instead of reading go.mod, this functions calls +// go list and works from there +func (mod *GoModule) BuildFullPackageList(g *modfile.File) (packageList []*GoPackage, err error) { + packageList = []*GoPackage{} + gobin, err := exec.LookPath("go") + if err != nil { + return nil, errors.New("unable to get full list of packages, go executbale not found ") + } + + if !util.Exists(filepath.Join(mod.opts.Path, GoSumFileName)) { + return nil, errors.New("unable to generate package list, go.sum file not found") + } + + gorun := command.NewWithWorkDir(mod.opts.Path, gobin, "list", "-deps", "-e", "-json", "./...") + output, err := gorun.RunSilentSuccessOutput() + if err != nil { + return nil, errors.Wrap(err, "while calling go to get full list of deps") + } + + type ModEntry struct { + DepOnly bool `json:"DepOnly,omitempty"` + Main bool `json:"Main,omitempty"` + Module struct { + Path string `json:"Path,omitempty"` // Path is theImportPath + Main bool `json:"Main,omitempty"` // true if its the main module (eg k/release) + Dir string `json:"Dir,omitempty"` // The source can be found here + GoMod string `json:"GoMod,omitempty"` // Or cached here + Version string `json:"Version,omitempty"` // PAckage version + Indirect bool `json:"Indirect,omitempty"` + } `json:"Module,omitempty"` + } + + dec := json.NewDecoder(strings.NewReader(output.Output())) + list := map[string]map[string]*ModEntry{} + for dec.More() { + m := &ModEntry{} + if err := dec.Decode(m); err != nil { + return nil, errors.Wrap(err, "decoding module list") + } + if m.Module.Path != "" { + if _, ok := list[m.Module.Path]; !ok { + list[m.Module.Path] = map[string]*ModEntry{} + } + list[m.Module.Path][m.Module.Version] = m + } + } + logrus.Info("Adding full list of dependencies:") + for _, versions := range list { + for _, fmod := range versions { + dep := &GoPackage{ + ImportPath: fmod.Module.Path, + Revision: fmod.Module.Version, + LocalDir: "", + LocalInstall: "", + } + if util.Exists(fmod.Module.Dir) { + dep.LocalInstall = fmod.Module.Dir + } + logrus.Infof(" > %s@%s", dep.ImportPath, dep.Revision) + packageList = append(packageList, dep) + } + } + logrus.Infof("Found %d modules from full dependency tree", len(packageList)) + return packageList, nil +} + type GoModDefaultImpl struct { licenseReader *license.Reader } @@ -177,7 +286,7 @@ func (di *GoModDefaultImpl) OpenModule(opts *GoModuleOptions) (*modfile.File, er return nil, errors.Wrap(err, "reading go.mod") } logrus.Infof( - "Parsed go.mod file for %s, found %d packages", + "Parsed go.mod file for %s, found %d direct dependencies", gomod.Module.Mod.Path, len(gomod.Require), ) @@ -224,8 +333,13 @@ func (di *GoModDefaultImpl) DownloadPackage(pkg *GoPackage, opts *GoModuleOption return errors.Wrap(err, "creating temporary dir") } // Create a clone of the module repo at the revision - rev := pkg.Revision - m := regexp.MustCompile(`v\d+\.\d+\.\d+-[0-9.]+-([a-f0-9]+)`).FindStringSubmatch(pkg.Revision) + rev := strings.TrimSuffix(pkg.Revision, "+incompatible") + + // Strip the revision from the whole string part + if goModRevRe == nil { + goModRevRe = regexp.MustCompile(goModRevPtn) + } + m := goModRevRe.FindStringSubmatch(pkg.Revision) if len(m) > 1 { rev = m[1] logrus.Infof("Using commit %s as revision for download", rev) @@ -243,7 +357,7 @@ func (di *GoModDefaultImpl) DownloadPackage(pkg *GoPackage, opts *GoModuleOption func (di *GoModDefaultImpl) RemoveDownloads(packageList []*GoPackage) error { for _, pkg := range packageList { if pkg.ImportPath != "" && util.Exists(pkg.LocalDir) { - if err := os.RemoveAll(pkg.ImportPath); err != nil { + if err := os.RemoveAll(pkg.LocalDir); err != nil { return errors.Wrap(err, "removing package data") } } @@ -275,7 +389,11 @@ func (di *GoModDefaultImpl) LicenseReader() (*license.Reader, error) { // ScanPackageLicense scans a package for licensing info func (di *GoModDefaultImpl) ScanPackageLicense( pkg *GoPackage, reader *license.Reader, opts *GoModuleOptions) error { - licenselist, _, err := reader.ReadLicenses(pkg.LocalDir) + dir := pkg.LocalDir + if dir == "" && pkg.LocalInstall != "" { + dir = pkg.LocalInstall + } + licenselist, _, err := reader.ReadLicenses(dir) if err != nil { return errors.Wrapf(err, "scanning package %s for licensing information", pkg.ImportPath) } diff --git a/pkg/spdx/implementation.go b/pkg/spdx/implementation.go index 0edcc58720b..90f9cdf493c 100644 --- a/pkg/spdx/implementation.go +++ b/pkg/spdx/implementation.go @@ -51,7 +51,7 @@ type spdxImplementation interface { GetDirectoryTree(string) ([]string, error) IgnorePatterns(string, []string, bool) ([]gitignore.Pattern, error) ApplyIgnorePatterns([]string, []gitignore.Pattern) []string - GetGoDependencies(string, bool) ([]*Package, error) + GetGoDependencies(string, *Options) ([]*Package, error) GetDirectoryLicense(*license.Reader, string, *Options) (*license.License, error) LicenseReader(*Options) (*license.Reader, error) } @@ -274,22 +274,33 @@ func (di *spdxDefaultImplementation) ApplyIgnorePatterns( return filteredList } -// GetGoDependencies -func (di *spdxDefaultImplementation) GetGoDependencies(path string, scanLicenses bool) ([]*Package, error) { +// GetGoDependencies opens a Go module and directory and returns the +// dependencies as SPDX packages. +func (di *spdxDefaultImplementation) GetGoDependencies( + path string, opts *Options, +) (spdxPackages []*Package, err error) { // Open the directory as a go module: mod, err := NewGoModuleFromPath(path) if err != nil { return nil, errors.Wrap(err, "creating a mod from the specified path") } - defer mod.GoMod.Cleanup() + mod.Options().OnlyDirectDeps = opts.OnlyDirectDeps + mod.Options().ScanLicenses = opts.ScanLicenses - if scanLicenses { + // Open the module + if err := mod.Open(); err != nil { + return nil, errors.Wrap(err, "opening new module path") + } + + defer func() { err = mod.RemoveDownloads() }() + + if opts.ScanLicenses { if err := mod.ScanLicenses(); err != nil { return nil, errors.Wrap(err, "scanning go module licenses") } } - spdxPackages := []*Package{} + spdxPackages = []*Package{} for _, goPkg := range mod.Packages { spdxPkg, err := goPkg.ToSPDXPackage() if err != nil { @@ -298,7 +309,7 @@ func (di *spdxDefaultImplementation) GetGoDependencies(path string, scanLicenses spdxPackages = append(spdxPackages, spdxPkg) } - return spdxPackages, nil + return spdxPackages, err } func (di *spdxDefaultImplementation) LicenseReader(spdxOpts *Options) (*license.Reader, error) { diff --git a/pkg/spdx/package.go b/pkg/spdx/package.go index 61be87ce759..db076a43763 100644 --- a/pkg/spdx/package.go +++ b/pkg/spdx/package.go @@ -221,8 +221,13 @@ func (p *Package) Render() (docFragment string, err error) { return "", errors.Wrap(err, "parsing package template") } - // If files were analyzed, calculate the verification - filesTagList := map[string]*struct{}{} + // If files were analyzed, calculate the verification which + // is a sha1sum from all sha1 checksumf from included friles. + // + // Since we are already doing it, we use the same loop to + // collect license tags to express them in the LicenseInfoFromFiles + // entry of the SPDX package: + filesTagList := []string{} if p.FilesAnalyzed { if len(p.Files) == 0 { return docFragment, errors.New("unable to get package verification code, package has no files") @@ -239,7 +244,16 @@ func (p *Package) Render() (docFragment string, err error) { // Collect the license tags if f.LicenseInfoInFile != "" { - filesTagList[f.LicenseInfoInFile] = nil + collected := false + for _, tag := range filesTagList { + if tag == f.LicenseInfoInFile { + collected = true + break + } + } + if !collected { + filesTagList = append(filesTagList, f.LicenseInfoInFile) + } } } sort.Strings(shaList) @@ -249,14 +263,17 @@ func (p *Package) Render() (docFragment string, err error) { } p.VerificationCode = fmt.Sprintf("%x", h.Sum(nil)) - for tag := range filesTagList { - if tag != "NONE" && tag != "NOASSERTION" { + for _, tag := range filesTagList { + if tag != NONE && tag != NOASSERTION { p.LicenseInfoFromFiles = append(p.LicenseInfoFromFiles, tag) } } + // If no license tags where collected from files, then + // the BOM has to express "NONE" in the LicenseInfoFromFiles + // section to be compliant: if len(filesTagList) == 0 { - p.LicenseInfoFromFiles = append(p.LicenseInfoFromFiles, "NONE") + p.LicenseInfoFromFiles = append(p.LicenseInfoFromFiles, NONE) } } diff --git a/pkg/spdx/spdx.go b/pkg/spdx/spdx.go index 08d730bc434..d8c8c7970d8 100644 --- a/pkg/spdx/spdx.go +++ b/pkg/spdx/spdx.go @@ -36,6 +36,10 @@ const ( spdxLicenseDlCache = spdxTempDir + "/downloadCache" gitIgnoreFile = ".gitignore" validNameCharsRe = `[^a-zA-Z0-9-]+` + + // Consts of some SPDX expressions + NONE = "NONE" + NOASSERTION = "NOASSERTION" ) type SPDX struct { @@ -58,6 +62,8 @@ type Options struct { AnalyzeLayers bool NoGitignore bool // Do not read exclusions from gitignore file ProcessGoModules bool // If true, spdx will check if dirs are go modules and analize the packages + OnlyDirectDeps bool // Only include direct dependencies from go.mod + ScanLicenses bool // Scan licenses from everypossible place unless false LicenseCacheDir string // Directory to cache SPDX license information IgnorePatterns []string // Patterns to ignore when scanning file } @@ -71,6 +77,7 @@ var defaultSPDXOptions = Options{ AnalyzeLayers: true, ProcessGoModules: true, IgnorePatterns: []string{}, + ScanLicenses: true, } type ArchiveManifest struct { @@ -85,7 +92,7 @@ type TarballOptions struct { } // PackageFromDirectory indexes all files in a directory and builds a -// SPDX package describing its contents +// SPDX package describing its contents func (spdx *SPDX) PackageFromDirectory(dirPath string) (pkg *Package, err error) { fileList, err := spdx.impl.GetDirectoryTree(dirPath) if err != nil { @@ -101,7 +108,7 @@ func (spdx *SPDX) PackageFromDirectory(dirPath string) (pkg *Package, err error) return nil, errors.Wrap(err, "scanning directory for licenses") } if lic == nil { - logrus.Warn(err, "Licenseclassifier could not find a license for directory") + logrus.Warnf("Licenseclassifier could not find a license for directory: %v", err) } else { licenseTag = lic.LicenseID } @@ -141,7 +148,7 @@ func (spdx *SPDX) PackageFromDirectory(dirPath string) (pkg *Package, err error) if lic != nil { f.LicenseInfoInFile = lic.LicenseID } else { - f.LicenseInfoInFile = "NONE" + f.LicenseInfoInFile = NONE } f.LicenseConcluded = licenseTag if err := f.ReadSourceFile(filepath.Join(dirPath, path)); err != nil { @@ -154,7 +161,7 @@ func (spdx *SPDX) PackageFromDirectory(dirPath string) (pkg *Package, err error) if util.Exists(filepath.Join(dirPath, GoModFileName)) && spdx.Options().ProcessGoModules { logrus.Info("Directory contains a go module. Scanning go packages") - deps, err := spdx.impl.GetGoDependencies(dirPath, true) + deps, err := spdx.impl.GetGoDependencies(dirPath, spdx.Options()) if err != nil { return nil, errors.Wrap(err, "scanning go packages") } diff --git a/pkg/spdx/spdxfakes/fake_spdx_implementation.go b/pkg/spdx/spdxfakes/fake_spdx_implementation.go index f94fb7bb944..51eedbf56d3 100644 --- a/pkg/spdx/spdxfakes/fake_spdx_implementation.go +++ b/pkg/spdx/spdxfakes/fake_spdx_implementation.go @@ -63,11 +63,11 @@ type FakeSpdxImplementation struct { result1 []string result2 error } - GetGoDependenciesStub func(string, bool) ([]*spdx.Package, error) + GetGoDependenciesStub func(string, *spdx.Options) ([]*spdx.Package, error) getGoDependenciesMutex sync.RWMutex getGoDependenciesArgsForCall []struct { arg1 string - arg2 bool + arg2 *spdx.Options } getGoDependenciesReturns struct { result1 []*spdx.Package @@ -414,12 +414,12 @@ func (fake *FakeSpdxImplementation) GetDirectoryTreeReturnsOnCall(i int, result1 }{result1, result2} } -func (fake *FakeSpdxImplementation) GetGoDependencies(arg1 string, arg2 bool) ([]*spdx.Package, error) { +func (fake *FakeSpdxImplementation) GetGoDependencies(arg1 string, arg2 *spdx.Options) ([]*spdx.Package, error) { fake.getGoDependenciesMutex.Lock() ret, specificReturn := fake.getGoDependenciesReturnsOnCall[len(fake.getGoDependenciesArgsForCall)] fake.getGoDependenciesArgsForCall = append(fake.getGoDependenciesArgsForCall, struct { arg1 string - arg2 bool + arg2 *spdx.Options }{arg1, arg2}) stub := fake.GetGoDependenciesStub fakeReturns := fake.getGoDependenciesReturns @@ -440,13 +440,13 @@ func (fake *FakeSpdxImplementation) GetGoDependenciesCallCount() int { return len(fake.getGoDependenciesArgsForCall) } -func (fake *FakeSpdxImplementation) GetGoDependenciesCalls(stub func(string, bool) ([]*spdx.Package, error)) { +func (fake *FakeSpdxImplementation) GetGoDependenciesCalls(stub func(string, *spdx.Options) ([]*spdx.Package, error)) { fake.getGoDependenciesMutex.Lock() defer fake.getGoDependenciesMutex.Unlock() fake.GetGoDependenciesStub = stub } -func (fake *FakeSpdxImplementation) GetGoDependenciesArgsForCall(i int) (string, bool) { +func (fake *FakeSpdxImplementation) GetGoDependenciesArgsForCall(i int) (string, *spdx.Options) { fake.getGoDependenciesMutex.RLock() defer fake.getGoDependenciesMutex.RUnlock() argsForCall := fake.getGoDependenciesArgsForCall[i]