Home | History | Annotate | Download | only in go
      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 // +build !cmd_go_bootstrap
      6 
      7 // This code is compiled into the real 'go' binary, but it is not
      8 // compiled into the binary that is built during all.bash, so as
      9 // to avoid needing to build net (and thus use cgo) during the
     10 // bootstrap process.
     11 
     12 package main
     13 
     14 import (
     15 	"encoding/xml"
     16 	"fmt"
     17 	"io"
     18 	"strings"
     19 )
     20 
     21 // charsetReader returns a reader for the given charset. Currently
     22 // it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful
     23 // error which is printed by go get, so the user can find why the package
     24 // wasn't downloaded if the encoding is not supported. Note that, in
     25 // order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters
     26 // greater than 0x7f are not rejected).
     27 func charsetReader(charset string, input io.Reader) (io.Reader, error) {
     28 	switch strings.ToLower(charset) {
     29 	case "ascii":
     30 		return input, nil
     31 	default:
     32 		return nil, fmt.Errorf("can't decode XML document using charset %q", charset)
     33 	}
     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 func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
     39 	d := xml.NewDecoder(r)
     40 	d.CharsetReader = charsetReader
     41 	d.Strict = false
     42 	var t xml.Token
     43 	for {
     44 		t, err = d.RawToken()
     45 		if err != nil {
     46 			if err == io.EOF || len(imports) > 0 {
     47 				err = nil
     48 			}
     49 			return
     50 		}
     51 		if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
     52 			return
     53 		}
     54 		if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
     55 			return
     56 		}
     57 		e, ok := t.(xml.StartElement)
     58 		if !ok || !strings.EqualFold(e.Name.Local, "meta") {
     59 			continue
     60 		}
     61 		if attrValue(e.Attr, "name") != "go-import" {
     62 			continue
     63 		}
     64 		if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
     65 			imports = append(imports, metaImport{
     66 				Prefix:   f[0],
     67 				VCS:      f[1],
     68 				RepoRoot: f[2],
     69 			})
     70 		}
     71 	}
     72 }
     73 
     74 // attrValue returns the attribute value for the case-insensitive key
     75 // `name', or the empty string if nothing is found.
     76 func attrValue(attrs []xml.Attr, name string) string {
     77 	for _, a := range attrs {
     78 		if strings.EqualFold(a.Name.Local, name) {
     79 			return a.Value
     80 		}
     81 	}
     82 	return ""
     83 }
     84