1
2
3
4
5
6
7 package modcmd
8
9 import (
10 "cmd/go/internal/base"
11 "cmd/go/internal/cfg"
12 "cmd/go/internal/gover"
13 "cmd/go/internal/imports"
14 "cmd/go/internal/modload"
15 "cmd/go/internal/toolchain"
16 "context"
17 "fmt"
18
19 "golang.org/x/mod/modfile"
20 )
21
22 var cmdTidy = &base.Command{
23 UsageLine: "go mod tidy [-e] [-v] [-x] [-diff] [-go=version] [-compat=version]",
24 Short: "add missing and remove unused modules",
25 Long: `
26 Tidy makes sure go.mod matches the source code in the module.
27 It adds any missing modules necessary to build the current module's
28 packages and dependencies, and it removes unused modules that
29 don't provide any relevant packages. It also adds any missing entries
30 to go.sum and removes any unnecessary ones.
31
32 The -v flag causes tidy to print information about removed modules
33 to standard error.
34
35 The -e flag causes tidy to attempt to proceed despite errors
36 encountered while loading packages.
37
38 The -diff flag causes tidy not to modify go.mod or go.sum but
39 instead print the necessary changes as a unified diff. It exits
40 with a non-zero code if the diff is not empty.
41
42 The -go flag causes tidy to update the 'go' directive in the go.mod
43 file to the given version, which may change which module dependencies
44 are retained as explicit requirements in the go.mod file.
45 (Go versions 1.17 and higher retain more requirements in order to
46 support lazy module loading.)
47
48 The -compat flag preserves any additional checksums needed for the
49 'go' command from the indicated major Go release to successfully load
50 the module graph, and causes tidy to error out if that version of the
51 'go' command would load any imported package from a different module
52 version. By default, tidy acts as if the -compat flag were set to the
53 version prior to the one indicated by the 'go' directive in the go.mod
54 file.
55
56 The -x flag causes tidy to print the commands download executes.
57
58 See https://golang.org/ref/mod#go-mod-tidy for more about 'go mod tidy'.
59 `,
60 Run: runTidy,
61 }
62
63 var (
64 tidyE bool
65 tidyDiff bool
66 tidyGo goVersionFlag
67 tidyCompat goVersionFlag
68 )
69
70 func init() {
71 cmdTidy.Flag.BoolVar(&cfg.BuildV, "v", false, "")
72 cmdTidy.Flag.BoolVar(&cfg.BuildX, "x", false, "")
73 cmdTidy.Flag.BoolVar(&tidyE, "e", false, "")
74 cmdTidy.Flag.BoolVar(&tidyDiff, "diff", false, "")
75 cmdTidy.Flag.Var(&tidyGo, "go", "")
76 cmdTidy.Flag.Var(&tidyCompat, "compat", "")
77 base.AddChdirFlag(&cmdTidy.Flag)
78 base.AddModCommonFlags(&cmdTidy.Flag)
79 }
80
81
82
83
84
85 type goVersionFlag struct {
86 v string
87 }
88
89 func (f *goVersionFlag) String() string { return f.v }
90 func (f *goVersionFlag) Get() any { return f.v }
91
92 func (f *goVersionFlag) Set(s string) error {
93 if s != "" {
94 latest := gover.Local()
95 if !modfile.GoVersionRE.MatchString(s) {
96 return fmt.Errorf("expecting a Go version like %q", latest)
97 }
98 if gover.Compare(s, latest) > 0 {
99 return fmt.Errorf("maximum supported Go version is %s", latest)
100 }
101 }
102
103 f.v = s
104 return nil
105 }
106
107 func runTidy(ctx context.Context, cmd *base.Command, args []string) {
108 moduleLoaderState := modload.NewState()
109 if len(args) > 0 {
110 base.Fatalf("go: 'go mod tidy' accepts no arguments")
111 }
112
113
114
115
116
117
118
119
120
121
122
123 moduleLoaderState.ForceUseModules = true
124 moduleLoaderState.RootMode = modload.NeedRoot
125
126 goVersion := tidyGo.String()
127 if goVersion != "" && gover.Compare(gover.Local(), goVersion) < 0 {
128 toolchain.SwitchOrFatal(moduleLoaderState, ctx, &gover.TooNewError{
129 What: "-go flag",
130 GoVersion: goVersion,
131 })
132 }
133
134 modload.LoadPackages(moduleLoaderState, ctx, modload.PackageOpts{
135 TidyGoVersion: tidyGo.String(),
136 Tags: imports.AnyTags(),
137 Tidy: true,
138 TidyDiff: tidyDiff,
139 TidyCompatibleVersion: tidyCompat.String(),
140 VendorModulesInGOROOTSrc: true,
141 ResolveMissingImports: true,
142 LoadTests: true,
143 AllowErrors: tidyE,
144 SilenceMissingStdImports: true,
145 Switcher: toolchain.NewSwitcher(moduleLoaderState),
146 }, "all")
147 }
148
View as plain text