Skip to content

Instantly share code, notes, and snippets.

@xlab
Created December 26, 2017 00:18
Show Gist options
  • Save xlab/b492b49498219901eb28bad6c93fcf47 to your computer and use it in GitHub Desktop.
Save xlab/b492b49498219901eb28bad6c93fcf47 to your computer and use it in GitHub Desktop.
Collect Go package dependency file tree (an overkilled version with multiple packages per file).
package main
func findDeps(p *build.Package, includes, excludes []string, debug bool) (map[string]map[string]struct{}, error) {
excludeRxs, err := compileRxs(excludes)
if err != nil {
return nil, err
}
deps := make(map[string]map[string]struct{}, len(p.Imports))
addDeps := func(parent, dep *build.Package) {
if !containsPrefix(dep.ImportPath, includes) {
return
}
for _, f := range dep.GoFiles {
path := filepath.Join(dep.Dir, f)
if deps[path] == nil {
deps[path] = make(map[string]struct{})
}
deps[path][parent.ImportPath] = struct{}{}
}
for _, f := range dep.HFiles {
path := filepath.Join(dep.Dir, f)
if deps[path] == nil {
deps[path] = make(map[string]struct{})
}
deps[path][parent.ImportPath] = struct{}{}
}
for _, f := range dep.CFiles {
path := filepath.Join(dep.Dir, f)
if deps[path] == nil {
deps[path] = make(map[string]struct{})
}
deps[path][parent.ImportPath] = struct{}{}
}
}
seenDeps := make(map[string]struct{}, len(p.Imports))
addImports := func(parent *build.Package) []*build.Package {
addDeps(parent, parent)
seenDeps[p.ImportPath] = struct{}{}
list := make([]*build.Package, 0, len(p.Imports))
for _, pkg := range p.Imports {
if _, ok := seenDeps[pkg]; ok {
continue
}
if dep, err := build.Import(pkg, "", 0); err == nil {
addDeps(parent, dep)
seenDeps[pkg] = struct{}{}
list = append(list, dep)
}
}
return list
}
list := addImports(p)
for len(list) > 0 {
newList := make([]*build.Package, 0, len(list))
for _, p := range list {
newList = append(newList, addImports(p)...)
}
list = newList
}
for path := range deps {
if isMatching(path, excludeRxs) {
if debug {
log.Println("gody watch: skipping", path)
}
delete(deps, path)
}
}
return deps, nil
}
func isMatching(path string, rxs []*regexp.Regexp) bool {
for _, rx := range rxs {
if rx.MatchString(path) {
return true
}
}
return false
}
func compileRxs(rxs []string) ([]*regexp.Regexp, error) {
var compiled []*regexp.Regexp
for _, rx := range rxs {
r, err := regexp.Compile(rx)
if err != nil {
return nil, fmt.Errorf("failed to parse Regexp: %s error: %v", rx, err)
}
compiled = append(compiled, r)
}
return compiled, nil
}
func containsPrefix(path string, prefixes []string) bool {
for _, p := range prefixes {
if p == "..." {
return true
}
if strings.HasPrefix(path, p) {
return true
}
}
return false
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment