...

Source file src/pkg/cmd/go/internal/get/discovery.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	package get
     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	// parseMetaGoImports returns meta imports from the HTML in r.
    30	// Parsing ends at the end of the <head> section or the beginning of the <body>.
    31	func parseMetaGoImports(r io.Reader, mod ModuleMode) (imports []metaImport, err error) {
    32		d := xml.NewDecoder(r)
    33		d.CharsetReader = charsetReader
    34		d.Strict = false
    35		var t xml.Token
    36		for {
    37			t, err = d.RawToken()
    38			if err != nil {
    39				if err == io.EOF || len(imports) > 0 {
    40					err = nil
    41				}
    42				break
    43			}
    44			if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
    45				break
    46			}
    47			if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
    48				break
    49			}
    50			e, ok := t.(xml.StartElement)
    51			if !ok || !strings.EqualFold(e.Name.Local, "meta") {
    52				continue
    53			}
    54			if attrValue(e.Attr, "name") != "go-import" {
    55				continue
    56			}
    57			if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
    58				imports = append(imports, metaImport{
    59					Prefix:   f[0],
    60					VCS:      f[1],
    61					RepoRoot: f[2],
    62				})
    63			}
    64		}
    65	
    66		// Extract mod entries if we are paying attention to them.
    67		var list []metaImport
    68		var have map[string]bool
    69		if mod == PreferMod {
    70			have = make(map[string]bool)
    71			for _, m := range imports {
    72				if m.VCS == "mod" {
    73					have[m.Prefix] = true
    74					list = append(list, m)
    75				}
    76			}
    77		}
    78	
    79		// Append non-mod entries, ignoring those superseded by a mod entry.
    80		for _, m := range imports {
    81			if m.VCS != "mod" && !have[m.Prefix] {
    82				list = append(list, m)
    83			}
    84		}
    85		return list, nil
    86	}
    87	
    88	// attrValue returns the attribute value for the case-insensitive key
    89	// `name', or the empty string if nothing is found.
    90	func attrValue(attrs []xml.Attr, name string) string {
    91		for _, a := range attrs {
    92			if strings.EqualFold(a.Name.Local, name) {
    93				return a.Value
    94			}
    95		}
    96		return ""
    97	}
    98	

View as plain text