Skip to content

Commit 7a514ce

Browse files
authored
fix: parseDependency parses all dependencies for all search dir now. (#2097)
if all dependecies were not loaded before parseTypes, every step for parseTypes/collectionConst may load new packages. it's will break uniqueness checking
1 parent 4bcc52f commit 7a514ce

File tree

3 files changed

+67
-20
lines changed

3 files changed

+67
-20
lines changed

golist.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,39 @@ import (
88
"go/build"
99
"os/exec"
1010
"path/filepath"
11+
"slices"
1112
)
1213

13-
func listPackages(ctx context.Context, dir string, env []string, args ...string) (pkgs []*build.Package, finalErr error) {
14+
func listPackages(ctx context.Context, dirs []string, env []string, args ...string) ([]*build.Package, error) {
15+
pkgMap := make(map[string]*build.Package)
16+
for i, dir := range dirs {
17+
pkgs, err := listOnePackages(ctx, dir, env, args...)
18+
if err != nil {
19+
if i == 0 {
20+
return nil, fmt.Errorf("pkg %s cannot find all dependencies, %s", dir, err)
21+
}
22+
continue // ignore search dir load error?
23+
}
24+
for _, pkg := range pkgs {
25+
pkgMap[pkg.Dir] = pkg
26+
}
27+
}
28+
pkgs := make([]*build.Package, 0, len(pkgMap))
29+
for _, pkg := range pkgMap {
30+
pkgs = append(pkgs, pkg)
31+
}
32+
slices.SortFunc(pkgs, func(a, b *build.Package) int {
33+
if a.Dir < b.Dir {
34+
return -1
35+
} else if a.Dir > b.Dir {
36+
return 1
37+
}
38+
return 0
39+
})
40+
return pkgs, nil
41+
}
42+
43+
func listOnePackages(ctx context.Context, dir string, env []string, args ...string) (pkgs []*build.Package, finalErr error) {
1444
cmd := exec.CommandContext(ctx, "go", append([]string{"list", "-json", "-e"}, args...)...)
1545
cmd.Env = env
1646
cmd.Dir = dir

golist_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func TestListPackages(t *testing.T) {
4242

4343
for _, c := range cases {
4444
t.Run(c.name, func(t *testing.T) {
45-
_, err := listPackages(context.TODO(), c.searchDir, nil, c.args...)
45+
_, err := listOnePackages(context.TODO(), c.searchDir, nil, c.args...)
4646
if c.except != nil {
4747
assert.NotNil(t, err)
4848
} else {

parser.go

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -419,10 +419,11 @@ func (parser *Parser) ParseAPIMultiSearchDir(searchDirs []string, mainAPIFile st
419419

420420
// Use 'go list' command instead of depth.Resolve()
421421
if parser.ParseDependency > 0 {
422+
allDir := append([]string{filepath.Dir(absMainAPIFilePath)}, searchDirs...)
422423
if parser.parseGoList {
423-
pkgs, err := listPackages(context.Background(), filepath.Dir(absMainAPIFilePath), nil, "-deps")
424+
pkgs, err := listPackages(context.Background(), allDir, nil, "-deps")
424425
if err != nil {
425-
return fmt.Errorf("pkg %s cannot find all dependencies, %s", filepath.Dir(absMainAPIFilePath), err)
426+
return err
426427
}
427428

428429
length := len(pkgs)
@@ -433,23 +434,35 @@ func (parser *Parser) ParseAPIMultiSearchDir(searchDirs []string, mainAPIFile st
433434
}
434435
}
435436
} else {
436-
var t depth.Tree
437-
t.ResolveInternal = true
438-
t.MaxDepth = parseDepth
439-
440-
pkgName, err := getPkgName(filepath.Dir(absMainAPIFilePath))
441-
if err != nil {
442-
return err
437+
dirImported := make(map[string]struct{}) // for deduplication
438+
for _, dir := range allDir { // ignore search dir (have been parsed)
439+
absDir, err := filepath.Abs(dir)
440+
if err == nil {
441+
dirImported[absDir] = struct{}{}
442+
}
443443
}
444+
for index, dir := range allDir {
445+
var t depth.Tree
446+
t.ResolveInternal = true
447+
t.MaxDepth = parseDepth
444448

445-
err = t.Resolve(pkgName)
446-
if err != nil {
447-
return fmt.Errorf("pkg %s cannot find all dependencies, %s", pkgName, err)
448-
}
449-
for i := 0; i < len(t.Root.Deps); i++ {
450-
err := parser.getAllGoFileInfoFromDeps(&t.Root.Deps[i], parser.ParseDependency)
449+
pkgName, err := getPkgName(dir)
451450
if err != nil {
452-
return err
451+
if index == 0 { // ignore error when load search dir
452+
return err
453+
}
454+
continue
455+
}
456+
457+
err = t.Resolve(pkgName)
458+
if err != nil {
459+
return fmt.Errorf("pkg %s cannot find all dependencies, %s", pkgName, err)
460+
}
461+
for i := 0; i < len(t.Root.Deps); i++ {
462+
err := parser.getAllGoFileInfoFromDeps(&t.Root.Deps[i], parser.ParseDependency, dirImported)
463+
if err != nil {
464+
return err
465+
}
453466
}
454467
}
455468
}
@@ -1867,7 +1880,7 @@ func (parser *Parser) getAllGoFileInfo(packageDir, searchDir string) error {
18671880
})
18681881
}
18691882

1870-
func (parser *Parser) getAllGoFileInfoFromDeps(pkg *depth.Pkg, parseFlag ParseFlag) error {
1883+
func (parser *Parser) getAllGoFileInfoFromDeps(pkg *depth.Pkg, parseFlag ParseFlag, dirImported map[string]struct{}) error {
18711884
ignoreInternal := pkg.Internal && !parser.ParseInternal
18721885
if ignoreInternal || !pkg.Resolved { // ignored internal and not resolved dependencies
18731886
return nil
@@ -1883,6 +1896,10 @@ func (parser *Parser) getAllGoFileInfoFromDeps(pkg *depth.Pkg, parseFlag ParseFl
18831896
}
18841897

18851898
srcDir := pkg.Raw.Dir
1899+
if _, ok := dirImported[srcDir]; ok {
1900+
return nil
1901+
}
1902+
dirImported[srcDir] = struct{}{}
18861903

18871904
files, err := os.ReadDir(srcDir) // only parsing files in the dir(don't contain sub dir files)
18881905
if err != nil {
@@ -1901,7 +1918,7 @@ func (parser *Parser) getAllGoFileInfoFromDeps(pkg *depth.Pkg, parseFlag ParseFl
19011918
}
19021919

19031920
for i := 0; i < len(pkg.Deps); i++ {
1904-
if err := parser.getAllGoFileInfoFromDeps(&pkg.Deps[i], parseFlag); err != nil {
1921+
if err := parser.getAllGoFileInfoFromDeps(&pkg.Deps[i], parseFlag, dirImported); err != nil {
19051922
return err
19061923
}
19071924
}

0 commit comments

Comments
 (0)