Skip to content
This repository has been archived by the owner on Oct 27, 2021. It is now read-only.

Commit

Permalink
Cache imported packages
Browse files Browse the repository at this point in the history
This commit adds a types.Importer that caches packages.  The uses the
filepath of the object/archive file associated with a package as the key
so that vendoring is supported (it also makes the cache relatively simple).
The timestamp of the object/archive file is used to determine when a
package should be re-imported.
  • Loading branch information
Charlie Vieth committed Sep 8, 2018
1 parent 00e7f5a commit ba75703
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 3 deletions.
96 changes: 96 additions & 0 deletions internal/goimporter/goimporter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package goimporter

import (
"fmt"
"go/importer"
"go/types"
"os"
"runtime"
"sync"
"time"

"golang.org/x/tools/go/gcexportdata"
)

type entry struct {
Filename string // object (.o) or archive (.a) filename
ModTime time.Time // binary package modified time
Package *types.Package
}

type goimporter struct {
pkgs map[string]*entry
mu sync.RWMutex
compiler string
}

func For(compiler string) types.ImporterFrom {
return &goimporter{
pkgs: make(map[string]*entry),
compiler: compiler,
}
}

func Default() types.ImporterFrom {
return For(runtime.Compiler)
}

func (m *goimporter) load(filename string) (*entry, bool) {
m.mu.RLock()
pkg, ok := m.pkgs[filename]
m.mu.RUnlock()
return pkg, ok
}

func (m *goimporter) store(pkg *entry) *entry {
m.mu.Lock()
found, ok := m.pkgs[pkg.Filename]
if !ok || found.ModTime.Before(pkg.ModTime) {
m.pkgs[pkg.Filename] = pkg
} else {
pkg = found
}
m.mu.Unlock()
return pkg
}

func (m *goimporter) Import(path string) (*types.Package, error) {
return m.ImportFrom(path, "", 0)
}

func (m *goimporter) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) {
filename, id := gcexportdata.Find(path, srcDir)
if filename == "" {
if path == "unsafe" {
return types.Unsafe, nil
}
return nil, fmt.Errorf("can't find import: %q", id)
}
fi, err := os.Stat(filename)
if err != nil {
return nil, fmt.Errorf("can't stat package file (%s) for import (%s): %s",
filename, id, err)
}
modtime := fi.ModTime()

// TODO: instrument cache hits/misses
if pkg, ok := m.load(filename); ok && pkg.ModTime.Equal(modtime) {
return pkg.Package, nil
}

// TODO: consider reusing importer for packages (stdlib) ???
imp := importer.Default().(types.ImporterFrom)
bpkg, err := imp.ImportFrom(path, srcDir, 0)
if err != nil {
return nil, fmt.Errorf("importing package (%s) from dir (%s): %s",
path, srcDir, err)
}

// store package and return result (in case a newer version was added)
pkg := m.store(&entry{
Filename: filename,
ModTime: modtime,
Package: bpkg,
})
return pkg.Package, nil
}
11 changes: 8 additions & 3 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main
import (
"bytes"
"fmt"
"go/importer"
"go/types"
"log"
"net"
Expand All @@ -14,6 +13,7 @@ import (
"time"

"github.com/mdempsky/gocode/internal/gbimporter"
"github.com/mdempsky/gocode/internal/goimporter"
"github.com/mdempsky/gocode/internal/suggest"
)

Expand Down Expand Up @@ -65,6 +65,11 @@ type AutoCompleteReply struct {
Len int
}

var (
binImporter = goimporter.Default()
srcImporter = goimporter.For("source")
)

func (s *Server) AutoComplete(req *AutoCompleteRequest, res *AutoCompleteReply) error {
defer func() {
if err := recover(); err != nil {
Expand All @@ -90,9 +95,9 @@ func (s *Server) AutoComplete(req *AutoCompleteRequest, res *AutoCompleteReply)
now := time.Now()
var underlying types.ImporterFrom
if req.Source {
underlying = importer.For("source", nil).(types.ImporterFrom)
underlying = srcImporter
} else {
underlying = importer.Default().(types.ImporterFrom)
underlying = binImporter
}
cfg := suggest.Config{
Importer: gbimporter.New(&req.Context, req.Filename, underlying),
Expand Down

0 comments on commit ba75703

Please sign in to comment.