Source file
src/go/build/deps_test.go
1
2
3
4
5
6
7
8 package build
9
10 import (
11 "bytes"
12 "fmt"
13 "go/token"
14 "internal/dag"
15 "internal/testenv"
16 "io/fs"
17 "os"
18 "path/filepath"
19 "runtime"
20 "sort"
21 "strings"
22 "testing"
23 )
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 var depsRules = `
40 # No dependencies allowed for any of these packages.
41 NONE
42 < constraints, container/list, container/ring,
43 internal/cfg, internal/coverage, internal/coverage/rtcov,
44 internal/coverage/uleb128, internal/coverage/calloc,
45 internal/cpu, internal/goarch,
46 internal/goexperiment, internal/goos,
47 internal/goversion, internal/nettrace, internal/platform,
48 unicode/utf8, unicode/utf16, unicode,
49 unsafe;
50
51 # These packages depend only on internal/goarch and unsafe.
52 internal/goarch, unsafe
53 < internal/abi;
54
55 # RUNTIME is the core runtime group of packages, all of them very light-weight.
56 internal/abi, internal/cpu, internal/goarch,
57 internal/coverage/rtcov, internal/goexperiment,
58 internal/goos, unsafe
59 < internal/bytealg
60 < internal/itoa
61 < internal/unsafeheader
62 < runtime/internal/sys
63 < runtime/internal/syscall
64 < runtime/internal/atomic
65 < runtime/internal/math
66 < runtime
67 < sync/atomic
68 < internal/race
69 < sync
70 < internal/godebug
71 < internal/reflectlite
72 < errors
73 < internal/oserror, math/bits
74 < RUNTIME;
75
76 RUNTIME
77 < sort
78 < container/heap;
79
80 RUNTIME
81 < io;
82
83 RUNTIME
84 < arena;
85
86 syscall !< io;
87 reflect !< sort;
88
89 RUNTIME, unicode/utf8
90 < path;
91
92 unicode !< path;
93
94 # SYSCALL is RUNTIME plus the packages necessary for basic system calls.
95 RUNTIME, unicode/utf8, unicode/utf16
96 < internal/syscall/windows/sysdll, syscall/js
97 < syscall
98 < internal/syscall/unix, internal/syscall/windows, internal/syscall/windows/registry
99 < internal/syscall/execenv
100 < SYSCALL;
101
102 # TIME is SYSCALL plus the core packages about time, including context.
103 SYSCALL
104 < time/tzdata
105 < time
106 < context
107 < TIME;
108
109 TIME, io, path, sort
110 < io/fs;
111
112 # MATH is RUNTIME plus the basic math packages.
113 RUNTIME
114 < math
115 < MATH;
116
117 unicode !< math;
118
119 MATH
120 < math/cmplx;
121
122 MATH
123 < math/rand;
124
125 MATH
126 < runtime/metrics;
127
128 MATH, unicode/utf8
129 < strconv;
130
131 unicode !< strconv;
132
133 # STR is basic string and buffer manipulation.
134 RUNTIME, io, unicode/utf8, unicode/utf16, unicode
135 < bytes, strings
136 < bufio;
137
138 bufio, path, strconv
139 < STR;
140
141 # OS is basic OS access, including helpers (path/filepath, os/exec, etc).
142 # OS includes string routines, but those must be layered above package os.
143 # OS does not include reflection.
144 io/fs
145 < internal/testlog
146 < internal/poll
147 < internal/safefilepath
148 < os
149 < os/signal;
150
151 io/fs
152 < embed;
153
154 unicode, fmt !< net, os, os/signal;
155
156 os/signal, STR
157 < path/filepath
158 < io/ioutil;
159
160 path/filepath, internal/godebug < os/exec;
161
162 io/ioutil, os/exec, os/signal
163 < OS;
164
165 reflect !< OS;
166
167 OS
168 < golang.org/x/sys/cpu;
169
170 # FMT is OS (which includes string routines) plus reflect and fmt.
171 # It does not include package log, which should be avoided in core packages.
172 arena, strconv, unicode
173 < reflect;
174
175 os, reflect
176 < internal/fmtsort
177 < fmt;
178
179 OS, fmt
180 < FMT;
181
182 log !< FMT;
183
184 # Misc packages needing only FMT.
185 FMT
186 < html,
187 internal/dag,
188 internal/goroot,
189 internal/types/errors,
190 mime/quotedprintable,
191 net/internal/socktest,
192 net/url,
193 runtime/trace,
194 text/scanner,
195 text/tabwriter;
196
197 io, reflect
198 < internal/saferio;
199
200 # encodings
201 # core ones do not use fmt.
202 io, strconv
203 < encoding;
204
205 encoding, reflect
206 < encoding/binary
207 < encoding/base32, encoding/base64;
208
209 FMT, encoding < flag;
210
211 fmt !< encoding/base32, encoding/base64;
212
213 FMT, encoding/base32, encoding/base64, internal/saferio
214 < encoding/ascii85, encoding/csv, encoding/gob, encoding/hex,
215 encoding/json, encoding/pem, encoding/xml, mime;
216
217 # hashes
218 io
219 < hash
220 < hash/adler32, hash/crc32, hash/crc64, hash/fnv, hash/maphash;
221
222 # math/big
223 FMT, encoding/binary, math/rand
224 < math/big;
225
226 # compression
227 FMT, encoding/binary, hash/adler32, hash/crc32
228 < compress/bzip2, compress/flate, compress/lzw
229 < archive/zip, compress/gzip, compress/zlib;
230
231 # templates
232 FMT
233 < text/template/parse;
234
235 net/url, text/template/parse
236 < text/template
237 < internal/lazytemplate;
238
239 encoding/json, html, text/template
240 < html/template;
241
242 # regexp
243 FMT
244 < regexp/syntax
245 < regexp
246 < internal/lazyregexp;
247
248 # suffix array
249 encoding/binary, regexp
250 < index/suffixarray;
251
252 # executable parsing
253 FMT, encoding/binary, compress/zlib, internal/saferio
254 < runtime/debug
255 < debug/dwarf
256 < debug/elf, debug/gosym, debug/macho, debug/pe, debug/plan9obj, internal/xcoff
257 < debug/buildinfo
258 < DEBUG;
259
260 # go parser and friends.
261 FMT
262 < go/token
263 < go/scanner
264 < go/ast
265 < go/internal/typeparams
266 < go/parser;
267
268 FMT
269 < go/build/constraint, go/doc/comment;
270
271 go/build/constraint, go/doc/comment, go/parser, text/tabwriter
272 < go/printer
273 < go/format;
274
275 go/doc/comment, go/parser, internal/lazyregexp, text/template
276 < go/doc;
277
278 math/big, go/token
279 < go/constant;
280
281 container/heap, go/constant, go/parser, internal/types/errors, regexp
282 < go/types;
283
284 FMT, internal/goexperiment
285 < internal/buildcfg;
286
287 go/build/constraint, go/doc, go/parser, internal/buildcfg, internal/goroot, internal/goversion
288 < go/build;
289
290 # databases
291 FMT
292 < database/sql/internal
293 < database/sql/driver
294 < database/sql;
295
296 # images
297 FMT, compress/lzw, compress/zlib
298 < image/color
299 < image, image/color/palette
300 < image/internal/imageutil
301 < image/draw
302 < image/gif, image/jpeg, image/png;
303
304 # cgo, delayed as long as possible.
305 # If you add a dependency on CGO, you must add the package
306 # to cgoPackages in cmd/dist/test.go as well.
307 RUNTIME
308 < C
309 < runtime/cgo
310 < CGO
311 < runtime/msan, runtime/asan;
312
313 # runtime/race
314 NONE < runtime/race/internal/amd64v1;
315 NONE < runtime/race/internal/amd64v3;
316 CGO, runtime/race/internal/amd64v1, runtime/race/internal/amd64v3 < runtime/race;
317
318 # Bulk of the standard library must not use cgo.
319 # The prohibition stops at net and os/user.
320 C !< fmt, go/types, CRYPTO-MATH;
321
322 CGO, OS
323 < plugin;
324
325 CGO, FMT
326 < os/user
327 < archive/tar;
328
329 sync
330 < internal/singleflight;
331
332 os
333 < golang.org/x/net/dns/dnsmessage,
334 golang.org/x/net/lif,
335 golang.org/x/net/route;
336
337 os, runtime, strconv, sync, unsafe,
338 internal/godebug
339 < internal/intern;
340
341 internal/bytealg, internal/intern, internal/itoa, math/bits, sort, strconv
342 < net/netip;
343
344 # net is unavoidable when doing any networking,
345 # so large dependencies must be kept out.
346 # This is a long-looking list but most of these
347 # are small with few dependencies.
348 CGO,
349 golang.org/x/net/dns/dnsmessage,
350 golang.org/x/net/lif,
351 golang.org/x/net/route,
352 internal/godebug,
353 internal/nettrace,
354 internal/poll,
355 internal/singleflight,
356 internal/race,
357 net/netip,
358 os
359 < net;
360
361 fmt, unicode !< net;
362 math/rand !< net; # net uses runtime instead
363
364 # NET is net plus net-helper packages.
365 FMT, net
366 < net/textproto;
367
368 mime, net/textproto, net/url
369 < NET;
370
371 # logging - most packages should not import; http and up is allowed
372 FMT
373 < log;
374
375 log !< crypto/tls, database/sql, go/importer, testing;
376
377 FMT, log, net
378 < log/syslog;
379
380 NET, log
381 < net/mail;
382
383 NONE < crypto/internal/boring/sig, crypto/internal/boring/syso;
384 sync/atomic < crypto/internal/boring/bcache, crypto/internal/boring/fipstls;
385 crypto/internal/boring/sig, crypto/internal/boring/fipstls < crypto/tls/fipsonly;
386
387 # CRYPTO is core crypto algorithms - no cgo, fmt, net.
388 # Unfortunately, stuck with reflect via encoding/binary.
389 crypto/internal/boring/sig,
390 crypto/internal/boring/syso,
391 encoding/binary,
392 golang.org/x/sys/cpu,
393 hash, embed
394 < crypto
395 < crypto/subtle
396 < crypto/internal/alias
397 < crypto/cipher;
398
399 crypto/cipher,
400 crypto/internal/boring/bcache
401 < crypto/internal/boring
402 < crypto/boring;
403
404 crypto/internal/alias
405 < crypto/internal/randutil
406 < crypto/internal/nistec/fiat
407 < crypto/internal/nistec
408 < crypto/internal/edwards25519/field
409 < crypto/internal/edwards25519;
410
411 crypto/boring
412 < crypto/aes, crypto/des, crypto/hmac, crypto/md5, crypto/rc4,
413 crypto/sha1, crypto/sha256, crypto/sha512;
414
415 crypto/boring, crypto/internal/edwards25519/field
416 < crypto/ecdh;
417
418 crypto/aes,
419 crypto/des,
420 crypto/ecdh,
421 crypto/hmac,
422 crypto/internal/edwards25519,
423 crypto/md5,
424 crypto/rc4,
425 crypto/sha1,
426 crypto/sha256,
427 crypto/sha512
428 < CRYPTO;
429
430 CGO, fmt, net !< CRYPTO;
431
432 # CRYPTO-MATH is core bignum-based crypto - no cgo, net; fmt now ok.
433 CRYPTO, FMT, math/big
434 < crypto/internal/boring/bbig
435 < crypto/rand
436 < crypto/ed25519
437 < encoding/asn1
438 < golang.org/x/crypto/cryptobyte/asn1
439 < golang.org/x/crypto/cryptobyte
440 < crypto/internal/bigmod
441 < crypto/dsa, crypto/elliptic, crypto/rsa
442 < crypto/ecdsa
443 < CRYPTO-MATH;
444
445 CGO, net !< CRYPTO-MATH;
446
447 # TLS, Prince of Dependencies.
448 CRYPTO-MATH, NET, container/list, encoding/hex, encoding/pem
449 < golang.org/x/crypto/internal/alias
450 < golang.org/x/crypto/internal/subtle
451 < golang.org/x/crypto/chacha20
452 < golang.org/x/crypto/internal/poly1305
453 < golang.org/x/crypto/chacha20poly1305
454 < golang.org/x/crypto/hkdf
455 < crypto/x509/internal/macos
456 < crypto/x509/pkix;
457
458 crypto/internal/boring/fipstls, crypto/x509/pkix
459 < crypto/x509
460 < crypto/tls;
461
462 # crypto-aware packages
463
464 DEBUG, go/build, go/types, text/scanner, crypto/md5
465 < internal/pkgbits
466 < go/internal/gcimporter, go/internal/gccgoimporter, go/internal/srcimporter
467 < go/importer;
468
469 NET, crypto/rand, mime/quotedprintable
470 < mime/multipart;
471
472 crypto/tls
473 < net/smtp;
474
475 # HTTP, King of Dependencies.
476
477 FMT
478 < golang.org/x/net/http2/hpack
479 < net/http/internal, net/http/internal/ascii, net/http/internal/testcert;
480
481 FMT, NET, container/list, encoding/binary, log
482 < golang.org/x/text/transform
483 < golang.org/x/text/unicode/norm
484 < golang.org/x/text/unicode/bidi
485 < golang.org/x/text/secure/bidirule
486 < golang.org/x/net/idna
487 < golang.org/x/net/http/httpguts, golang.org/x/net/http/httpproxy;
488
489 NET, crypto/tls
490 < net/http/httptrace;
491
492 compress/gzip,
493 golang.org/x/net/http/httpguts,
494 golang.org/x/net/http/httpproxy,
495 golang.org/x/net/http2/hpack,
496 net/http/internal,
497 net/http/internal/ascii,
498 net/http/internal/testcert,
499 net/http/httptrace,
500 mime/multipart,
501 log
502 < net/http;
503
504 # HTTP-aware packages
505
506 encoding/json, net/http
507 < expvar;
508
509 net/http, net/http/internal/ascii
510 < net/http/cookiejar, net/http/httputil;
511
512 net/http, flag
513 < net/http/httptest;
514
515 net/http, regexp
516 < net/http/cgi
517 < net/http/fcgi;
518
519 # Profiling
520 FMT, compress/gzip, encoding/binary, text/tabwriter
521 < runtime/pprof;
522
523 OS, compress/gzip, regexp
524 < internal/profile;
525
526 html, internal/profile, net/http, runtime/pprof, runtime/trace
527 < net/http/pprof;
528
529 # RPC
530 encoding/gob, encoding/json, go/token, html/template, net/http
531 < net/rpc
532 < net/rpc/jsonrpc;
533
534 # System Information
535 internal/cpu, sync
536 < internal/sysinfo;
537
538 # Test-only
539 log
540 < testing/iotest
541 < testing/fstest;
542
543 FMT, flag, math/rand
544 < testing/quick;
545
546 FMT, DEBUG, flag, runtime/trace, internal/sysinfo, math/rand
547 < testing;
548
549 FMT, crypto/sha256, encoding/json, go/ast, go/parser, go/token,
550 internal/godebug, math/rand, encoding/hex, crypto/sha256
551 < internal/fuzz;
552
553 internal/fuzz, internal/testlog, runtime/pprof, regexp
554 < testing/internal/testdeps;
555
556 OS, flag, testing, internal/cfg, internal/platform, internal/goroot
557 < internal/testenv;
558
559 OS, encoding/base64
560 < internal/obscuretestdata;
561
562 CGO, OS, fmt
563 < internal/testpty;
564
565 NET, testing, math/rand
566 < golang.org/x/net/nettest;
567
568 syscall
569 < os/exec/internal/fdtest;
570
571 FMT, container/heap, math/rand
572 < internal/trace;
573
574 FMT
575 < internal/diff, internal/txtar;
576
577 FMT, crypto/md5, encoding/binary, regexp, sort, text/tabwriter, unsafe,
578 internal/coverage, internal/coverage/uleb128
579 < internal/coverage/cmerge,
580 internal/coverage/pods,
581 internal/coverage/slicereader,
582 internal/coverage/slicewriter;
583
584 internal/coverage/slicereader, internal/coverage/slicewriter
585 < internal/coverage/stringtab
586 < internal/coverage/decodecounter, internal/coverage/decodemeta,
587 internal/coverage/encodecounter, internal/coverage/encodemeta;
588
589 internal/coverage/cmerge
590 < internal/coverage/cformat;
591
592 runtime/debug,
593 internal/coverage/calloc,
594 internal/coverage/cformat,
595 internal/coverage/decodecounter, internal/coverage/decodemeta,
596 internal/coverage/encodecounter, internal/coverage/encodemeta,
597 internal/coverage/pods
598 < runtime/coverage;
599 `
600
601
602 func listStdPkgs(goroot string) ([]string, error) {
603
604 var pkgs []string
605
606 src := filepath.Join(goroot, "src") + string(filepath.Separator)
607 walkFn := func(path string, d fs.DirEntry, err error) error {
608 if err != nil || !d.IsDir() || path == src {
609 return nil
610 }
611
612 base := filepath.Base(path)
613 if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") || base == "testdata" {
614 return filepath.SkipDir
615 }
616
617 name := filepath.ToSlash(path[len(src):])
618 if name == "builtin" || name == "cmd" {
619 return filepath.SkipDir
620 }
621
622 pkgs = append(pkgs, strings.TrimPrefix(name, "vendor/"))
623 return nil
624 }
625 if err := filepath.WalkDir(src, walkFn); err != nil {
626 return nil, err
627 }
628 return pkgs, nil
629 }
630
631 func TestDependencies(t *testing.T) {
632 if !testenv.HasSrc() {
633
634
635 t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH)
636 }
637
638 ctxt := Default
639 all, err := listStdPkgs(ctxt.GOROOT)
640 if err != nil {
641 t.Fatal(err)
642 }
643 sort.Strings(all)
644
645 sawImport := map[string]map[string]bool{}
646 policy := depsPolicy(t)
647
648 for _, pkg := range all {
649 imports, err := findImports(pkg)
650 if err != nil {
651 t.Error(err)
652 continue
653 }
654 if sawImport[pkg] == nil {
655 sawImport[pkg] = map[string]bool{}
656 }
657 var bad []string
658 for _, imp := range imports {
659 sawImport[pkg][imp] = true
660 if !policy.HasEdge(pkg, imp) {
661 bad = append(bad, imp)
662 }
663 }
664 if bad != nil {
665 t.Errorf("unexpected dependency: %s imports %v", pkg, bad)
666 }
667 }
668 }
669
670 var buildIgnore = []byte("\n//go:build ignore")
671
672 func findImports(pkg string) ([]string, error) {
673 vpkg := pkg
674 if strings.HasPrefix(pkg, "golang.org") {
675 vpkg = "vendor/" + pkg
676 }
677 dir := filepath.Join(Default.GOROOT, "src", vpkg)
678 files, err := os.ReadDir(dir)
679 if err != nil {
680 return nil, err
681 }
682 var imports []string
683 var haveImport = map[string]bool{}
684 if pkg == "crypto/internal/boring" {
685 haveImport["C"] = true
686 }
687 fset := token.NewFileSet()
688 for _, file := range files {
689 name := file.Name()
690 if name == "slice_go14.go" || name == "slice_go18.go" {
691
692 continue
693 }
694 if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
695 continue
696 }
697 info := fileInfo{
698 name: filepath.Join(dir, name),
699 fset: fset,
700 }
701 f, err := os.Open(info.name)
702 if err != nil {
703 return nil, err
704 }
705 err = readGoInfo(f, &info)
706 f.Close()
707 if err != nil {
708 return nil, fmt.Errorf("reading %v: %v", name, err)
709 }
710 if info.parsed.Name.Name == "main" {
711 continue
712 }
713 if bytes.Contains(info.header, buildIgnore) {
714 continue
715 }
716 for _, imp := range info.imports {
717 path := imp.path
718 if !haveImport[path] {
719 haveImport[path] = true
720 imports = append(imports, path)
721 }
722 }
723 }
724 sort.Strings(imports)
725 return imports, nil
726 }
727
728
729 func depsPolicy(t *testing.T) *dag.Graph {
730 g, err := dag.Parse(depsRules)
731 if err != nil {
732 t.Fatal(err)
733 }
734 return g
735 }
736
737
738
739 func TestStdlibLowercase(t *testing.T) {
740 if !testenv.HasSrc() {
741 t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH)
742 }
743
744 ctxt := Default
745 all, err := listStdPkgs(ctxt.GOROOT)
746 if err != nil {
747 t.Fatal(err)
748 }
749
750 for _, pkgname := range all {
751 if strings.ToLower(pkgname) != pkgname {
752 t.Errorf("package %q should not use upper-case path", pkgname)
753 }
754 }
755 }
756
757
758 func TestFindImports(t *testing.T) {
759 imports, err := findImports("go/build")
760 if err != nil {
761 t.Fatal(err)
762 }
763 t.Logf("go/build imports %q", imports)
764 want := []string{"bytes", "os", "path/filepath", "strings"}
765 wantLoop:
766 for _, w := range want {
767 for _, imp := range imports {
768 if imp == w {
769 continue wantLoop
770 }
771 }
772 t.Errorf("expected to find %q in import list", w)
773 }
774 }
775
View as plain text