Skip to content

Commit

Permalink
save: only save our roots' test imports (robfig#38)
Browse files Browse the repository at this point in the history
* save: only save our roots' test imports

This transitively avoids saving test imports, except for those which
are directly imported by the target package or its subpackages.

* [TBS]: correctly evaluate all packages with each value of useAllFiles
  • Loading branch information
tamird authored and robfig committed Nov 22, 2016
1 parent 7bc8ce5 commit 4222fa4
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 38 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
sudo: false
language: go
go:
- 1.7
- 1.6
- 1.5
- 1.4
Expand Down
106 changes: 70 additions & 36 deletions save.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"sort"
"strings"

"golang.org/x/tools/refactor/importgraph"
"golang.org/x/tools/go/buildutil"
)

var cmdSave = &Command{
Expand Down Expand Up @@ -137,59 +137,93 @@ func (p byImportPath) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// getAllDeps returns a slice of package import paths for all dependencies
// (including test dependencies) of the given import path (and subpackages) and commands.
func getAllDeps(importPath string, cmds []string) []string {
deps := map[string]struct{}{}
roots := map[string]struct{}{
importPath: {},
}
subpackagePrefix := importPath + "/"

// Add the command packages. Note that external command packages are
// considered dependencies.
for _, pkg := range cmds {
roots[pkg] = struct{}{}
var depsSlice []string
for _, useAllFiles := range []bool{false, true} {
printLoadingError := func(path string, err error) {
if err != nil && !useAllFiles {
// Lots of errors because of UseAllFiles.
log.Printf("error loading package %s: %s", path, err)
}
}

if !strings.HasPrefix(pkg, subpackagePrefix) {
deps[pkg] = struct{}{}
deps := map[string]struct{}{}
roots := map[string]struct{}{
importPath: {},
}
}

for _, useAllFiles := range []bool{false, true} {
buildContext := build.Default
buildContext.CgoEnabled = true
buildContext.UseAllFiles = useAllFiles
// Add the command packages. Note that external command packages are
// considered dependencies.
for _, pkg := range cmds {
roots[pkg] = struct{}{}

forward, _, errs := importgraph.Build(&buildContext)
for pkg, err := range errs {
// Lots of errors because of UseAllFiles.
if !useAllFiles {
log.Printf("error loading package %s: %v", pkg, err)
if !strings.HasPrefix(pkg, subpackagePrefix) {
deps[pkg] = struct{}{}
}
}

buildContext := build.Default
buildContext.CgoEnabled = true
buildContext.UseAllFiles = useAllFiles

// Add the subpackages.
for pkg := range forward {
if strings.HasPrefix(pkg, subpackagePrefix) {
roots[pkg] = struct{}{}
for path := range buildutil.ExpandPatterns(&buildContext, []string{subpackagePrefix + "..."}) {
_, err := buildContext.Import(path, "", 0)
if _, ok := err.(*build.NoGoError); ok {
continue
}
printLoadingError(path, err)
roots[path] = struct{}{}
}

// Get the reflexive transitive closure for all packages of interest.
for pkg := range forward.Search(setToSlice(roots)...) {
// Exclude our roots. Note that commands are special-cased above.
if _, ok := roots[pkg]; ok {
continue
var addTransitiveClosure func(string)
addTransitiveClosure = func(path string) {
pkg, err := buildContext.Import(path, "", 0)
printLoadingError(path, err)

importPaths := append([]string(nil), pkg.Imports...)
if _, ok := roots[path]; ok {
importPaths = append(importPaths, pkg.TestImports...)
importPaths = append(importPaths, pkg.XTestImports...)
}
slash := strings.IndexByte(pkg, '/')
stdLib := slash == -1 || strings.IndexByte(pkg[:slash], '.') == -1
// Exclude the standard library.
if stdLib {
continue

for _, path := range importPaths {
if path == "C" {
continue // "C" is fake
}

// Resolve the import path relative to the importing package.
if bp2, _ := buildContext.Import(path, pkg.Dir, build.FindOnly); bp2 != nil {
path = bp2.ImportPath
}

// Exclude our roots. Note that commands are special-cased above.
if _, ok := roots[path]; ok {
continue
}
slash := strings.IndexByte(path, '/')
stdLib := slash == -1 || strings.IndexByte(path[:slash], '.') == -1
// Exclude the standard library.
if stdLib {
continue
}
if _, ok := deps[path]; !ok {
deps[path] = struct{}{}
addTransitiveClosure(path)
}
}
deps[pkg] = struct{}{}
}

for path := range roots {
addTransitiveClosure(path)
}
addTransitiveClosure(importPath)

depsSlice = append(depsSlice, setToSlice(deps)...)
}

return setToSlice(deps)
return depsSlice
}

func run(name string, args ...string) ([]byte, error) {
Expand Down
3 changes: 1 addition & 2 deletions save_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ var saveTests = []saveTest{

// the following should be included:
// - package's tests' dependencies
// the following should be excluded:
// - package's dependencies' tests' dependencies
// - package's tests' dependencies' tests' dependencies
{
Expand Down Expand Up @@ -132,8 +133,6 @@ var saveTests = []saveTest{
[]string{
"github.com/test/p2",
"github.com/test/p3",
"github.com/test/p4",
"github.com/test/p5",
},
},

Expand Down

0 comments on commit 4222fa4

Please sign in to comment.