discovery.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  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. //
  28. // This copy of cmd/go/internal/vcs.parseMetaGoImports always operates
  29. // in IgnoreMod ModuleMode.
  30. func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
  31. d := xml.NewDecoder(r)
  32. d.CharsetReader = charsetReader
  33. d.Strict = false
  34. var t xml.Token
  35. for {
  36. t, err = d.RawToken()
  37. if err != nil {
  38. if err == io.EOF || len(imports) > 0 {
  39. err = nil
  40. }
  41. return
  42. }
  43. if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
  44. return
  45. }
  46. if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
  47. return
  48. }
  49. e, ok := t.(xml.StartElement)
  50. if !ok || !strings.EqualFold(e.Name.Local, "meta") {
  51. continue
  52. }
  53. if attrValue(e.Attr, "name") != "go-import" {
  54. continue
  55. }
  56. if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
  57. // Ignore VCS type "mod", which is applicable only in module mode.
  58. if f[1] == "mod" {
  59. continue
  60. }
  61. imports = append(imports, metaImport{
  62. Prefix: f[0],
  63. VCS: f[1],
  64. RepoRoot: f[2],
  65. })
  66. }
  67. }
  68. }
  69. // attrValue returns the attribute value for the case-insensitive key
  70. // `name', or the empty string if nothing is found.
  71. func attrValue(attrs []xml.Attr, name string) string {
  72. for _, a := range attrs {
  73. if strings.EqualFold(a.Name.Local, name) {
  74. return a.Value
  75. }
  76. }
  77. return ""
  78. }