本站源代码
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.

110 lines
3.2KB

  1. package buildutil
  2. import (
  3. "fmt"
  4. "go/build"
  5. "io"
  6. "io/ioutil"
  7. "os"
  8. "path"
  9. "path/filepath"
  10. "sort"
  11. "strings"
  12. "time"
  13. )
  14. // FakeContext returns a build.Context for the fake file tree specified
  15. // by pkgs, which maps package import paths to a mapping from file base
  16. // names to contents.
  17. //
  18. // The fake Context has a GOROOT of "/go" and no GOPATH, and overrides
  19. // the necessary file access methods to read from memory instead of the
  20. // real file system.
  21. //
  22. // Unlike a real file tree, the fake one has only two levels---packages
  23. // and files---so ReadDir("/go/src/") returns all packages under
  24. // /go/src/ including, for instance, "math" and "math/big".
  25. // ReadDir("/go/src/math/big") would return all the files in the
  26. // "math/big" package.
  27. //
  28. func FakeContext(pkgs map[string]map[string]string) *build.Context {
  29. clean := func(filename string) string {
  30. f := path.Clean(filepath.ToSlash(filename))
  31. // Removing "/go/src" while respecting segment
  32. // boundaries has this unfortunate corner case:
  33. if f == "/go/src" {
  34. return ""
  35. }
  36. return strings.TrimPrefix(f, "/go/src/")
  37. }
  38. ctxt := build.Default // copy
  39. ctxt.GOROOT = "/go"
  40. ctxt.GOPATH = ""
  41. ctxt.Compiler = "gc"
  42. ctxt.IsDir = func(dir string) bool {
  43. dir = clean(dir)
  44. if dir == "" {
  45. return true // needed by (*build.Context).SrcDirs
  46. }
  47. return pkgs[dir] != nil
  48. }
  49. ctxt.ReadDir = func(dir string) ([]os.FileInfo, error) {
  50. dir = clean(dir)
  51. var fis []os.FileInfo
  52. if dir == "" {
  53. // enumerate packages
  54. for importPath := range pkgs {
  55. fis = append(fis, fakeDirInfo(importPath))
  56. }
  57. } else {
  58. // enumerate files of package
  59. for basename := range pkgs[dir] {
  60. fis = append(fis, fakeFileInfo(basename))
  61. }
  62. }
  63. sort.Sort(byName(fis))
  64. return fis, nil
  65. }
  66. ctxt.OpenFile = func(filename string) (io.ReadCloser, error) {
  67. filename = clean(filename)
  68. dir, base := path.Split(filename)
  69. content, ok := pkgs[path.Clean(dir)][base]
  70. if !ok {
  71. return nil, fmt.Errorf("file not found: %s", filename)
  72. }
  73. return ioutil.NopCloser(strings.NewReader(content)), nil
  74. }
  75. ctxt.IsAbsPath = func(path string) bool {
  76. path = filepath.ToSlash(path)
  77. // Don't rely on the default (filepath.Path) since on
  78. // Windows, it reports virtual paths as non-absolute.
  79. return strings.HasPrefix(path, "/")
  80. }
  81. return &ctxt
  82. }
  83. type byName []os.FileInfo
  84. func (s byName) Len() int { return len(s) }
  85. func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  86. func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() }
  87. type fakeFileInfo string
  88. func (fi fakeFileInfo) Name() string { return string(fi) }
  89. func (fakeFileInfo) Sys() interface{} { return nil }
  90. func (fakeFileInfo) ModTime() time.Time { return time.Time{} }
  91. func (fakeFileInfo) IsDir() bool { return false }
  92. func (fakeFileInfo) Size() int64 { return 0 }
  93. func (fakeFileInfo) Mode() os.FileMode { return 0644 }
  94. type fakeDirInfo string
  95. func (fd fakeDirInfo) Name() string { return string(fd) }
  96. func (fakeDirInfo) Sys() interface{} { return nil }
  97. func (fakeDirInfo) ModTime() time.Time { return time.Time{} }
  98. func (fakeDirInfo) IsDir() bool { return true }
  99. func (fakeDirInfo) Size() int64 { return 0 }
  100. func (fakeDirInfo) Mode() os.FileMode { return 0755 }
上海开阖软件有限公司 沪ICP备12045867号-1