| 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 |
| } |