You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

76 lines
2.1 KiB

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