| package vendor |
| |
| import ( |
| "fmt" |
| "go/build" |
| "os" |
| "path/filepath" |
| "strings" |
| ) |
| |
| // Pkg describes a Go package. |
| type Pkg struct { |
| *Depset |
| *build.Package |
| } |
| |
| // Depset describes a set of related Go packages. |
| type Depset struct { |
| Root string |
| Prefix string |
| Pkgs map[string]*Pkg |
| } |
| |
| // LoadPaths returns a map of paths to Depsets. |
| func LoadPaths(paths ...struct{ Root, Prefix string }) (map[string]*Depset, error) { |
| m := make(map[string]*Depset) |
| for _, p := range paths { |
| set, err := LoadTree(p.Root, p.Prefix) |
| if err != nil { |
| return nil, err |
| } |
| m[set.Root] = set |
| } |
| return m, nil |
| } |
| |
| // LoadTree parses a tree of source files into a map of *pkgs. |
| func LoadTree(root string, prefix string) (*Depset, error) { |
| d := Depset{ |
| Root: root, |
| Prefix: prefix, |
| Pkgs: make(map[string]*Pkg), |
| } |
| fn := func(dir string, fi os.FileInfo) error { |
| importpath := filepath.Join(prefix, dir[len(root)+1:]) |
| |
| // if we're at the root of a tree, skip it |
| if importpath == "" { |
| return nil |
| } |
| |
| p, err := loadPackage(&d, dir) |
| if err != nil { |
| if _, ok := err.(*build.NoGoError); ok { |
| return nil |
| } |
| return fmt.Errorf("loadPackage(%q, %q): %v", dir, importpath, err) |
| } |
| p.ImportPath = filepath.ToSlash(importpath) |
| if p != nil { |
| d.Pkgs[p.ImportPath] = p |
| } |
| return nil |
| } |
| |
| // handle root of the tree |
| fi, err := os.Stat(root) |
| if err != nil { |
| return nil, err |
| } |
| if err := fn(root+string(filepath.Separator), fi); err != nil { |
| return nil, err |
| } |
| |
| // walk sub directories |
| err = eachDir(root, fn) |
| return &d, err |
| } |
| |
| func loadPackage(d *Depset, dir string) (*Pkg, error) { |
| p := Pkg{ |
| Depset: d, |
| } |
| var err error |
| |
| // expolit local import logic |
| p.Package, err = build.ImportDir(dir, build.ImportComment) |
| return &p, err |
| } |
| |
| func eachDir(dir string, fn func(string, os.FileInfo) error) error { |
| f, err := os.Open(dir) |
| if err != nil { |
| return err |
| } |
| defer f.Close() |
| files, err := f.Readdir(-1) |
| for _, fi := range files { |
| if !fi.IsDir() { |
| continue |
| } |
| if strings.HasPrefix(fi.Name(), "_") || strings.HasPrefix(fi.Name(), ".") || fi.Name() == "testdata" { |
| continue |
| } |
| path := filepath.Join(dir, fi.Name()) |
| if err := fn(path, fi); err != nil { |
| return err |
| } |
| if err := eachDir(path, fn); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |