github.com/sc0rp1us/gb@v0.4.1-0.20160319180011-4ba8cf1baa5a/vendor/depset.go (about)

     1  package vendor
     2  
     3  import (
     4  	"fmt"
     5  	"go/build"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  )
    10  
    11  // Pkg describes a Go package.
    12  type Pkg struct {
    13  	*Depset
    14  	*build.Package
    15  }
    16  
    17  // Depset describes a set of related Go packages.
    18  type Depset struct {
    19  	Root   string
    20  	Prefix string
    21  	Pkgs   map[string]*Pkg
    22  }
    23  
    24  // LoadPaths returns a map of paths to Depsets.
    25  func LoadPaths(paths ...struct{ Root, Prefix string }) (map[string]*Depset, error) {
    26  	m := make(map[string]*Depset)
    27  	for _, p := range paths {
    28  		set, err := LoadTree(p.Root, p.Prefix)
    29  		if err != nil {
    30  			return nil, err
    31  		}
    32  		m[set.Root] = set
    33  	}
    34  	return m, nil
    35  }
    36  
    37  // LoadTree parses a tree of source files into a map of *pkgs.
    38  func LoadTree(root string, prefix string) (*Depset, error) {
    39  	d := Depset{
    40  		Root:   root,
    41  		Prefix: prefix,
    42  		Pkgs:   make(map[string]*Pkg),
    43  	}
    44  	fn := func(dir string, fi os.FileInfo) error {
    45  		importpath := filepath.Join(prefix, dir[len(root)+1:])
    46  
    47  		// if we're at the root of a tree, skip it
    48  		if importpath == "" {
    49  			return nil
    50  		}
    51  
    52  		p, err := loadPackage(&d, dir)
    53  		if err != nil {
    54  			if _, ok := err.(*build.NoGoError); ok {
    55  				return nil
    56  			}
    57  			return fmt.Errorf("loadPackage(%q, %q): %v", dir, importpath, err)
    58  		}
    59  		p.ImportPath = filepath.ToSlash(importpath)
    60  		if p != nil {
    61  			d.Pkgs[p.ImportPath] = p
    62  		}
    63  		return nil
    64  	}
    65  
    66  	// handle root of the tree
    67  	fi, err := os.Stat(root)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	if err := fn(root+string(filepath.Separator), fi); err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	// walk sub directories
    76  	err = eachDir(root, fn)
    77  	return &d, err
    78  }
    79  
    80  func loadPackage(d *Depset, dir string) (*Pkg, error) {
    81  	p := Pkg{
    82  		Depset: d,
    83  	}
    84  	var err error
    85  
    86  	// expolit local import logic
    87  	p.Package, err = build.ImportDir(dir, build.ImportComment)
    88  	return &p, err
    89  }
    90  
    91  func eachDir(dir string, fn func(string, os.FileInfo) error) error {
    92  	f, err := os.Open(dir)
    93  	if err != nil {
    94  		return err
    95  	}
    96  	defer f.Close()
    97  	files, err := f.Readdir(-1)
    98  	for _, fi := range files {
    99  		if !fi.IsDir() {
   100  			continue
   101  		}
   102  		if strings.HasPrefix(fi.Name(), "_") || strings.HasPrefix(fi.Name(), ".") || fi.Name() == "testdata" {
   103  			continue
   104  		}
   105  		path := filepath.Join(dir, fi.Name())
   106  		if err := fn(path, fi); err != nil {
   107  			return err
   108  		}
   109  		if err := eachDir(path, fn); err != nil {
   110  			return err
   111  		}
   112  	}
   113  	return nil
   114  }