diff --git a/packages/cache/cache.go b/packages/cache/cache.go index 1d60812..0089179 100644 --- a/packages/cache/cache.go +++ b/packages/cache/cache.go @@ -16,6 +16,7 @@ package cache import ( "bytes" "errors" + "io" "os" "os/exec" "strconv" @@ -84,21 +85,21 @@ func (p *Impl) Prepare(dir string, pkgPath ...string) (err error) { } // Find finds the cache for a pkgPath. -func (p *Impl) Find(dir, pkgPath string) (expfile string, err error) { +func (p *Impl) Find(dir, pkgPath string) (f io.ReadCloser, err error) { val, ok := p.cache.Load(pkgPath) - if !ok || isDirty(pkgPath, val, p.h) { + if !ok || isDirty(&f, pkgPath, val, p.h) { err = p.Prepare(dir, pkgPath) - if val, ok = p.cache.Load(pkgPath); !ok { - if err == nil { - err = os.ErrNotExist - } - return + if val, ok = p.cache.Load(pkgPath); ok { + return os.Open(val.(*pkgCache).expfile) + } + if err == nil { + err = os.ErrNotExist } } - return val.(*pkgCache).expfile, nil + return } -func isDirty(pkgPath string, val any, h PkgHash) bool { +func isDirty(pf *io.ReadCloser, pkgPath string, val any, h PkgHash) bool { pkg := val.(*pkgCache) if pkg.hash == HashInvalid || h(pkgPath, true) != pkg.hash { return true @@ -108,7 +109,9 @@ func isDirty(pkgPath string, val any, h PkgHash) bool { return true } } - return false + f, err := os.Open(pkg.expfile) + *pf = f + return err != nil } type exportPkg struct { diff --git a/packages/cache/cache_test.go b/packages/cache/cache_test.go index 3e7c941..32a9e2b 100644 --- a/packages/cache/cache_test.go +++ b/packages/cache/cache_test.go @@ -109,7 +109,7 @@ func TestIsDirty(t *testing.T) { c := &pkgCache{"1.a", "a", []depPkg{ {"b", "b"}, }} - if !isDirty("a", c, func(pkgPath string, self bool) (hash string) { + if !isDirty(nil, "a", c, func(pkgPath string, self bool) (hash string) { if self { return pkgPath } diff --git a/packages/imp.go b/packages/imp.go index bbc5a2e..373dedd 100644 --- a/packages/imp.go +++ b/packages/imp.go @@ -18,6 +18,7 @@ import ( "errors" "go/token" "go/types" + "io" "os" "os/exec" "sync" @@ -30,7 +31,7 @@ import ( // Cache represents a cache for the importer. type Cache interface { - Find(dir, pkgPath string) (expfile string, err error) + Find(dir, pkgPath string) (f io.ReadCloser, err error) } // Importer represents a Go package importer. @@ -87,20 +88,15 @@ func (p *Importer) ImportFrom(pkgPath, dir string, mode types.ImportMode) (*type return ret, nil } p.m.RUnlock() - expfile, err := p.findExport(dir, pkgPath) - if err != nil { - return nil, err - } - return p.loadByExport(expfile, pkgPath) -} - -func (p *Importer) loadByExport(expfile string, pkgPath string) (ret *types.Package, err error) { - f, err := os.Open(expfile) + f, err := p.findExport(dir, pkgPath) if err != nil { return nil, err } defer f.Close() + return p.loadByExport(f, pkgPath) +} +func (p *Importer) loadByExport(f io.ReadCloser, pkgPath string) (ret *types.Package, err error) { r, err := gcexportdata.NewReader(f) if err == nil { p.m.Lock() // use mutex because Import should be multi-thread safe @@ -113,7 +109,7 @@ func (p *Importer) loadByExport(expfile string, pkgPath string) (ret *types.Pack // ---------------------------------------------------------------------------- // findExport lookups export file (.a) of a package by its pkgPath. -func (p *Importer) findExport(dir, pkgPath string) (expfile string, err error) { +func (p *Importer) findExport(dir, pkgPath string) (f io.ReadCloser, err error) { if c := p.cache; c != nil { return c.Find(dir, pkgPath) } @@ -122,8 +118,8 @@ func (p *Importer) findExport(dir, pkgPath string) (expfile string, err error) { if err != nil { return } - expfile = string(bytes.TrimSuffix(data, []byte{'\n'})) - return + expfile := string(bytes.TrimSuffix(data, []byte{'\n'})) + return os.Open(expfile) } func golistExport(dir, pkgPath string) (ret []byte, err error) { diff --git a/packages/imp_test.go b/packages/imp_test.go index 24363f4..841ef4b 100644 --- a/packages/imp_test.go +++ b/packages/imp_test.go @@ -14,6 +14,8 @@ package packages import ( + "go/types" + "io" "os" "testing" ) @@ -50,10 +52,20 @@ func TestImportBuiltin(t *testing.T) { func Test_loadByExport(t *testing.T) { p := NewImporter(nil) - if _, err := p.loadByExport("/not-found", "notfound"); !os.IsNotExist(err) { + if _, err := loadByExport(p, "/not-found", "notfound"); !os.IsNotExist(err) { + t.Fatal("Test_loadByExport:", err) + } + if _, err := p.findExport(".", "C"); err == nil { t.Fatal("Test_loadByExport: no error?") } - p.findExport(".", "C") +} + +func loadByExport(p *Importer, expfile, pkgPath string) (pkg *types.Package, err error) { + f, err := os.Open(expfile) + if err != nil { + return + } + return p.loadByExport(f, pkgPath) } // ---------------------------------------------------------------------------- @@ -62,11 +74,11 @@ type diskCache struct { imp *Importer } -func (p diskCache) Find(dir, pkgPath string) (expfile string, err error) { +func (p diskCache) Find(dir, pkgPath string) (f io.ReadCloser, err error) { if p.imp != nil { return p.imp.findExport(dir, pkgPath) } - return "", os.ErrNotExist + return nil, os.ErrNotExist } func TestCache(t *testing.T) {