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

     1  package vendor
     2  
     3  import (
     4  	"fmt"
     5  	"go/parser"
     6  	"go/token"
     7  	"io"
     8  	"net/http"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  )
    13  
    14  // ParseImports parses Go packages from a specific root returning a set of import paths.
    15  func ParseImports(root string) (map[string]bool, error) {
    16  	pkgs := make(map[string]bool)
    17  
    18  	var walkFn = func(path string, info os.FileInfo, err error) error {
    19  		if info.IsDir() {
    20  			name := info.Name()
    21  			if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "_") || name == "testdata" {
    22  				return filepath.SkipDir
    23  			}
    24  			return nil
    25  		}
    26  		if filepath.Ext(path) != ".go" { // Parse only go source files
    27  			return nil
    28  		}
    29  
    30  		fs := token.NewFileSet()
    31  		f, err := parser.ParseFile(fs, path, nil, parser.ImportsOnly)
    32  		if err != nil {
    33  			return err
    34  		}
    35  
    36  		for _, s := range f.Imports {
    37  			p := strings.Replace(s.Path.Value, "\"", "", -1)
    38  			pkgs[p] = true
    39  		}
    40  		return nil
    41  	}
    42  
    43  	err := filepath.Walk(root, walkFn)
    44  	return pkgs, err
    45  }
    46  
    47  // FetchMetadata fetchs the remote metadata for path.
    48  func FetchMetadata(path string, insecure bool) (rc io.ReadCloser, err error) {
    49  	defer func() {
    50  		if err != nil {
    51  			err = fmt.Errorf("unable to determine remote metadata protocol: %s", err)
    52  		}
    53  	}()
    54  	// try https first
    55  	rc, err = fetchMetadata("https", path)
    56  	if err == nil {
    57  		return
    58  	}
    59  	// try http if supported
    60  	if insecure {
    61  		rc, err = fetchMetadata("http", path)
    62  	}
    63  	return
    64  }
    65  
    66  func fetchMetadata(scheme, path string) (io.ReadCloser, error) {
    67  	url := fmt.Sprintf("%s://%s?go-get=1", scheme, path)
    68  	switch scheme {
    69  	case "https", "http":
    70  		resp, err := http.Get(url)
    71  		if err != nil {
    72  			return nil, fmt.Errorf("failed to access url %q", url)
    73  		}
    74  		return resp.Body, nil
    75  	default:
    76  		return nil, fmt.Errorf("unknown remote protocol scheme: %q", scheme)
    77  	}
    78  }
    79  
    80  // ParseMetadata fetchs and decodes remote metadata for path.
    81  func ParseMetadata(path string, insecure bool) (string, string, string, error) {
    82  	rc, err := FetchMetadata(path, insecure)
    83  	if err != nil {
    84  		return "", "", "", err
    85  	}
    86  	defer rc.Close()
    87  
    88  	imports, err := parseMetaGoImports(rc)
    89  	if err != nil {
    90  		return "", "", "", err
    91  	}
    92  	match := -1
    93  	for i, im := range imports {
    94  		if !strings.HasPrefix(path, im.Prefix) {
    95  			continue
    96  		}
    97  		if match != -1 {
    98  			return "", "", "", fmt.Errorf("multiple meta tags match import path %q", path)
    99  		}
   100  		match = i
   101  	}
   102  	if match == -1 {
   103  		return "", "", "", fmt.Errorf("go-import metadata not found")
   104  	}
   105  	return imports[match].Prefix, imports[match].VCS, imports[match].RepoRoot, nil
   106  }