github.com/golang/dep@v0.5.4/gps/discovery.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gps 6 7 // This code is taken from cmd/go/discovery.go; it is the logic go get itself 8 // uses to interpret meta imports information. 9 10 import ( 11 "encoding/xml" 12 "fmt" 13 "io" 14 "strings" 15 ) 16 17 // charsetReader returns a reader for the given charset. Currently 18 // it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful 19 // error which is printed by go get, so the user can find why the package 20 // wasn't downloaded if the encoding is not supported. Note that, in 21 // order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters 22 // greater than 0x7f are not rejected). 23 func charsetReader(charset string, input io.Reader) (io.Reader, error) { 24 switch strings.ToLower(charset) { 25 case "ascii": 26 return input, nil 27 default: 28 return nil, fmt.Errorf("can't decode XML document using charset %q", charset) 29 } 30 } 31 32 type metaImport struct { 33 Prefix, VCS, RepoRoot string 34 } 35 36 // parseMetaGoImports returns meta imports from the HTML in r. 37 // Parsing ends at the end of the <head> section or the beginning of the <body>. 38 // 39 // This copy of cmd/go/internal/vcs.parseMetaGoImports always operates 40 // in IgnoreMod ModuleMode. 41 func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) { 42 d := xml.NewDecoder(r) 43 d.CharsetReader = charsetReader 44 d.Strict = false 45 var t xml.Token 46 for { 47 t, err = d.RawToken() 48 if err != nil { 49 if err == io.EOF || len(imports) > 0 { 50 err = nil 51 } 52 return 53 } 54 if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") { 55 return 56 } 57 if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") { 58 return 59 } 60 e, ok := t.(xml.StartElement) 61 if !ok || !strings.EqualFold(e.Name.Local, "meta") { 62 continue 63 } 64 if attrValue(e.Attr, "name") != "go-import" { 65 continue 66 } 67 if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 { 68 // Ignore VCS type "mod", which is applicable only in module mode. 69 if f[1] == "mod" { 70 continue 71 } 72 imports = append(imports, metaImport{ 73 Prefix: f[0], 74 VCS: f[1], 75 RepoRoot: f[2], 76 }) 77 } 78 } 79 } 80 81 // attrValue returns the attribute value for the case-insensitive key 82 // `name', or the empty string if nothing is found. 83 func attrValue(attrs []xml.Attr, name string) string { 84 for _, a := range attrs { 85 if strings.EqualFold(a.Name.Local, name) { 86 return a.Value 87 } 88 } 89 return "" 90 }