1
0
mirror of https://github.com/golang/go synced 2024-11-05 14:46:11 -07:00
go/refactor/importgraph/graph.go
Alan Donovan e079f6c632 go/ssa: change import path of synthetic test package to "test$main"
...to avoid namespace conflicts.
Also make its name "main", since it defines func main().

And fix 2 typos.

Change-Id: I7cf7894d6bed134907b3d2742255e5a82426071b
Reviewed-on: https://go-review.googlesource.com/3150
Reviewed-by: Robert Griesemer <gri@golang.org>
2015-01-21 22:21:01 +00:00

124 lines
2.8 KiB
Go

// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package importgraph computes the forward and reverse import
// dependency graphs for all packages in a Go workspace.
package importgraph // import "golang.org/x/tools/refactor/importgraph"
import (
"go/build"
"sync"
"golang.org/x/tools/go/buildutil"
)
// A Graph is an import dependency graph, either forward or reverse.
//
// The graph maps each node (a package import path) to the set of its
// successors in the graph. For a forward graph, this is the set of
// imported packages (prerequisites); for a reverse graph, it is the set
// of importing packages (clients).
//
type Graph map[string]map[string]bool
func (g Graph) addEdge(from, to string) {
edges := g[from]
if edges == nil {
edges = make(map[string]bool)
g[from] = edges
}
edges[to] = true
}
// Search returns all the nodes of the graph reachable from
// any of the specified roots, by following edges forwards.
// Relationally, this is the reflexive transitive closure.
func (g Graph) Search(roots ...string) map[string]bool {
seen := make(map[string]bool)
var visit func(x string)
visit = func(x string) {
if !seen[x] {
seen[x] = true
for y := range g[x] {
visit(y)
}
}
}
for _, root := range roots {
visit(root)
}
return seen
}
// Build scans the specified Go workspace and builds the forward and
// reverse import dependency graphs for all its packages.
// It also returns a mapping from import paths to errors for packages
// that could not be loaded.
func Build(ctxt *build.Context) (forward, reverse Graph, errors map[string]error) {
type importEdge struct {
from, to string
}
type pathError struct {
path string
err error
}
ch := make(chan interface{})
var wg sync.WaitGroup
buildutil.ForEachPackage(ctxt, func(path string, err error) {
wg.Add(1)
go func() {
defer wg.Done()
if err != nil {
ch <- pathError{path, err}
return
}
bp, err := ctxt.Import(path, "", 0)
if _, ok := err.(*build.NoGoError); ok {
return // empty directory is not an error
}
if err != nil {
ch <- pathError{path, err}
return
}
for _, imp := range bp.Imports {
ch <- importEdge{path, imp}
}
for _, imp := range bp.TestImports {
ch <- importEdge{path, imp}
}
for _, imp := range bp.XTestImports {
ch <- importEdge{path, imp}
}
}()
})
go func() {
wg.Wait()
close(ch)
}()
forward = make(Graph)
reverse = make(Graph)
for e := range ch {
switch e := e.(type) {
case pathError:
if errors == nil {
errors = make(map[string]error)
}
errors[e.path] = e.err
case importEdge:
if e.to == "C" {
continue // "C" is fake
}
forward.addEdge(e.from, e.to)
reverse.addEdge(e.to, e.from)
}
}
return forward, reverse, errors
}