1
2
3
4
5 package buildutil
6
7 import (
8 "fmt"
9 "go/ast"
10 "go/build"
11 "go/parser"
12 "go/token"
13 "io"
14 "io/ioutil"
15 "os"
16 "path"
17 "path/filepath"
18 "strings"
19 )
20
21
22
23
24
25
26
27
28
29
30
31 func ParseFile(fset *token.FileSet, ctxt *build.Context, displayPath func(string) string, dir string, file string, mode parser.Mode) (*ast.File, error) {
32 if !IsAbsPath(ctxt, file) {
33 file = JoinPath(ctxt, dir, file)
34 }
35 rd, err := OpenFile(ctxt, file)
36 if err != nil {
37 return nil, err
38 }
39 defer rd.Close()
40 if displayPath != nil {
41 file = displayPath(file)
42 }
43 return parser.ParseFile(fset, file, rd, mode)
44 }
45
46
47
48
49
50
51
52
53 func ContainingPackage(ctxt *build.Context, dir, filename string) (*build.Package, error) {
54 if !IsAbsPath(ctxt, filename) {
55 filename = JoinPath(ctxt, dir, filename)
56 }
57
58
59
60
61
62
63
64
65
66 dirSlash := path.Dir(filepath.ToSlash(filename)) + "/"
67
68
69 for _, srcdir := range ctxt.SrcDirs() {
70 srcdirSlash := filepath.ToSlash(srcdir) + "/"
71 if importPath, ok := HasSubdir(ctxt, srcdirSlash, dirSlash); ok {
72 return ctxt.Import(importPath, dir, build.FindOnly)
73 }
74 }
75
76 return nil, fmt.Errorf("can't find package containing %s", filename)
77 }
78
79
80
81
82
83
84
85 func HasSubdir(ctxt *build.Context, root, dir string) (rel string, ok bool) {
86 if f := ctxt.HasSubdir; f != nil {
87 return f(root, dir)
88 }
89
90
91 if rel, ok = hasSubdir(root, dir); ok {
92 return
93 }
94
95
96
97
98 rootSym, _ := filepath.EvalSymlinks(root)
99 dirSym, _ := filepath.EvalSymlinks(dir)
100
101 if rel, ok = hasSubdir(rootSym, dir); ok {
102 return
103 }
104 if rel, ok = hasSubdir(root, dirSym); ok {
105 return
106 }
107 return hasSubdir(rootSym, dirSym)
108 }
109
110 func hasSubdir(root, dir string) (rel string, ok bool) {
111 const sep = string(filepath.Separator)
112 root = filepath.Clean(root)
113 if !strings.HasSuffix(root, sep) {
114 root += sep
115 }
116
117 dir = filepath.Clean(dir)
118 if !strings.HasPrefix(dir, root) {
119 return "", false
120 }
121
122 return filepath.ToSlash(dir[len(root):]), true
123 }
124
125
126
127 func FileExists(ctxt *build.Context, path string) bool {
128 if ctxt.OpenFile != nil {
129 r, err := ctxt.OpenFile(path)
130 if err != nil {
131 return false
132 }
133 r.Close()
134 return true
135 }
136 _, err := os.Stat(path)
137 return err == nil
138 }
139
140
141
142 func OpenFile(ctxt *build.Context, path string) (io.ReadCloser, error) {
143 if ctxt.OpenFile != nil {
144 return ctxt.OpenFile(path)
145 }
146 return os.Open(path)
147 }
148
149
150
151 func IsAbsPath(ctxt *build.Context, path string) bool {
152 if ctxt.IsAbsPath != nil {
153 return ctxt.IsAbsPath(path)
154 }
155 return filepath.IsAbs(path)
156 }
157
158
159
160 func JoinPath(ctxt *build.Context, path ...string) string {
161 if ctxt.JoinPath != nil {
162 return ctxt.JoinPath(path...)
163 }
164 return filepath.Join(path...)
165 }
166
167
168
169 func IsDir(ctxt *build.Context, path string) bool {
170 if ctxt.IsDir != nil {
171 return ctxt.IsDir(path)
172 }
173 fi, err := os.Stat(path)
174 return err == nil && fi.IsDir()
175 }
176
177
178
179 func ReadDir(ctxt *build.Context, path string) ([]os.FileInfo, error) {
180 if ctxt.ReadDir != nil {
181 return ctxt.ReadDir(path)
182 }
183 return ioutil.ReadDir(path)
184 }
185
186
187
188 func SplitPathList(ctxt *build.Context, s string) []string {
189 if ctxt.SplitPathList != nil {
190 return ctxt.SplitPathList(s)
191 }
192 return filepath.SplitList(s)
193 }
194
195
196
197 func sameFile(x, y string) bool {
198 if path.Clean(x) == path.Clean(y) {
199 return true
200 }
201 if filepath.Base(x) == filepath.Base(y) {
202 if xi, err := os.Stat(x); err == nil {
203 if yi, err := os.Stat(y); err == nil {
204 return os.SameFile(xi, yi)
205 }
206 }
207 }
208 return false
209 }
210
View as plain text