1
2
3
4
5 package modload
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 import (
96 "bytes"
97 "context"
98 "errors"
99 "fmt"
100 "go/build"
101 "io/fs"
102 "os"
103 "path"
104 pathpkg "path"
105 "path/filepath"
106 "reflect"
107 "runtime"
108 "sort"
109 "strings"
110 "sync"
111 "sync/atomic"
112
113 "cmd/go/internal/base"
114 "cmd/go/internal/cfg"
115 "cmd/go/internal/fsys"
116 "cmd/go/internal/imports"
117 "cmd/go/internal/modfetch"
118 "cmd/go/internal/mvs"
119 "cmd/go/internal/par"
120 "cmd/go/internal/search"
121 "cmd/go/internal/str"
122
123 "golang.org/x/mod/module"
124 )
125
126
127
128 var loaded *loader
129
130
131 type PackageOpts struct {
132
133
134
135 Tags map[string]bool
136
137
138
139
140
141
142 ResolveMissingImports bool
143
144
145
146
147
148
149
150
151 AllowPackage func(ctx context.Context, path string, mod module.Version) error
152
153
154
155
156 LoadTests bool
157
158
159
160
161
162
163 UseVendorAll bool
164
165
166
167 AllowErrors bool
168
169
170
171 SilenceErrors bool
172
173
174
175 SilenceUnmatchedWarnings bool
176 }
177
178
179
180 func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (matches []*search.Match, loadedPackages []string) {
181 LoadModFile(ctx)
182 if opts.Tags == nil {
183 opts.Tags = imports.Tags()
184 }
185
186 patterns = search.CleanPatterns(patterns)
187 matches = make([]*search.Match, 0, len(patterns))
188 allPatternIsRoot := false
189 for _, pattern := range patterns {
190 matches = append(matches, search.NewMatch(pattern))
191 if pattern == "all" {
192 allPatternIsRoot = true
193 }
194 }
195
196 updateMatches := func(ld *loader) {
197 for _, m := range matches {
198 switch {
199 case m.IsLocal():
200
201 if m.Dirs == nil {
202 matchLocalDirs(m)
203 }
204
205
206
207
208
209
210
211 m.Pkgs = m.Pkgs[:0]
212 for _, dir := range m.Dirs {
213 pkg, err := resolveLocalPackage(dir)
214 if err != nil {
215 if !m.IsLiteral() && (err == errPkgIsBuiltin || err == errPkgIsGorootSrc) {
216 continue
217 }
218
219
220
221 ModRoot()
222
223 if ld != nil {
224 m.AddError(err)
225 }
226 continue
227 }
228 m.Pkgs = append(m.Pkgs, pkg)
229 }
230
231 case m.IsLiteral():
232 m.Pkgs = []string{m.Pattern()}
233
234 case strings.Contains(m.Pattern(), "..."):
235 m.Errs = m.Errs[:0]
236 matchPackages(ctx, m, opts.Tags, includeStd, buildList)
237
238 case m.Pattern() == "all":
239 if ld == nil {
240
241
242 m.Errs = m.Errs[:0]
243 matchPackages(ctx, m, opts.Tags, omitStd, []module.Version{Target})
244 } else {
245
246
247 m.Pkgs = ld.computePatternAll()
248 }
249
250 case m.Pattern() == "std" || m.Pattern() == "cmd":
251 if m.Pkgs == nil {
252 m.MatchPackages()
253 }
254
255 default:
256 panic(fmt.Sprintf("internal error: modload missing case for pattern %s", m.Pattern()))
257 }
258 }
259 }
260
261 loaded = loadFromRoots(loaderParams{
262 PackageOpts: opts,
263
264 allClosesOverTests: index.allPatternClosesOverTests() && !opts.UseVendorAll,
265 allPatternIsRoot: allPatternIsRoot,
266
267 listRoots: func() (roots []string) {
268 updateMatches(nil)
269 for _, m := range matches {
270 roots = append(roots, m.Pkgs...)
271 }
272 return roots
273 },
274 })
275
276
277 updateMatches(loaded)
278
279
280 checkMultiplePaths()
281 for _, pkg := range loaded.pkgs {
282 if pkg.err != nil {
283 if sumErr := (*ImportMissingSumError)(nil); errors.As(pkg.err, &sumErr) {
284 if importer := pkg.stack; importer != nil {
285 sumErr.importer = importer.path
286 sumErr.importerVersion = importer.mod.Version
287 sumErr.importerIsTest = importer.testOf != nil
288 }
289 }
290
291 if !opts.SilenceErrors {
292 if opts.AllowErrors {
293 fmt.Fprintf(os.Stderr, "%s: %v\n", pkg.stackText(), pkg.err)
294 } else {
295 base.Errorf("%s: %v", pkg.stackText(), pkg.err)
296 }
297 }
298 }
299 if !pkg.isTest() {
300 loadedPackages = append(loadedPackages, pkg.path)
301 }
302 }
303 if !opts.SilenceErrors {
304
305
306 for _, match := range matches {
307 for _, err := range match.Errs {
308 if opts.AllowErrors {
309 fmt.Fprintf(os.Stderr, "%v\n", err)
310 } else {
311 base.Errorf("%v", err)
312 }
313 }
314 }
315 }
316 base.ExitIfErrors()
317
318 if !opts.SilenceUnmatchedWarnings {
319 search.WarnUnmatched(matches)
320 }
321
322
323 WriteGoMod()
324 sort.Strings(loadedPackages)
325 return matches, loadedPackages
326 }
327
328
329
330 func matchLocalDirs(m *search.Match) {
331 if !m.IsLocal() {
332 panic(fmt.Sprintf("internal error: resolveLocalDirs on non-local pattern %s", m.Pattern()))
333 }
334
335 if i := strings.Index(m.Pattern(), "..."); i >= 0 {
336
337
338
339
340
341 dir := filepath.Dir(filepath.Clean(m.Pattern()[:i+3]))
342 absDir := dir
343 if !filepath.IsAbs(dir) {
344 absDir = filepath.Join(base.Cwd, dir)
345 }
346 if search.InDir(absDir, cfg.GOROOTsrc) == "" && search.InDir(absDir, ModRoot()) == "" && pathInModuleCache(absDir) == "" {
347 m.Dirs = []string{}
348 m.AddError(fmt.Errorf("directory prefix %s outside available modules", base.ShortPath(absDir)))
349 return
350 }
351 }
352
353 m.MatchDirs()
354 }
355
356
357 func resolveLocalPackage(dir string) (string, error) {
358 var absDir string
359 if filepath.IsAbs(dir) {
360 absDir = filepath.Clean(dir)
361 } else {
362 absDir = filepath.Join(base.Cwd, dir)
363 }
364
365 bp, err := cfg.BuildContext.ImportDir(absDir, 0)
366 if err != nil && (bp == nil || len(bp.IgnoredGoFiles) == 0) {
367
368
369
370
371
372
373
374 if _, err := fsys.Stat(absDir); err != nil {
375 if os.IsNotExist(err) {
376
377
378 return "", &fs.PathError{Op: "stat", Path: absDir, Err: errDirectoryNotFound}
379 }
380 return "", err
381 }
382 if _, noGo := err.(*build.NoGoError); noGo {
383
384
385
386
387
388
389
390
391 return "", err
392 }
393 }
394
395 if modRoot != "" && absDir == modRoot {
396 if absDir == cfg.GOROOTsrc {
397 return "", errPkgIsGorootSrc
398 }
399 return targetPrefix, nil
400 }
401
402
403
404
405 if modRoot != "" && strings.HasPrefix(absDir, modRoot+string(filepath.Separator)) && !strings.Contains(absDir[len(modRoot):], "@") {
406 suffix := filepath.ToSlash(absDir[len(modRoot):])
407 if strings.HasPrefix(suffix, "/vendor/") {
408 if cfg.BuildMod != "vendor" {
409 return "", fmt.Errorf("without -mod=vendor, directory %s has no package path", absDir)
410 }
411
412 readVendorList()
413 pkg := strings.TrimPrefix(suffix, "/vendor/")
414 if _, ok := vendorPkgModule[pkg]; !ok {
415 return "", fmt.Errorf("directory %s is not a package listed in vendor/modules.txt", absDir)
416 }
417 return pkg, nil
418 }
419
420 if targetPrefix == "" {
421 pkg := strings.TrimPrefix(suffix, "/")
422 if pkg == "builtin" {
423
424
425
426 return "", errPkgIsBuiltin
427 }
428 return pkg, nil
429 }
430
431 pkg := targetPrefix + suffix
432 if _, ok, err := dirInModule(pkg, targetPrefix, modRoot, true); err != nil {
433 return "", err
434 } else if !ok {
435 return "", &PackageNotInModuleError{Mod: Target, Pattern: pkg}
436 }
437 return pkg, nil
438 }
439
440 if sub := search.InDir(absDir, cfg.GOROOTsrc); sub != "" && sub != "." && !strings.Contains(sub, "@") {
441 pkg := filepath.ToSlash(sub)
442 if pkg == "builtin" {
443 return "", errPkgIsBuiltin
444 }
445 return pkg, nil
446 }
447
448 pkg := pathInModuleCache(absDir)
449 if pkg == "" {
450 return "", fmt.Errorf("directory %s outside available modules", base.ShortPath(absDir))
451 }
452 return pkg, nil
453 }
454
455 var (
456 errDirectoryNotFound = errors.New("directory not found")
457 errPkgIsGorootSrc = errors.New("GOROOT/src is not an importable package")
458 errPkgIsBuiltin = errors.New(`"builtin" is a pseudo-package, not an importable package`)
459 )
460
461
462
463 func pathInModuleCache(dir string) string {
464 tryMod := func(m module.Version) (string, bool) {
465 var root string
466 var err error
467 if repl := Replacement(m); repl.Path != "" && repl.Version == "" {
468 root = repl.Path
469 if !filepath.IsAbs(root) {
470 root = filepath.Join(ModRoot(), root)
471 }
472 } else if repl.Path != "" {
473 root, err = modfetch.DownloadDir(repl)
474 } else {
475 root, err = modfetch.DownloadDir(m)
476 }
477 if err != nil {
478 return "", false
479 }
480
481 sub := search.InDir(dir, root)
482 if sub == "" {
483 return "", false
484 }
485 sub = filepath.ToSlash(sub)
486 if strings.Contains(sub, "/vendor/") || strings.HasPrefix(sub, "vendor/") || strings.Contains(sub, "@") {
487 return "", false
488 }
489
490 return path.Join(m.Path, filepath.ToSlash(sub)), true
491 }
492
493 for _, m := range buildList[1:] {
494 if importPath, ok := tryMod(m); ok {
495
496
497 return importPath
498 }
499 }
500 return ""
501 }
502
503
504
505 func ImportFromFiles(ctx context.Context, gofiles []string) {
506 LoadModFile(ctx)
507
508 tags := imports.Tags()
509 imports, testImports, err := imports.ScanFiles(gofiles, tags)
510 if err != nil {
511 base.Fatalf("go: %v", err)
512 }
513
514 loaded = loadFromRoots(loaderParams{
515 PackageOpts: PackageOpts{
516 Tags: tags,
517 ResolveMissingImports: true,
518 },
519 allClosesOverTests: index.allPatternClosesOverTests(),
520 listRoots: func() (roots []string) {
521 roots = append(roots, imports...)
522 roots = append(roots, testImports...)
523 return roots
524 },
525 })
526 WriteGoMod()
527 }
528
529
530
531 func DirImportPath(dir string) string {
532 if !HasModRoot() {
533 return "."
534 }
535 LoadModFile(context.TODO())
536
537 if !filepath.IsAbs(dir) {
538 dir = filepath.Join(base.Cwd, dir)
539 } else {
540 dir = filepath.Clean(dir)
541 }
542
543 if dir == modRoot {
544 return targetPrefix
545 }
546 if strings.HasPrefix(dir, modRoot+string(filepath.Separator)) {
547 suffix := filepath.ToSlash(dir[len(modRoot):])
548 if strings.HasPrefix(suffix, "/vendor/") {
549 return strings.TrimPrefix(suffix, "/vendor/")
550 }
551 return targetPrefix + suffix
552 }
553 return "."
554 }
555
556
557
558
559 func TargetPackages(ctx context.Context, pattern string) *search.Match {
560
561
562 LoadModFile(ctx)
563 ModRoot()
564
565 m := search.NewMatch(pattern)
566 matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{Target})
567 return m
568 }
569
570
571
572
573
574 func ImportMap(path string) string {
575 pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
576 if !ok {
577 return ""
578 }
579 return pkg.path
580 }
581
582
583
584 func PackageDir(path string) string {
585 pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
586 if !ok {
587 return ""
588 }
589 return pkg.dir
590 }
591
592
593 func PackageModule(path string) module.Version {
594 pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
595 if !ok {
596 return module.Version{}
597 }
598 return pkg.mod
599 }
600
601
602
603
604
605
606 func PackageImports(path string) (imports, testImports []string) {
607 pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
608 if !ok {
609 return nil, nil
610 }
611 imports = make([]string, len(pkg.imports))
612 for i, p := range pkg.imports {
613 imports[i] = p.path
614 }
615 if pkg.test != nil {
616 testImports = make([]string, len(pkg.test.imports))
617 for i, p := range pkg.test.imports {
618 testImports[i] = p.path
619 }
620 }
621 return imports, testImports
622 }
623
624
625
626
627
628 func Lookup(parentPath string, parentIsStd bool, path string) (dir, realPath string, err error) {
629 if path == "" {
630 panic("Lookup called with empty package path")
631 }
632
633 if parentIsStd {
634 path = loaded.stdVendor(parentPath, path)
635 }
636 pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
637 if !ok {
638
639
640
641
642
643
644
645
646 dir := findStandardImportPath(path)
647 if dir != "" {
648 return dir, path, nil
649 }
650 return "", "", errMissing
651 }
652 return pkg.dir, pkg.path, pkg.err
653 }
654
655
656
657
658
659 type loader struct {
660 loaderParams
661
662 work *par.Queue
663
664
665 roots []*loadPkg
666 pkgCache *par.Cache
667 pkgs []*loadPkg
668
669
670 direct map[string]bool
671 }
672
673
674
675 type loaderParams struct {
676 PackageOpts
677
678 allClosesOverTests bool
679 allPatternIsRoot bool
680
681 listRoots func() []string
682 }
683
684 func (ld *loader) reset() {
685 select {
686 case <-ld.work.Idle():
687 default:
688 panic("loader.reset when not idle")
689 }
690
691 ld.roots = nil
692 ld.pkgCache = new(par.Cache)
693 ld.pkgs = nil
694 }
695
696
697 type loadPkg struct {
698
699 path string
700 testOf *loadPkg
701
702
703 flags atomicLoadPkgFlags
704
705
706 mod module.Version
707 dir string
708 err error
709 imports []*loadPkg
710 testImports []string
711 inStd bool
712
713
714 testOnce sync.Once
715 test *loadPkg
716
717
718 stack *loadPkg
719 }
720
721
722 type loadPkgFlags int8
723
724 const (
725
726
727
728
729
730
731
732
733
734
735 pkgInAll loadPkgFlags = 1 << iota
736
737
738
739
740
741
742
743
744
745
746 pkgIsRoot
747
748
749
750 pkgImportsLoaded
751 )
752
753
754 func (f loadPkgFlags) has(cond loadPkgFlags) bool {
755 return f&cond == cond
756 }
757
758
759
760 type atomicLoadPkgFlags struct {
761 bits int32
762 }
763
764
765
766
767
768 func (af *atomicLoadPkgFlags) update(flags loadPkgFlags) (old loadPkgFlags) {
769 for {
770 old := atomic.LoadInt32(&af.bits)
771 new := old | int32(flags)
772 if new == old || atomic.CompareAndSwapInt32(&af.bits, old, new) {
773 return loadPkgFlags(old)
774 }
775 }
776 }
777
778
779 func (af *atomicLoadPkgFlags) has(cond loadPkgFlags) bool {
780 return loadPkgFlags(atomic.LoadInt32(&af.bits))&cond == cond
781 }
782
783
784 func (pkg *loadPkg) isTest() bool {
785 return pkg.testOf != nil
786 }
787
788 var errMissing = errors.New("cannot find package")
789
790
791
792
793
794
795
796 func loadFromRoots(params loaderParams) *loader {
797 ld := &loader{
798 loaderParams: params,
799 work: par.NewQueue(runtime.GOMAXPROCS(0)),
800 }
801
802 var err error
803 reqs := &mvsReqs{buildList: buildList}
804 buildList, err = mvs.BuildList(Target, reqs)
805 if err != nil {
806 base.Fatalf("go: %v", err)
807 }
808
809 addedModuleFor := make(map[string]bool)
810 for {
811 ld.reset()
812
813
814
815
816
817 inRoots := map[*loadPkg]bool{}
818 for _, path := range ld.listRoots() {
819 root := ld.pkg(path, pkgIsRoot)
820 if !inRoots[root] {
821 ld.roots = append(ld.roots, root)
822 inRoots[root] = true
823 }
824 }
825
826
827
828
829
830
831 <-ld.work.Idle()
832
833 ld.buildStacks()
834
835 if !ld.ResolveMissingImports || (!HasModRoot() && !allowMissingModuleImports) {
836
837 break
838 }
839 modAddedBy := ld.resolveMissingImports(addedModuleFor)
840 if len(modAddedBy) == 0 {
841 break
842 }
843
844
845 reqs = &mvsReqs{buildList: buildList}
846 buildList, err = mvs.BuildList(Target, reqs)
847 if err != nil {
848
849
850
851 if err, ok := err.(*mvs.BuildListError); ok {
852 if pkg := modAddedBy[err.Module()]; pkg != nil {
853 base.Fatalf("go: %s: %v", pkg.stackText(), err.Err)
854 }
855 }
856 base.Fatalf("go: %v", err)
857 }
858 }
859 base.ExitIfErrors()
860
861
862 ld.direct = make(map[string]bool)
863 for _, pkg := range ld.pkgs {
864 if pkg.mod == Target {
865 for _, dep := range pkg.imports {
866 if dep.mod.Path != "" && dep.mod.Path != Target.Path && index != nil {
867 _, explicit := index.require[dep.mod]
868 if allowWriteGoMod && cfg.BuildMod == "readonly" && !explicit {
869
870
871
872
873 base.Errorf("go: %[1]s: package %[2]s imported from implicitly required module; to add missing requirements, run:\n\tgo get %[2]s@%[3]s", pkg.path, dep.path, dep.mod.Version)
874 }
875 ld.direct[dep.mod.Path] = true
876 }
877 }
878 }
879 }
880 base.ExitIfErrors()
881
882
883
884
885
886
887 if modFile != nil && (!ld.allPatternIsRoot || !reflect.DeepEqual(ld.Tags, imports.AnyTags())) {
888 for _, r := range modFile.Require {
889 if !r.Indirect {
890 ld.direct[r.Mod.Path] = true
891 }
892 }
893 }
894
895 return ld
896 }
897
898
899
900
901
902
903
904 func (ld *loader) resolveMissingImports(addedModuleFor map[string]bool) (modAddedBy map[module.Version]*loadPkg) {
905 var needPkgs []*loadPkg
906 for _, pkg := range ld.pkgs {
907 if pkg.err == nil {
908 continue
909 }
910 if pkg.isTest() {
911
912
913 continue
914 }
915 if !errors.As(pkg.err, new(*ImportMissingError)) {
916
917 continue
918 }
919
920 needPkgs = append(needPkgs, pkg)
921
922 pkg := pkg
923 ld.work.Add(func() {
924 pkg.mod, pkg.err = queryImport(context.TODO(), pkg.path)
925 })
926 }
927 <-ld.work.Idle()
928
929 modAddedBy = map[module.Version]*loadPkg{}
930 for _, pkg := range needPkgs {
931 if pkg.err != nil {
932 continue
933 }
934
935 fmt.Fprintf(os.Stderr, "go: found %s in %s %s\n", pkg.path, pkg.mod.Path, pkg.mod.Version)
936 if addedModuleFor[pkg.path] {
937
938
939 base.Fatalf("go: %s: looping trying to add package", pkg.stackText())
940 }
941 if modAddedBy[pkg.mod] == nil {
942 modAddedBy[pkg.mod] = pkg
943 buildList = append(buildList, pkg.mod)
944 }
945 }
946
947 return modAddedBy
948 }
949
950
951
952
953
954
955
956
957 func (ld *loader) pkg(path string, flags loadPkgFlags) *loadPkg {
958 if flags.has(pkgImportsLoaded) {
959 panic("internal error: (*loader).pkg called with pkgImportsLoaded flag set")
960 }
961
962 pkg := ld.pkgCache.Do(path, func() interface{} {
963 pkg := &loadPkg{
964 path: path,
965 }
966 ld.applyPkgFlags(pkg, flags)
967
968 ld.work.Add(func() { ld.load(pkg) })
969 return pkg
970 }).(*loadPkg)
971
972 ld.applyPkgFlags(pkg, flags)
973 return pkg
974 }
975
976
977
978
979 func (ld *loader) applyPkgFlags(pkg *loadPkg, flags loadPkgFlags) {
980 if flags == 0 {
981 return
982 }
983
984 if flags.has(pkgInAll) && ld.allPatternIsRoot && !pkg.isTest() {
985
986 flags |= pkgIsRoot
987 }
988
989 old := pkg.flags.update(flags)
990 new := old | flags
991 if new == old || !new.has(pkgImportsLoaded) {
992
993
994
995 return
996 }
997
998 if !pkg.isTest() {
999
1000
1001
1002 wantTest := false
1003 switch {
1004 case ld.allPatternIsRoot && pkg.mod == Target:
1005
1006
1007
1008
1009
1010 wantTest = true
1011
1012 case ld.allPatternIsRoot && ld.allClosesOverTests && new.has(pkgInAll):
1013
1014
1015
1016 wantTest = true
1017
1018 case ld.LoadTests && new.has(pkgIsRoot):
1019
1020 wantTest = true
1021 }
1022
1023 if wantTest {
1024 var testFlags loadPkgFlags
1025 if pkg.mod == Target || (ld.allClosesOverTests && new.has(pkgInAll)) {
1026
1027
1028
1029 testFlags |= pkgInAll
1030 }
1031 ld.pkgTest(pkg, testFlags)
1032 }
1033 }
1034
1035 if new.has(pkgInAll) && !old.has(pkgInAll|pkgImportsLoaded) {
1036
1037
1038 for _, dep := range pkg.imports {
1039 ld.applyPkgFlags(dep, pkgInAll)
1040 }
1041 }
1042 }
1043
1044
1045 func (ld *loader) load(pkg *loadPkg) {
1046 if strings.Contains(pkg.path, "@") {
1047
1048 return
1049 }
1050 if build.IsLocalImport(pkg.path) || filepath.IsAbs(pkg.path) {
1051
1052
1053 return
1054 }
1055
1056 if search.IsMetaPackage(pkg.path) {
1057 pkg.err = &invalidImportError{
1058 importPath: pkg.path,
1059 err: fmt.Errorf("%q is not an importable package; see 'go help packages'", pkg.path),
1060 }
1061 return
1062 }
1063
1064 pkg.mod, pkg.dir, pkg.err = importFromBuildList(context.TODO(), pkg.path, buildList)
1065 if pkg.dir == "" {
1066 return
1067 }
1068 if pkg.mod == Target {
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078 ld.applyPkgFlags(pkg, pkgInAll)
1079 }
1080 if ld.AllowPackage != nil {
1081 if err := ld.AllowPackage(context.TODO(), pkg.path, pkg.mod); err != nil {
1082 pkg.err = err
1083 }
1084 }
1085
1086 pkg.inStd = (search.IsStandardImportPath(pkg.path) && search.InDir(pkg.dir, cfg.GOROOTsrc) != "")
1087
1088 var imports, testImports []string
1089
1090 if cfg.BuildContext.Compiler == "gccgo" && pkg.inStd {
1091
1092 } else {
1093 var err error
1094 imports, testImports, err = scanDir(pkg.dir, ld.Tags)
1095 if err != nil {
1096 pkg.err = err
1097 return
1098 }
1099 }
1100
1101 pkg.imports = make([]*loadPkg, 0, len(imports))
1102 var importFlags loadPkgFlags
1103 if pkg.flags.has(pkgInAll) {
1104 importFlags = pkgInAll
1105 }
1106 for _, path := range imports {
1107 if pkg.inStd {
1108
1109
1110 path = ld.stdVendor(pkg.path, path)
1111 }
1112 pkg.imports = append(pkg.imports, ld.pkg(path, importFlags))
1113 }
1114 pkg.testImports = testImports
1115
1116 ld.applyPkgFlags(pkg, pkgImportsLoaded)
1117 }
1118
1119
1120
1121
1122
1123
1124 func (ld *loader) pkgTest(pkg *loadPkg, testFlags loadPkgFlags) *loadPkg {
1125 if pkg.isTest() {
1126 panic("pkgTest called on a test package")
1127 }
1128
1129 createdTest := false
1130 pkg.testOnce.Do(func() {
1131 pkg.test = &loadPkg{
1132 path: pkg.path,
1133 testOf: pkg,
1134 mod: pkg.mod,
1135 dir: pkg.dir,
1136 err: pkg.err,
1137 inStd: pkg.inStd,
1138 }
1139 ld.applyPkgFlags(pkg.test, testFlags)
1140 createdTest = true
1141 })
1142
1143 test := pkg.test
1144 if createdTest {
1145 test.imports = make([]*loadPkg, 0, len(pkg.testImports))
1146 var importFlags loadPkgFlags
1147 if test.flags.has(pkgInAll) {
1148 importFlags = pkgInAll
1149 }
1150 for _, path := range pkg.testImports {
1151 if pkg.inStd {
1152 path = ld.stdVendor(test.path, path)
1153 }
1154 test.imports = append(test.imports, ld.pkg(path, importFlags))
1155 }
1156 pkg.testImports = nil
1157 ld.applyPkgFlags(test, pkgImportsLoaded)
1158 } else {
1159 ld.applyPkgFlags(test, testFlags)
1160 }
1161
1162 return test
1163 }
1164
1165
1166
1167 func (ld *loader) stdVendor(parentPath, path string) string {
1168 if search.IsStandardImportPath(path) {
1169 return path
1170 }
1171
1172 if str.HasPathPrefix(parentPath, "cmd") {
1173 if Target.Path != "cmd" {
1174 vendorPath := pathpkg.Join("cmd", "vendor", path)
1175 if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil {
1176 return vendorPath
1177 }
1178 }
1179 } else if Target.Path != "std" || str.HasPathPrefix(parentPath, "vendor") {
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192 vendorPath := pathpkg.Join("vendor", path)
1193 if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil {
1194 return vendorPath
1195 }
1196 }
1197
1198
1199 return path
1200 }
1201
1202
1203
1204 func (ld *loader) computePatternAll() (all []string) {
1205 for _, pkg := range ld.pkgs {
1206 if pkg.flags.has(pkgInAll) && !pkg.isTest() {
1207 all = append(all, pkg.path)
1208 }
1209 }
1210 sort.Strings(all)
1211 return all
1212 }
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226 func scanDir(dir string, tags map[string]bool) (imports_, testImports []string, err error) {
1227 imports_, testImports, err = imports.ScanDir(dir, tags)
1228
1229 filter := func(x []string) []string {
1230 w := 0
1231 for _, pkg := range x {
1232 if pkg != "C" && pkg != "appengine" && !strings.HasPrefix(pkg, "appengine/") &&
1233 pkg != "appengine_internal" && !strings.HasPrefix(pkg, "appengine_internal/") {
1234 x[w] = pkg
1235 w++
1236 }
1237 }
1238 return x[:w]
1239 }
1240
1241 return filter(imports_), filter(testImports), err
1242 }
1243
1244
1245
1246
1247
1248
1249
1250
1251 func (ld *loader) buildStacks() {
1252 if len(ld.pkgs) > 0 {
1253 panic("buildStacks")
1254 }
1255 for _, pkg := range ld.roots {
1256 pkg.stack = pkg
1257 ld.pkgs = append(ld.pkgs, pkg)
1258 }
1259 for i := 0; i < len(ld.pkgs); i++ {
1260 pkg := ld.pkgs[i]
1261 for _, next := range pkg.imports {
1262 if next.stack == nil {
1263 next.stack = pkg
1264 ld.pkgs = append(ld.pkgs, next)
1265 }
1266 }
1267 if next := pkg.test; next != nil && next.stack == nil {
1268 next.stack = pkg
1269 ld.pkgs = append(ld.pkgs, next)
1270 }
1271 }
1272 for _, pkg := range ld.roots {
1273 pkg.stack = nil
1274 }
1275 }
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286 func (pkg *loadPkg) stackText() string {
1287 var stack []*loadPkg
1288 for p := pkg; p != nil; p = p.stack {
1289 stack = append(stack, p)
1290 }
1291
1292 var buf bytes.Buffer
1293 for i := len(stack) - 1; i >= 0; i-- {
1294 p := stack[i]
1295 fmt.Fprint(&buf, p.path)
1296 if p.testOf != nil {
1297 fmt.Fprint(&buf, ".test")
1298 }
1299 if i > 0 {
1300 if stack[i-1].testOf == p {
1301 fmt.Fprint(&buf, " tested by\n\t")
1302 } else {
1303 fmt.Fprint(&buf, " imports\n\t")
1304 }
1305 }
1306 }
1307 return buf.String()
1308 }
1309
1310
1311
1312 func (pkg *loadPkg) why() string {
1313 var buf strings.Builder
1314 var stack []*loadPkg
1315 for p := pkg; p != nil; p = p.stack {
1316 stack = append(stack, p)
1317 }
1318
1319 for i := len(stack) - 1; i >= 0; i-- {
1320 p := stack[i]
1321 if p.testOf != nil {
1322 fmt.Fprintf(&buf, "%s.test\n", p.testOf.path)
1323 } else {
1324 fmt.Fprintf(&buf, "%s\n", p.path)
1325 }
1326 }
1327 return buf.String()
1328 }
1329
1330
1331
1332
1333
1334
1335 func Why(path string) string {
1336 pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
1337 if !ok {
1338 return ""
1339 }
1340 return pkg.why()
1341 }
1342
1343
1344
1345
1346 func WhyDepth(path string) int {
1347 n := 0
1348 pkg, _ := loaded.pkgCache.Get(path).(*loadPkg)
1349 for p := pkg; p != nil; p = p.stack {
1350 n++
1351 }
1352 return n
1353 }
1354
View as plain text