blob: 0124483d3f28dfbe4b45c5b81ed8eb890d79234b [file] [log] [blame]
package vendor
import (
"fmt"
"go/parser"
"go/token"
"io"
"net/http"
"os"
"path/filepath"
"strings"
)
// ParseImports parses Go packages from a specific root returning a set of import paths.
func ParseImports(root string) (map[string]bool, error) {
pkgs := make(map[string]bool)
var walkFn = func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
name := info.Name()
if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "_") || name == "testdata" {
return filepath.SkipDir
}
return nil
}
if filepath.Ext(path) != ".go" { // Parse only go source files
return nil
}
fs := token.NewFileSet()
f, err := parser.ParseFile(fs, path, nil, parser.ImportsOnly)
if err != nil {
return err
}
for _, s := range f.Imports {
p := strings.Replace(s.Path.Value, "\"", "", -1)
pkgs[p] = true
}
return nil
}
err := filepath.Walk(root, walkFn)
return pkgs, err
}
// FetchMetadata fetchs the remote metadata for path.
func FetchMetadata(path string, insecure bool) (rc io.ReadCloser, err error) {
defer func() {
if err != nil {
err = fmt.Errorf("unable to determine remote metadata protocol: %s", err)
}
}()
// try https first
rc, err = fetchMetadata("https", path)
if err == nil {
return
}
// try http if supported
if insecure {
rc, err = fetchMetadata("http", path)
}
return
}
func fetchMetadata(scheme, path string) (io.ReadCloser, error) {
url := fmt.Sprintf("%s://%s?go-get=1", scheme, path)
switch scheme {
case "https", "http":
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("failed to access url %q", url)
}
return resp.Body, nil
default:
return nil, fmt.Errorf("unknown remote protocol scheme: %q", scheme)
}
}
// ParseMetadata fetchs and decodes remote metadata for path.
func ParseMetadata(path string, insecure bool) (string, string, string, error) {
rc, err := FetchMetadata(path, insecure)
if err != nil {
return "", "", "", err
}
defer rc.Close()
imports, err := parseMetaGoImports(rc)
if err != nil {
return "", "", "", err
}
match := -1
for i, im := range imports {
if !strings.HasPrefix(path, im.Prefix) {
continue
}
if match != -1 {
return "", "", "", fmt.Errorf("multiple meta tags match import path %q", path)
}
match = i
}
if match == -1 {
return "", "", "", fmt.Errorf("go-import metadata not found")
}
return imports[match].Prefix, imports[match].VCS, imports[match].RepoRoot, nil
}