1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package main
16
17 import (
18 "bufio"
19 "bytes"
20 "errors"
21 "fmt"
22 "io"
23 "io/ioutil"
24 "os"
25 "path/filepath"
26 "sort"
27 "strings"
28 )
29
30 type archive struct {
31 label, importPath, packagePath, file string
32 importPathAliases []string
33 }
34
35
36
37
38
39
40 func checkImports(files []fileInfo, archives []archive, stdPackageListPath string, importPath string, recompileInternalDeps []string) (map[string]*archive, error) {
41
42 packagesTxt, err := ioutil.ReadFile(stdPackageListPath)
43 if err != nil {
44 return nil, err
45 }
46 stdPkgs := make(map[string]bool)
47 for len(packagesTxt) > 0 {
48 n := bytes.IndexByte(packagesTxt, '\n')
49 var line string
50 if n < 0 {
51 line = string(packagesTxt)
52 packagesTxt = nil
53 } else {
54 line = string(packagesTxt[:n])
55 packagesTxt = packagesTxt[n+1:]
56 }
57 line = strings.TrimSpace(line)
58 if line == "" {
59 continue
60 }
61 stdPkgs[line] = true
62 }
63
64
65 importToArchive := make(map[string]*archive)
66 importAliasToArchive := make(map[string]*archive)
67 for i := range archives {
68 arc := &archives[i]
69 importToArchive[arc.importPath] = arc
70 for _, imp := range arc.importPathAliases {
71 importAliasToArchive[imp] = arc
72 }
73 }
74
75 recompileInternalDepMap := make(map[string]struct{})
76 for _, dep := range recompileInternalDeps {
77 recompileInternalDepMap[dep] = struct{}{}
78 }
79
80 imports := make(map[string]*archive)
81 var derr depsError
82 for _, f := range files {
83 for _, imp := range f.imports {
84 path := imp.path
85 if _, ok := imports[path]; ok || path == "C" || isRelative(path) {
86
87
88 continue
89 }
90 if _, ok := recompileInternalDepMap[path]; ok {
91 return nil, fmt.Errorf("dependency cycle detected between %q and %q in file %q", importPath, path, f.filename)
92 }
93 if stdPkgs[path] {
94 imports[path] = nil
95 } else if arc := importToArchive[path]; arc != nil {
96 imports[path] = arc
97 } else if arc := importAliasToArchive[path]; arc != nil {
98 imports[path] = arc
99 } else {
100 derr.missing = append(derr.missing, missingDep{f.filename, path})
101 }
102 }
103 }
104 if len(derr.missing) > 0 {
105 return nil, derr
106 }
107 return imports, nil
108 }
109
110
111
112
113 func buildImportcfgFileForCompile(imports map[string]*archive, installSuffix, dir string) (string, error) {
114 buf := &bytes.Buffer{}
115 goroot, ok := os.LookupEnv("GOROOT")
116 if !ok {
117 return "", errors.New("GOROOT not set")
118 }
119 goroot = abs(goroot)
120
121 sortedImports := make([]string, 0, len(imports))
122 for imp := range imports {
123 sortedImports = append(sortedImports, imp)
124 }
125 sort.Strings(sortedImports)
126
127 for _, imp := range sortedImports {
128 if arc := imports[imp]; arc == nil {
129
130 path := filepath.Join(goroot, "pkg", installSuffix, filepath.FromSlash(imp))
131 fmt.Fprintf(buf, "packagefile %s=%s.a\n", imp, path)
132 } else {
133 if imp != arc.packagePath {
134 fmt.Fprintf(buf, "importmap %s=%s\n", imp, arc.packagePath)
135 }
136 fmt.Fprintf(buf, "packagefile %s=%s\n", arc.packagePath, arc.file)
137 }
138 }
139
140 f, err := ioutil.TempFile(dir, "importcfg")
141 if err != nil {
142 return "", err
143 }
144 filename := f.Name()
145 if _, err := io.Copy(f, buf); err != nil {
146 f.Close()
147 os.Remove(filename)
148 return "", err
149 }
150 if err := f.Close(); err != nil {
151 os.Remove(filename)
152 return "", err
153 }
154 return filename, nil
155 }
156
157 func buildImportcfgFileForLink(archives []archive, stdPackageListPath, installSuffix, dir string) (string, error) {
158 buf := &bytes.Buffer{}
159 goroot, ok := os.LookupEnv("GOROOT")
160 if !ok {
161 return "", errors.New("GOROOT not set")
162 }
163 prefix := abs(filepath.Join(goroot, "pkg", installSuffix))
164 stdPackageListFile, err := os.Open(stdPackageListPath)
165 if err != nil {
166 return "", err
167 }
168 defer stdPackageListFile.Close()
169 scanner := bufio.NewScanner(stdPackageListFile)
170 for scanner.Scan() {
171 line := strings.TrimSpace(scanner.Text())
172 if line == "" {
173 continue
174 }
175 fmt.Fprintf(buf, "packagefile %s=%s.a\n", line, filepath.Join(prefix, filepath.FromSlash(line)))
176 }
177 if err := scanner.Err(); err != nil {
178 return "", err
179 }
180 depsSeen := map[string]string{}
181 for _, arc := range archives {
182 if _, ok := depsSeen[arc.packagePath]; ok {
183 return "", fmt.Errorf("internal error: package %s provided multiple times. This should have been detected during analysis.", arc.packagePath)
184 }
185 depsSeen[arc.packagePath] = arc.label
186 fmt.Fprintf(buf, "packagefile %s=%s\n", arc.packagePath, arc.file)
187 }
188 f, err := ioutil.TempFile(dir, "importcfg")
189 if err != nil {
190 return "", err
191 }
192 filename := f.Name()
193 if _, err := io.Copy(f, buf); err != nil {
194 f.Close()
195 os.Remove(filename)
196 return "", err
197 }
198 if err := f.Close(); err != nil {
199 os.Remove(filename)
200 return "", err
201 }
202 return filename, nil
203 }
204
205 type depsError struct {
206 missing []missingDep
207 known []string
208 }
209
210 type missingDep struct {
211 filename, imp string
212 }
213
214 var _ error = depsError{}
215
216 func (e depsError) Error() string {
217 buf := bytes.NewBuffer(nil)
218 fmt.Fprintf(buf, "missing strict dependencies:\n")
219 for _, dep := range e.missing {
220 fmt.Fprintf(buf, "\t%s: import of %q\n", dep.filename, dep.imp)
221 }
222 if len(e.known) == 0 {
223 fmt.Fprintln(buf, "No dependencies were provided.")
224 } else {
225 fmt.Fprintln(buf, "Known dependencies are:")
226 for _, imp := range e.known {
227 fmt.Fprintf(buf, "\t%s\n", imp)
228 }
229 }
230 fmt.Fprint(buf, "Check that imports in Go sources match importpath attributes in deps.")
231 return buf.String()
232 }
233
234 func isRelative(path string) bool {
235 return strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../")
236 }
237
238 type archiveMultiFlag []archive
239
240 func (m *archiveMultiFlag) String() string {
241 if m == nil || len(*m) == 0 {
242 return ""
243 }
244 return fmt.Sprint(*m)
245 }
246
247 func (m *archiveMultiFlag) Set(v string) error {
248 parts := strings.Split(v, "=")
249 if len(parts) != 3 {
250 return fmt.Errorf("badly formed -arc flag: %s", v)
251 }
252 importPaths := strings.Split(parts[0], ":")
253 a := archive{
254 importPath: importPaths[0],
255 importPathAliases: importPaths[1:],
256 packagePath: parts[1],
257 file: abs(parts[2]),
258 }
259 *m = append(*m, a)
260 return nil
261 }
262
View as plain text