PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/third_party/gofrontend/libgo/go/go/build/deps_test.go

http://github.com/axw/llgo
Go | 520 lines | 400 code | 56 blank | 64 comment | 52 complexity | 9a4f5fd61651017886b98e7824a9100e MD5 | raw file
Possible License(s): BSD-3-Clause, MIT
  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. // This file exercises the import parser but also checks that
  5. // some low-level packages do not have new dependencies added.
  6. package build
  7. import (
  8. "bytes"
  9. "fmt"
  10. "io/ioutil"
  11. "os"
  12. "path/filepath"
  13. "runtime"
  14. "sort"
  15. "strconv"
  16. "strings"
  17. "testing"
  18. )
  19. // pkgDeps defines the expected dependencies between packages in
  20. // the Go source tree. It is a statement of policy.
  21. // Changes should not be made to this map without prior discussion.
  22. //
  23. // The map contains two kinds of entries:
  24. // 1) Lower-case keys are standard import paths and list the
  25. // allowed imports in that package.
  26. // 2) Upper-case keys define aliases for package sets, which can then
  27. // be used as dependencies by other rules.
  28. //
  29. // DO NOT CHANGE THIS DATA TO FIX BUILDS.
  30. //
  31. var pkgDeps = map[string][]string{
  32. // L0 is the lowest level, core, nearly unavoidable packages.
  33. "errors": {},
  34. "io": {"errors", "sync"},
  35. "runtime": {"unsafe"},
  36. "sync": {"runtime", "sync/atomic", "unsafe"},
  37. "sync/atomic": {"unsafe"},
  38. "unsafe": {},
  39. "L0": {
  40. "errors",
  41. "io",
  42. "runtime",
  43. "sync",
  44. "sync/atomic",
  45. "unsafe",
  46. },
  47. // L1 adds simple functions and strings processing,
  48. // but not Unicode tables.
  49. "math": {"unsafe"},
  50. "math/cmplx": {"math"},
  51. "math/rand": {"L0", "math"},
  52. "sort": {},
  53. "strconv": {"L0", "unicode/utf8", "math"},
  54. "unicode/utf16": {},
  55. "unicode/utf8": {},
  56. "L1": {
  57. "L0",
  58. "math",
  59. "math/cmplx",
  60. "math/rand",
  61. "sort",
  62. "strconv",
  63. "unicode/utf16",
  64. "unicode/utf8",
  65. },
  66. // L2 adds Unicode and strings processing.
  67. "bufio": {"L0", "unicode/utf8", "bytes"},
  68. "bytes": {"L0", "unicode", "unicode/utf8"},
  69. "path": {"L0", "unicode/utf8", "strings"},
  70. "strings": {"L0", "unicode", "unicode/utf8"},
  71. "unicode": {},
  72. "L2": {
  73. "L1",
  74. "bufio",
  75. "bytes",
  76. "path",
  77. "strings",
  78. "unicode",
  79. },
  80. // L3 adds reflection and some basic utility packages
  81. // and interface definitions, but nothing that makes
  82. // system calls.
  83. "crypto": {"L2", "hash"}, // interfaces
  84. "crypto/cipher": {"L2", "crypto/subtle"}, // interfaces
  85. "crypto/subtle": {},
  86. "encoding/base32": {"L2"},
  87. "encoding/base64": {"L2"},
  88. "encoding/binary": {"L2", "reflect"},
  89. "hash": {"L2"}, // interfaces
  90. "hash/adler32": {"L2", "hash"},
  91. "hash/crc32": {"L2", "hash"},
  92. "hash/crc64": {"L2", "hash"},
  93. "hash/fnv": {"L2", "hash"},
  94. "image": {"L2", "image/color"}, // interfaces
  95. "image/color": {"L2"}, // interfaces
  96. "image/color/palette": {"L2", "image/color"},
  97. "reflect": {"L2"},
  98. "L3": {
  99. "L2",
  100. "crypto",
  101. "crypto/cipher",
  102. "crypto/subtle",
  103. "encoding/base32",
  104. "encoding/base64",
  105. "encoding/binary",
  106. "hash",
  107. "hash/adler32",
  108. "hash/crc32",
  109. "hash/crc64",
  110. "hash/fnv",
  111. "image",
  112. "image/color",
  113. "image/color/palette",
  114. "reflect",
  115. },
  116. // End of linear dependency definitions.
  117. // Operating system access.
  118. "syscall": {"L0", "unicode/utf16"},
  119. "internal/syscall/unix": {"L0", "syscall"},
  120. "internal/syscall/windows": {"L0", "syscall"},
  121. "internal/syscall/windows/registry": {"L0", "syscall", "unicode/utf16"},
  122. "time": {"L0", "syscall", "internal/syscall/windows/registry"},
  123. "os": {"L1", "os", "syscall", "time", "internal/syscall/windows"},
  124. "path/filepath": {"L2", "os", "syscall"},
  125. "io/ioutil": {"L2", "os", "path/filepath", "time"},
  126. "os/exec": {"L2", "os", "path/filepath", "syscall"},
  127. "os/signal": {"L2", "os", "syscall"},
  128. // OS enables basic operating system functionality,
  129. // but not direct use of package syscall, nor os/signal.
  130. "OS": {
  131. "io/ioutil",
  132. "os",
  133. "os/exec",
  134. "path/filepath",
  135. "time",
  136. },
  137. // Formatted I/O: few dependencies (L1) but we must add reflect.
  138. "fmt": {"L1", "os", "reflect"},
  139. "log": {"L1", "os", "fmt", "time"},
  140. // Packages used by testing must be low-level (L2+fmt).
  141. "regexp": {"L2", "regexp/syntax"},
  142. "regexp/syntax": {"L2"},
  143. "runtime/debug": {"L2", "fmt", "io/ioutil", "os", "time"},
  144. "runtime/pprof": {"L2", "fmt", "text/tabwriter"},
  145. "runtime/trace": {"L0"},
  146. "text/tabwriter": {"L2"},
  147. "testing": {"L2", "flag", "fmt", "os", "runtime/pprof", "runtime/trace", "time"},
  148. "testing/iotest": {"L2", "log"},
  149. "testing/quick": {"L2", "flag", "fmt", "reflect"},
  150. "internal/testenv": {"L2", "os", "testing"},
  151. // L4 is defined as L3+fmt+log+time, because in general once
  152. // you're using L3 packages, use of fmt, log, or time is not a big deal.
  153. "L4": {
  154. "L3",
  155. "fmt",
  156. "log",
  157. "time",
  158. },
  159. // Go parser.
  160. "go/ast": {"L4", "OS", "go/scanner", "go/token"},
  161. "go/doc": {"L4", "go/ast", "go/token", "regexp", "text/template"},
  162. "go/parser": {"L4", "OS", "go/ast", "go/scanner", "go/token"},
  163. "go/printer": {"L4", "OS", "go/ast", "go/scanner", "go/token", "text/tabwriter"},
  164. "go/scanner": {"L4", "OS", "go/token"},
  165. "go/token": {"L4"},
  166. "GOPARSER": {
  167. "go/ast",
  168. "go/doc",
  169. "go/parser",
  170. "go/printer",
  171. "go/scanner",
  172. "go/token",
  173. },
  174. "go/format": {"L4", "GOPARSER", "internal/format"},
  175. "internal/format": {"L4", "GOPARSER"},
  176. // Go type checking.
  177. "go/constant": {"L4", "go/token", "math/big"},
  178. "go/importer": {"L4", "go/internal/gcimporter", "go/internal/gccgoimporter", "go/types"},
  179. "go/internal/gcimporter": {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"},
  180. "go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "text/scanner"},
  181. "go/types": {"L4", "GOPARSER", "container/heap", "go/constant"},
  182. // One of a kind.
  183. "archive/tar": {"L4", "OS", "syscall"},
  184. "archive/zip": {"L4", "OS", "compress/flate"},
  185. "container/heap": {"sort"},
  186. "compress/bzip2": {"L4"},
  187. "compress/flate": {"L4"},
  188. "compress/gzip": {"L4", "compress/flate"},
  189. "compress/lzw": {"L4"},
  190. "compress/zlib": {"L4", "compress/flate"},
  191. "database/sql": {"L4", "container/list", "database/sql/driver"},
  192. "database/sql/driver": {"L4", "time"},
  193. "debug/dwarf": {"L4"},
  194. "debug/elf": {"L4", "OS", "debug/dwarf"},
  195. "debug/gosym": {"L4"},
  196. "debug/macho": {"L4", "OS", "debug/dwarf"},
  197. "debug/pe": {"L4", "OS", "debug/dwarf"},
  198. "debug/plan9obj": {"L4", "OS"},
  199. "encoding": {"L4"},
  200. "encoding/ascii85": {"L4"},
  201. "encoding/asn1": {"L4", "math/big"},
  202. "encoding/csv": {"L4"},
  203. "encoding/gob": {"L4", "OS", "encoding"},
  204. "encoding/hex": {"L4"},
  205. "encoding/json": {"L4", "encoding"},
  206. "encoding/pem": {"L4"},
  207. "encoding/xml": {"L4", "encoding"},
  208. "flag": {"L4", "OS"},
  209. "go/build": {"L4", "OS", "GOPARSER"},
  210. "html": {"L4"},
  211. "image/draw": {"L4", "image/internal/imageutil"},
  212. "image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"},
  213. "image/internal/imageutil": {"L4"},
  214. "image/jpeg": {"L4", "image/internal/imageutil"},
  215. "image/png": {"L4", "compress/zlib"},
  216. "index/suffixarray": {"L4", "regexp"},
  217. "internal/singleflight": {"sync"},
  218. "internal/trace": {"L4", "OS"},
  219. "math/big": {"L4"},
  220. "mime": {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
  221. "mime/quotedprintable": {"L4"},
  222. "net/internal/socktest": {"L4", "OS", "syscall"},
  223. "net/url": {"L4"},
  224. "text/scanner": {"L4", "OS"},
  225. "text/template/parse": {"L4"},
  226. "html/template": {
  227. "L4", "OS", "encoding/json", "html", "text/template",
  228. "text/template/parse",
  229. },
  230. "text/template": {
  231. "L4", "OS", "net/url", "text/template/parse",
  232. },
  233. // Cgo.
  234. "runtime/cgo": {"L0", "C"},
  235. "CGO": {"C", "runtime/cgo"},
  236. // Fake entry to satisfy the pseudo-import "C"
  237. // that shows up in programs that use cgo.
  238. "C": {},
  239. // Race detector uses cgo.
  240. "runtime/race": {"C"},
  241. // Plan 9 alone needs io/ioutil and os.
  242. "os/user": {"L4", "CGO", "io/ioutil", "os", "syscall"},
  243. // Basic networking.
  244. // Because net must be used by any package that wants to
  245. // do networking portably, it must have a small dependency set: just L1+basic os.
  246. "net": {"L1", "CGO", "os", "syscall", "time", "internal/syscall/windows", "internal/singleflight"},
  247. // NET enables use of basic network-related packages.
  248. "NET": {
  249. "net",
  250. "mime",
  251. "net/textproto",
  252. "net/url",
  253. },
  254. // Uses of networking.
  255. "log/syslog": {"L4", "OS", "net"},
  256. "net/mail": {"L4", "NET", "OS", "mime"},
  257. "net/textproto": {"L4", "OS", "net"},
  258. // Core crypto.
  259. "crypto/aes": {"L3"},
  260. "crypto/des": {"L3"},
  261. "crypto/hmac": {"L3"},
  262. "crypto/md5": {"L3"},
  263. "crypto/rc4": {"L3"},
  264. "crypto/sha1": {"L3"},
  265. "crypto/sha256": {"L3"},
  266. "crypto/sha512": {"L3"},
  267. "CRYPTO": {
  268. "crypto/aes",
  269. "crypto/des",
  270. "crypto/hmac",
  271. "crypto/md5",
  272. "crypto/rc4",
  273. "crypto/sha1",
  274. "crypto/sha256",
  275. "crypto/sha512",
  276. },
  277. // Random byte, number generation.
  278. // This would be part of core crypto except that it imports
  279. // math/big, which imports fmt.
  280. "crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall", "internal/syscall/unix"},
  281. // Mathematical crypto: dependencies on fmt (L4) and math/big.
  282. // We could avoid some of the fmt, but math/big imports fmt anyway.
  283. "crypto/dsa": {"L4", "CRYPTO", "math/big"},
  284. "crypto/ecdsa": {"L4", "CRYPTO", "crypto/elliptic", "math/big", "encoding/asn1"},
  285. "crypto/elliptic": {"L4", "CRYPTO", "math/big"},
  286. "crypto/rsa": {"L4", "CRYPTO", "crypto/rand", "math/big"},
  287. "CRYPTO-MATH": {
  288. "CRYPTO",
  289. "crypto/dsa",
  290. "crypto/ecdsa",
  291. "crypto/elliptic",
  292. "crypto/rand",
  293. "crypto/rsa",
  294. "encoding/asn1",
  295. "math/big",
  296. },
  297. // SSL/TLS.
  298. "crypto/tls": {
  299. "L4", "CRYPTO-MATH", "CGO", "OS",
  300. "container/list", "crypto/x509", "encoding/pem", "net", "syscall",
  301. },
  302. "crypto/x509": {
  303. "L4", "CRYPTO-MATH", "OS", "CGO",
  304. "crypto/x509/pkix", "encoding/pem", "encoding/hex", "net", "syscall",
  305. },
  306. "crypto/x509/pkix": {"L4", "CRYPTO-MATH"},
  307. // Simple net+crypto-aware packages.
  308. "mime/multipart": {"L4", "OS", "mime", "crypto/rand", "net/textproto", "mime/quotedprintable"},
  309. "net/smtp": {"L4", "CRYPTO", "NET", "crypto/tls"},
  310. // HTTP, kingpin of dependencies.
  311. "net/http": {
  312. "L4", "NET", "OS",
  313. "compress/gzip", "crypto/tls", "mime/multipart", "runtime/debug",
  314. "net/http/internal",
  315. },
  316. "net/http/internal": {"L4"},
  317. // HTTP-using packages.
  318. "expvar": {"L4", "OS", "encoding/json", "net/http"},
  319. "net/http/cgi": {"L4", "NET", "OS", "crypto/tls", "net/http", "regexp"},
  320. "net/http/cookiejar": {"L4", "NET", "net/http"},
  321. "net/http/fcgi": {"L4", "NET", "OS", "net/http", "net/http/cgi"},
  322. "net/http/httptest": {"L4", "NET", "OS", "crypto/tls", "flag", "net/http"},
  323. "net/http/httputil": {"L4", "NET", "OS", "net/http", "net/http/internal"},
  324. "net/http/pprof": {"L4", "OS", "html/template", "net/http", "runtime/pprof", "runtime/trace"},
  325. "net/rpc": {"L4", "NET", "encoding/gob", "html/template", "net/http"},
  326. "net/rpc/jsonrpc": {"L4", "NET", "encoding/json", "net/rpc"},
  327. }
  328. // isMacro reports whether p is a package dependency macro
  329. // (uppercase name).
  330. func isMacro(p string) bool {
  331. return 'A' <= p[0] && p[0] <= 'Z'
  332. }
  333. func allowed(pkg string) map[string]bool {
  334. m := map[string]bool{}
  335. var allow func(string)
  336. allow = func(p string) {
  337. if m[p] {
  338. return
  339. }
  340. m[p] = true // set even for macros, to avoid loop on cycle
  341. // Upper-case names are macro-expanded.
  342. if isMacro(p) {
  343. for _, pp := range pkgDeps[p] {
  344. allow(pp)
  345. }
  346. }
  347. }
  348. for _, pp := range pkgDeps[pkg] {
  349. allow(pp)
  350. }
  351. return m
  352. }
  353. var bools = []bool{false, true}
  354. var geese = []string{"android", "darwin", "dragonfly", "freebsd", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows"}
  355. var goarches = []string{"386", "amd64", "arm", "arm64"}
  356. type osPkg struct {
  357. goos, pkg string
  358. }
  359. // allowedErrors are the operating systems and packages known to contain errors
  360. // (currently just "no Go source files")
  361. var allowedErrors = map[osPkg]bool{
  362. osPkg{"windows", "log/syslog"}: true,
  363. osPkg{"plan9", "log/syslog"}: true,
  364. }
  365. // listStdPkgs returns the same list of packages as "go list std".
  366. func listStdPkgs(goroot string) ([]string, error) {
  367. // Based on cmd/go's matchPackages function.
  368. var pkgs []string
  369. src := filepath.Join(goroot, "src") + string(filepath.Separator)
  370. walkFn := func(path string, fi os.FileInfo, err error) error {
  371. if err != nil || !fi.IsDir() || path == src {
  372. return nil
  373. }
  374. base := filepath.Base(path)
  375. if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") || base == "testdata" {
  376. return filepath.SkipDir
  377. }
  378. name := filepath.ToSlash(path[len(src):])
  379. if name == "builtin" || name == "cmd" || strings.Contains(name, ".") {
  380. return filepath.SkipDir
  381. }
  382. pkgs = append(pkgs, name)
  383. return nil
  384. }
  385. if err := filepath.Walk(src, walkFn); err != nil {
  386. return nil, err
  387. }
  388. return pkgs, nil
  389. }
  390. func TestDependencies(t *testing.T) {
  391. iOS := runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64")
  392. if runtime.GOOS == "nacl" || iOS {
  393. // Tests run in a limited file system and we do not
  394. // provide access to every source file.
  395. t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH)
  396. }
  397. ctxt := Default
  398. all, err := listStdPkgs(ctxt.GOROOT)
  399. if err != nil {
  400. t.Fatal(err)
  401. }
  402. sort.Strings(all)
  403. test := func(mustImport bool) {
  404. for _, pkg := range all {
  405. imports, err := findImports(pkg)
  406. if err != nil {
  407. t.Error(err)
  408. continue
  409. }
  410. ok := allowed(pkg)
  411. var bad []string
  412. for _, imp := range imports {
  413. if !ok[imp] {
  414. bad = append(bad, imp)
  415. }
  416. }
  417. if bad != nil {
  418. t.Errorf("unexpected dependency: %s imports %v", pkg, bad)
  419. }
  420. }
  421. }
  422. test(true)
  423. }
  424. var buildIgnore = []byte("\n// +build ignore")
  425. func findImports(pkg string) ([]string, error) {
  426. dir := filepath.Join(Default.GOROOT, "src", pkg)
  427. files, err := ioutil.ReadDir(dir)
  428. if err != nil {
  429. return nil, err
  430. }
  431. var imports []string
  432. var haveImport = map[string]bool{}
  433. for _, file := range files {
  434. name := file.Name()
  435. if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
  436. continue
  437. }
  438. f, err := os.Open(filepath.Join(dir, name))
  439. if err != nil {
  440. return nil, err
  441. }
  442. var imp []string
  443. data, err := readImports(f, false, &imp)
  444. f.Close()
  445. if err != nil {
  446. return nil, fmt.Errorf("reading %v: %v", name, err)
  447. }
  448. if bytes.Contains(data, buildIgnore) {
  449. continue
  450. }
  451. for _, quoted := range imp {
  452. path, err := strconv.Unquote(quoted)
  453. if err != nil {
  454. continue
  455. }
  456. if !haveImport[path] {
  457. haveImport[path] = true
  458. imports = append(imports, path)
  459. }
  460. }
  461. }
  462. sort.Strings(imports)
  463. return imports, nil
  464. }