Skip to content

Commit df16664

Browse files
authored
refactor(convert): preload dependency dirs via go list (goplus#650)
* refactor(convert): preload dependency dirs via go list cache * fix(convert): seed go-list cache from configured deps * refactor(convert): remove xgomod from dep loader * refactor(convert): remove BuildMod and strict go list deps preload * refactor(convert): simplify dep list preload and cover patterns * fix(convert): include go list output in preload errors
1 parent beba8c5 commit df16664

File tree

6 files changed

+118
-37
lines changed

6 files changed

+118
-37
lines changed

cl/internal/convert/deps.go

Lines changed: 70 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,39 @@
11
package convert
22

33
import (
4+
"errors"
45
"fmt"
56
"go/token"
67
"go/types"
78
"log"
9+
"os/exec"
810
"path"
911
"path/filepath"
1012
"strings"
1113

1214
"github.com/goplus/gogen"
1315
llcppg "github.com/goplus/llcppg/config"
14-
"github.com/goplus/mod/xgomod"
1516
)
1617

17-
type Module = xgomod.Module
18-
1918
type PkgDepLoader struct {
20-
module *xgomod.Module
19+
root string
2120
pkg *gogen.Package
2221
pkgCache map[string]*PkgInfo // pkgPath -> *PkgInfo
22+
pkgs map[string]string // pkgPath -> pkgDir
2323
regCache map[string]struct{} // pkgPath
2424
}
2525

26-
func NewPkgDepLoader(mod *xgomod.Module, pkg *gogen.Package) *PkgDepLoader {
27-
return &PkgDepLoader{
28-
module: mod,
26+
func NewPkgDepLoader(root string, pkg *gogen.Package, deps []string) (*PkgDepLoader, error) {
27+
ret := &PkgDepLoader{
28+
root: root,
2929
pkg: pkg,
3030
pkgCache: make(map[string]*PkgInfo),
3131
regCache: make(map[string]struct{}),
3232
}
33+
if err := ret.loadPkgDirs(deps); err != nil {
34+
return nil, err
35+
}
36+
return ret, nil
3337
}
3438

3539
// for current package & dependent packages
@@ -83,12 +87,11 @@ func (pm *PkgDepLoader) Import(pkgPath string) (*PkgInfo, error) {
8387
return pkg, nil
8488
}
8589

86-
pkg, err := pm.module.Lookup(pkgPath)
87-
if err != nil {
88-
return nil, err
90+
pkgDir := pm.pkgs[pkgPath]
91+
if pkgDir == "" {
92+
return nil, fmt.Errorf("%w: go list cache has no dir for package %q", llcppg.ErrConfig, pkgPath)
8993
}
90-
91-
pkgDir, err := filepath.Abs(pkg.Dir)
94+
pkgDir, err := filepath.Abs(pkgDir)
9295
if err != nil {
9396
return nil, err
9497
}
@@ -121,6 +124,61 @@ func (pm *PkgDepLoader) Import(pkgPath string) (*PkgInfo, error) {
121124
return newPkg, nil
122125
}
123126

127+
func (pm *PkgDepLoader) loadPkgDirs(deps []string) error {
128+
args := []string{"list", "-deps", "-f={{.ImportPath}}={{.Dir}}"}
129+
130+
// Warm the go-list cache with explicit dependency patterns.
131+
//
132+
// We intentionally avoid relying on `go list ... all` when deps are provided:
133+
// `all` only includes packages reachable from packages in the current main module.
134+
// At this stage, we may have finished `go get`, but generated code has not been
135+
// written yet, so those dependencies are not necessarily reachable by imports.
136+
// In that case, `all` can miss entries such as github.com/goplus/lib/c.
137+
//
138+
// So we normalize configured deps first (for example, c -> github.com/goplus/lib/c
139+
// and pkg@version -> pkg), de-duplicate them, and pass them as explicit patterns
140+
// to get stable ImportPath -> Dir mappings for later dependency loading.
141+
patterns := listPatterns(deps)
142+
args = append(args, patterns...)
143+
144+
data, err := runGoCommand(pm.root, args...)
145+
if err != nil {
146+
return errors.New("go " + strings.Join(args, " ") + ": " + err.Error() + ": " + strings.TrimSpace(string(data)))
147+
}
148+
pm.pkgs = make(map[string]string)
149+
for _, line := range strings.Split(string(data), "\n") {
150+
parts := strings.SplitN(line, "=", 2)
151+
if len(parts) == 2 && parts[0] != "" {
152+
pm.pkgs[parts[0]] = parts[1]
153+
}
154+
}
155+
return nil
156+
}
157+
158+
func listPatterns(deps []string) []string {
159+
seen := make(map[string]struct{})
160+
patterns := make([]string, 0, len(deps))
161+
for _, dep := range deps {
162+
dep, _ = IsDepStd(dep)
163+
dep, _ = splitPkgPath(dep)
164+
if _, ok := seen[dep]; ok {
165+
continue
166+
}
167+
seen[dep] = struct{}{}
168+
patterns = append(patterns, dep)
169+
}
170+
if len(patterns) == 0 {
171+
patterns = append(patterns, "all")
172+
}
173+
return patterns
174+
}
175+
176+
func runGoCommand(root string, args ...string) ([]byte, error) {
177+
cmd := exec.Command("go", args...)
178+
cmd.Dir = root
179+
return cmd.CombinedOutput()
180+
}
181+
124182
func splitPkgPath(pkgPath string) (string, string) {
125183
parts := strings.Split(pkgPath, "@")
126184
if len(parts) == 1 {

cl/internal/convert/deps_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package convert
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func TestListPatterns_NormalizeAndDedup(t *testing.T) {
9+
deps := []string{
10+
"c",
11+
"github.com/goplus/lib/c",
12+
"github.com/goplus/lib/c@v0.3.1",
13+
"github.com/goplus/llpkg/libxml2@v1.0.1",
14+
"github.com/goplus/llpkg/libxml2",
15+
}
16+
got := listPatterns(deps)
17+
want := []string{
18+
"github.com/goplus/lib/c",
19+
"github.com/goplus/llpkg/libxml2",
20+
}
21+
if !reflect.DeepEqual(got, want) {
22+
t.Fatalf("listPatterns() mismatch:\nwant: %#v\ngot: %#v", want, got)
23+
}
24+
}
25+
26+
func TestListPatterns_EmptyDepsFallbackAll(t *testing.T) {
27+
got := listPatterns(nil)
28+
want := []string{"all"}
29+
if !reflect.DeepEqual(got, want) {
30+
t.Fatalf("listPatterns() mismatch:\nwant: %#v\ngot: %#v", want, got)
31+
}
32+
}

cl/internal/convert/package.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
"github.com/goplus/llcppg/cl/nc"
1414
"github.com/goplus/llcppg/internal/name"
1515
ctoken "github.com/goplus/llcppg/token"
16-
"github.com/goplus/mod/xgomod"
1716
)
1817

1918
// In Processing Package
@@ -83,14 +82,12 @@ func NewPackage(pnc nc.NodeConverter, config *PackageConfig) (*Package, error) {
8382
config.Deps = append([]string{"c"}, config.Deps...)
8483
}
8584

86-
mod, err := xgomod.Load(config.OutputDir)
87-
if err != nil {
88-
return nil, fmt.Errorf("failed to load mod: %w", err)
89-
}
90-
9185
p.PkgInfo = NewPkgInfo(config.PkgPath, config.Deps, config.Pubs)
9286

93-
pkgManager := NewPkgDepLoader(mod, p.p)
87+
pkgManager, err := NewPkgDepLoader(config.OutputDir, p.p, config.Deps)
88+
if err != nil {
89+
return nil, fmt.Errorf("failed to preload package dirs: %w", err)
90+
}
9491
err = pkgManager.InitDeps(p.PkgInfo)
9592
if err != nil {
9693
return nil, fmt.Errorf("failed to init deps: %w", err)

cl/internal/convert/package_test.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
llcppg "github.com/goplus/llcppg/config"
1717
"github.com/goplus/llcppg/internal/name"
1818
"github.com/goplus/llcppg/token"
19-
"github.com/goplus/mod/xgomod"
2019
)
2120

2221
var dir string
@@ -1972,21 +1971,23 @@ func TestHeaderFileToGo(t *testing.T) {
19721971

19731972
func TestImport(t *testing.T) {
19741973
t.Run("invalid include path", func(t *testing.T) {
1975-
p := &convert.Package{}
19761974
genPkg := gogen.NewPackage(".", "include", nil)
1977-
mod, err := xgomod.Load(".")
1978-
if err != nil {
1979-
t.Fatal(err)
1980-
}
19811975
deps := []string{
19821976
"github.com/goplus/llcppg/cl/internal/convert/testdata/invalidpath",
19831977
"github.com/goplus/llcppg/cl/internal/convert/testdata/partfinddep",
19841978
}
1985-
p.PkgInfo = convert.NewPkgInfo(".", deps, nil)
1986-
loader := convert.NewPkgDepLoader(mod, genPkg)
1987-
depPkgs, err := loader.LoadDeps(p.PkgInfo)
1988-
p.PkgInfo.Deps = depPkgs
1989-
if err != nil && !errors.Is(err, llcppg.ErrConfig) {
1979+
_, err := convert.NewPkgDepLoader(".", genPkg, deps)
1980+
if err == nil {
1981+
t.Fatal("expected error")
1982+
}
1983+
})
1984+
t.Run("unknown import path", func(t *testing.T) {
1985+
genPkg := gogen.NewPackage(".", "include", nil)
1986+
deps := []string{
1987+
"github.com/goplus/llcppg/cl/internal/convert/testdata/cjson",
1988+
}
1989+
loader, err := convert.NewPkgDepLoader(".", genPkg, deps)
1990+
if err != nil {
19901991
t.Fatal(err)
19911992
}
19921993
_, err = loader.Import("github.com/goplus/invalidpkg")

go.mod

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,5 @@ require (
66
github.com/goplus/gogen v1.20.2
77
github.com/goplus/lib v0.3.1
88
github.com/goplus/llgo v0.12.1
9-
github.com/goplus/mod v0.19.1
109
github.com/qiniu/x v1.16.0
1110
)
12-
13-
require golang.org/x/mod v0.27.0 // indirect

go.sum

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,5 @@ github.com/goplus/lib v0.3.1 h1:Xws4DBVvgOMu58awqB972wtvTacDbk3nqcbHjdx9KSg=
44
github.com/goplus/lib v0.3.1/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
55
github.com/goplus/llgo v0.12.1 h1:LOlBxzDfano8lfeIPvNYevXbP1+aI3Ifa8JcAvOhT+A=
66
github.com/goplus/llgo v0.12.1/go.mod h1:gsOG7aJtVm8Nf2uqVWAHhklt2toZMXwxItGgLxJ9gQY=
7-
github.com/goplus/mod v0.19.1 h1:quh1tEqhqT1dRKlWec3VNu634IqmaEF7TJaPR4LqMEs=
8-
github.com/goplus/mod v0.19.1/go.mod h1:4HcnqpUHXFHWRTJXQgiHrFbvy0j3K/OEzpFh5KFYLRM=
97
github.com/qiniu/x v1.16.0 h1:W2VOecyIT3Uxwjm6vJinUR7G3gpwgUgHZA9OpeHArdE=
108
github.com/qiniu/x v1.16.0/go.mod h1:AiovSOCaRijaf3fj+0CBOpR1457pn24b0Vdb1JpwhII=
11-
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
12-
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=

0 commit comments

Comments
 (0)