github.com/sc0rp1us/gb@v0.4.1-0.20160319180011-4ba8cf1baa5a/vendor/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 vendor 6 7 import ( 8 "encoding/xml" 9 "fmt" 10 "io" 11 "strings" 12 ) 13 14 // charsetReader returns a reader for the given charset. Currently 15 // it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful 16 // error which is printed by go get, so the user can find why the package 17 // wasn't downloaded if the encoding is not supported. Note that, in 18 // order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters 19 // greater than 0x7f are not rejected). 20 func charsetReader(charset string, input io.Reader) (io.Reader, error) { 21 switch strings.ToLower(charset) { 22 case "ascii": 23 return input, nil 24 default: 25 return nil, fmt.Errorf("can't decode XML document using charset %q", charset) 26 } 27 } 28 29 type metaImport struct { 30 Prefix, VCS, RepoRoot string 31 } 32 33 // parseMetaGoImports returns meta imports from the HTML in r. 34 // Parsing ends at the end of the <head> section or the beginning of the <body>. 35 func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) { 36 d := xml.NewDecoder(r) 37 d.CharsetReader = charsetReader 38 d.Strict = false 39 var t xml.Token 40 for { 41 t, err = d.Token() 42 if err != nil { 43 if err == io.EOF { 44 err = nil 45 } 46 return 47 } 48 if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") { 49 return 50 } 51 if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") { 52 return 53 } 54 e, ok := t.(xml.StartElement) 55 if !ok || !strings.EqualFold(e.Name.Local, "meta") { 56 continue 57 } 58 if attrValue(e.Attr, "name") != "go-import" { 59 continue 60 } 61 if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 { 62 imports = append(imports, metaImport{ 63 Prefix: f[0], 64 VCS: f[1], 65 RepoRoot: f[2], 66 }) 67 } 68 } 69 } 70 71 // attrValue returns the attribute value for the case-insensitive key 72 // `name', or the empty string if nothing is found. 73 func attrValue(attrs []xml.Attr, name string) string { 74 for _, a := range attrs { 75 if strings.EqualFold(a.Name.Local, name) { 76 return a.Value 77 } 78 } 79 return "" 80 }