1
2
3
4
5
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package modcmd
import (
"context"
"fmt"
"strings"
"cmd/go/internal/base"
"cmd/go/internal/imports"
"cmd/go/internal/modload"
"golang.org/x/mod/module"
)
var cmdWhy = &base.Command{
UsageLine: "go mod why [-m] [-vendor] packages...",
Short: "explain why packages or modules are needed",
Long: `
Why shows a shortest path in the import graph from the main module to
each of the listed packages. If the -m flag is given, why treats the
arguments as a list of modules and finds a path to any package in each
of the modules.
By default, why queries the graph of packages matched by "go list all",
which includes tests for reachable packages. The -vendor flag causes why
to exclude tests of dependencies.
The output is a sequence of stanzas, one for each package or module
name on the command line, separated by blank lines. Each stanza begins
with a comment line "# package" or "# module" giving the target
package or module. Subsequent lines give a path through the import
graph, one package per line. If the package or module is not
referenced from the main module, the stanza will display a single
parenthesized note indicating that fact.
For example:
$ go mod why golang.org/x/text/language golang.org/x/text/encoding
# golang.org/x/text/language
rsc.io/quote
rsc.io/sampler
golang.org/x/text/language
# golang.org/x/text/encoding
(main module does not need package golang.org/x/text/encoding)
$
See https://golang.org/ref/mod#go-mod-why for more about 'go mod why'.
`,
}
var (
whyM = cmdWhy.Flag.Bool("m", false, "")
whyVendor = cmdWhy.Flag.Bool("vendor", false, "")
)
func init() {
cmdWhy.Run = runWhy // break init cycle
base.AddModCommonFlags(&cmdWhy.Flag)
}
func runWhy(ctx context.Context, cmd *base.Command, args []string) {
modload.ForceUseModules = true
modload.RootMode = modload.NeedRoot
loadOpts := modload.PackageOpts{
Tags: imports.AnyTags(),
LoadTests: !*whyVendor,
SilenceErrors: true,
UseVendorAll: *whyVendor,
}
if *whyM {
listU := false
listVersions := false
listRetractions := false
for _, arg := range args {
if strings.Contains(arg, "@") {
base.Fatalf("go mod why: module query not allowed")
}
}
mods := modload.ListModules(ctx, args, listU, listVersions, listRetractions)
byModule := make(map[module.Version][]string)
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all")
for _, path := range pkgs {
m := modload.PackageModule(path)
if m.Path != "" {
byModule[m] = append(byModule[m], path)
}
}
sep := ""
for _, m := range mods {
best := ""
bestDepth := 1000000000
for _, path := range byModule[module.Version{Path: m.Path, Version: m.Version}] {
d := modload.WhyDepth(path)
if d > 0 && d < bestDepth {
best = path
bestDepth = d
}
}
why := modload.Why(best)
if why == "" {
vendoring := ""
if *whyVendor {
vendoring = " to vendor"
}
why = "(main module does not need" + vendoring + " module " + m.Path + ")\n"
}
fmt.Printf("%s# %s\n%s", sep, m.Path, why)
sep = "\n"
}
} else {
// Resolve to packages.
matches, _ := modload.LoadPackages(ctx, loadOpts, args...)
modload.LoadPackages(ctx, loadOpts, "all") // rebuild graph, from main module (not from named packages)
sep := ""
for _, m := range matches {
for _, path := range m.Pkgs {
why := modload.Why(path)
if why == "" {
vendoring := ""
if *whyVendor {
vendoring = " to vendor"
}
why = "(main module does not need" + vendoring + " package " + path + ")\n"
}
fmt.Printf("%s# %s\n%s", sep, path, why)
sep = "\n"
}
}
}
}
|