/
context.go
136 lines (120 loc) · 3.14 KB
/
context.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package srcimporter
import (
"bytes"
"go/build"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
)
func NewBuildContext(source map[string]map[string]string, tags []string) *build.Context {
tags = append(tags, "js", "netgo", "purego", "jsgo")
b := &build.Context{
GOARCH: "amd64", // Target architecture
GOOS: "darwin", // Target operating system
GOROOT: "goroot", // Go root
GOPATH: "gopath", // Go path
InstallSuffix: "", // Builder only: "min" or "".
Compiler: "gc", // Compiler to assume when computing target paths
BuildTags: tags, // Build tags
CgoEnabled: false, // Builder only: detect `import "C"` to throw proper error
ReleaseTags: build.Default.ReleaseTags,
IsDir: func(path string) bool {
pkg := dir2pkg(path)
if _, ok := source[pkg]; ok {
return true
}
for p := range source {
if strings.HasPrefix(p, pkg+"/") {
return true
}
}
return false
},
HasSubdir: func(root, dir string) (rel string, ok bool) {
// copied from default implementation to prevent use of filepath.EvalSymlinks
const sep = string(filepath.Separator)
root = filepath.Clean(root)
if !strings.HasSuffix(root, sep) {
root += sep
}
dir = filepath.Clean(dir)
if !strings.HasPrefix(dir, root) {
return "", false
}
return filepath.ToSlash(dir[len(root):]), true
},
ReadDir: func(path string) ([]os.FileInfo, error) {
pkg := dir2pkg(path)
idx := len(strings.Split(pkg, "/")) // len(pkg parts) will be the index of the next part (which is the name of any subdir)
files, ok := source[pkg]
if !ok {
return nil, os.ErrNotExist
}
var fis []os.FileInfo
for p := range source {
if strings.HasPrefix(p, pkg+"/") {
fis = append(fis, file{name: strings.Split(p, "/")[idx], dir: true})
}
}
for name, contents := range files {
fis = append(fis, file{name: name, length: len(contents)})
}
return fis, nil
},
// OpenFile opens a file (not a directory) for reading.
// If OpenFile is nil, Import uses os.Open.
OpenFile: func(path string) (io.ReadCloser, error) {
dir, name := filepath.Split(path)
files, ok := source[dir2pkg(dir)]
if !ok {
return nil, os.ErrNotExist
}
contents, ok := files[name]
if !ok {
return nil, os.ErrNotExist
}
return ioutil.NopCloser(bytes.NewBuffer([]byte(contents))), nil
},
}
return b
}
func dir2pkg(dir string) string {
const sep = string(filepath.Separator)
dir = strings.TrimPrefix(dir, sep) // trim leading slash
parts := strings.Split(dir, sep) // split into parts
if len(parts) <= 2 {
return ""
}
dir = strings.Join(parts[2:], sep) // dirs[0] == "gopath", dirs[1] == "src"
return strings.Trim(filepath.ToSlash(dir), "/")
}
type file struct {
name string
length int
dir bool
}
func (f file) Name() string {
return f.name
}
func (f file) Size() int64 {
return int64(f.length)
}
func (f file) Mode() os.FileMode {
if f.dir {
return os.ModeDir
} else {
return 0
}
}
func (f file) ModTime() time.Time {
return time.Time{}
}
func (f file) IsDir() bool {
return f.dir
}
func (file) Sys() interface{} {
return nil
}