Skip to content

Commit

Permalink
Fix(recursive): use packages.Load support for recursive search instea…
Browse files Browse the repository at this point in the history
…d of manual

- Fix(Parsepackages): Ignore packages with no Go files
  • Loading branch information
sonalys committed Nov 8, 2024
1 parent 5a0ad1c commit 97ba6f2
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 115 deletions.
125 changes: 11 additions & 114 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"os"
"path/filepath"
"reflect"
"regexp"
"strings"
Expand Down Expand Up @@ -542,128 +541,26 @@ func shouldExcludeModule(ctx context.Context, root *pathlib.Path, goModPath *pat
return false, nil
}

func (c *Config) subPackages(
ctx context.Context,
pkgPath string,
pkgConfig *Config,
currentDepth int,
) ([]string, error) {
log := zerolog.Ctx(ctx)

func (c *Config) subPackages(pkgPath string) ([]string, error) {
pkgs, err := packages.Load(&packages.Config{
Mode: packages.NeedName | packages.NeedFiles,
}, pkgPath)
}, pkgPath+"/...")
if err != nil {
return nil, fmt.Errorf("failed to load packages: %w", err)
}
pkg := pkgs[0]

if currentDepth == 0 && len(pkg.GoFiles) == 0 {
log.Error().
Err(ErrNoGoFilesFoundInRoot).
Str("documentation", logging.DocsURL("/notes/#error-no-go-files-found-in-root-search-path")).
Msg("package contains no go files")
return nil, ErrNoGoFilesFoundInRoot
}
representativeFile := pathlib.NewPath(pkg.GoFiles[0])
searchRoot := representativeFile.Parent()
packageRootName := pathlib.NewPath(pkg.PkgPath)
packageRootPath := searchRoot
subPackages := []string{}

walker, err := pathlib.NewWalk(
searchRoot,
pathlib.WalkAlgorithm(pathlib.AlgorithmPreOrderDepthFirst),
pathlib.WalkFollowSymlinks(false),
pathlib.WalkVisitDirs(false),
pathlib.WalkVisitFiles(true),
)
if err != nil {
return nil, fmt.Errorf("failed to create filesystem walker: %w", err)
}

visitedDirs := map[string]any{}
subdirectoriesWithGoFiles := []*pathlib.Path{}

// We consider the searchRoot to already be visited because
// we know it's already in the configuration.
visitedDirs[searchRoot.String()] = nil

// Walk the filesystem path, starting at the root of the package we've
// been given. Note that this will always work because Go downloads
// the package when we call `packages.Load`
walkErr := walker.Walk(func(path *pathlib.Path, info os.FileInfo, err error) error {
pathLog := log.With().Stringer("path", path).Logger()
if err != nil {
return err
}
if path.Name() == "go.mod" {
pathLog.Debug().Msg("path contains go.mod file")
// Check if our current depth is 0. We do this to skip sub-modules, but not
// the root module.
shouldExclude, err := shouldExcludeModule(ctx, searchRoot, path)
if err != nil {
return err
}

if shouldExclude {
return pathlib.ErrWalkSkipSubtree
}
}

_, haveVisitedDir := visitedDirs[path.Parent().String()]
if !haveVisitedDir && strings.HasSuffix(path.Name(), ".go") {

if !c.IncludeAutoGenerated {
autoGenerated, err := isAutoGenerated(path)
if err != nil {
pathLog.Err(err).Msg("failed to determine if file is auto-generated")
return err
}
if autoGenerated {
pathLog.Debug().Msg("skipping file as auto-generated")
return nil
}
}

pathLog.Debug().Msg("subdirectory has a .go file")
goModPath := path.Parent().Join("go.mod")
goModExists, err := goModPath.Exists()
if err != nil {
pathLog.Err(err).Msg("failed to determine if go.mod exists")
return err
}
if goModExists {
shouldExclude, err := shouldExcludeModule(ctx, searchRoot, goModPath)
if err != nil {
return err
}
if shouldExclude {
return pathlib.ErrWalkSkipSubtree
}
convertPkgPath := func(pkgs []*packages.Package) []string {
paths := make([]string, 0, len(pkgs))
for _, pkg := range pkgs {
if len(pkg.GoFiles) == 0 {
continue
}
subdirectoriesWithGoFiles = append(subdirectoriesWithGoFiles, path.Parent())
visitedDirs[path.Parent().String()] = nil
}
return nil
})
if walkErr != nil {
return nil, fmt.Errorf("error occurred during filesystem walk: %w", walkErr)
}

// Parse the subdirectories we found into their respective fully qualified
// package paths
for _, d := range subdirectoriesWithGoFiles {
relativeFilesystemPath, err := d.RelativeTo(packageRootPath)
if err != nil {
log.Err(err).Stringer("root", packageRootPath).Stringer("subRoot", d).Msg("failed to make subroot relative to root")
return nil, fmt.Errorf("failed to make subroot relative to root: %w", err)
paths = append(paths, pkg.PkgPath)
}
absolutePackageName := packageRootName.Join(relativeFilesystemPath.Parts()...)
subPackages = append(subPackages, filepath.ToSlash(absolutePackageName.String()))
return paths
}

return subPackages, nil
return convertPkgPath(pkgs), nil
}

// discoverRecursivePackages parses the provided config for packages marked as
Expand Down Expand Up @@ -697,7 +594,7 @@ func (c *Config) discoverRecursivePackages(ctx context.Context) error {
pkgLog := log.With().Str("package-path", pkgPath).Logger()
pkgCtx := pkgLog.WithContext(ctx)
pkgLog.Debug().Msg("discovering sub-packages")
subPkgs, err := c.subPackages(pkgCtx, pkgPath, conf, 0)
subPkgs, err := c.subPackages(pkgPath)
if err != nil {
return fmt.Errorf("failed to get subpackages: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1012,7 +1012,7 @@ packages:
config:
recursive: True
all: True`,
wantErr: ErrNoGoFilesFoundInRoot,
wantErr: nil,
},
{
name: "test with no subpackages present",
Expand Down
3 changes: 3 additions & 0 deletions pkg/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ func (p *Parser) ParsePackages(ctx context.Context, packageNames []string) error
return err
}
for _, pkg := range packages {
if len(pkg.GoFiles) == 0 {
continue
}
for _, err := range pkg.Errors {
log.Err(err).Msg("encountered error when loading package")
}
Expand Down

0 comments on commit 97ba6f2

Please sign in to comment.