1
2
3
4
5 package modcmd
6
7 import (
8 "context"
9 "encoding/json"
10 "os"
11 "runtime"
12
13 "cmd/go/internal/base"
14 "cmd/go/internal/cfg"
15 "cmd/go/internal/modfetch"
16 "cmd/go/internal/modload"
17
18 "golang.org/x/mod/module"
19 )
20
21 var cmdDownload = &base.Command{
22 UsageLine: "go mod download [-x] [-json] [modules]",
23 Short: "download modules to local cache",
24 Long: `
25 Download downloads the named modules, which can be module patterns selecting
26 dependencies of the main module or module queries of the form path@version.
27 With no arguments, download applies to all dependencies of the main module
28 (equivalent to 'go mod download all').
29
30 The go command will automatically download modules as needed during ordinary
31 execution. The "go mod download" command is useful mainly for pre-filling
32 the local cache or to compute the answers for a Go module proxy.
33
34 By default, download writes nothing to standard output. It may print progress
35 messages and errors to standard error.
36
37 The -json flag causes download to print a sequence of JSON objects
38 to standard output, describing each downloaded module (or failure),
39 corresponding to this Go struct:
40
41 type Module struct {
42 Path string // module path
43 Version string // module version
44 Error string // error loading module
45 Info string // absolute path to cached .info file
46 GoMod string // absolute path to cached .mod file
47 Zip string // absolute path to cached .zip file
48 Dir string // absolute path to cached source root directory
49 Sum string // checksum for path, version (as in go.sum)
50 GoModSum string // checksum for go.mod (as in go.sum)
51 }
52
53 The -x flag causes download to print the commands download executes.
54
55 See https://golang.org/ref/mod#go-mod-download for more about 'go mod download'.
56
57 See https://golang.org/ref/mod#version-queries for more about version queries.
58 `,
59 }
60
61 var downloadJSON = cmdDownload.Flag.Bool("json", false, "")
62
63 func init() {
64 cmdDownload.Run = runDownload
65
66
67 cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
68 base.AddModCommonFlags(&cmdDownload.Flag)
69 }
70
71 type moduleJSON struct {
72 Path string `json:",omitempty"`
73 Version string `json:",omitempty"`
74 Error string `json:",omitempty"`
75 Info string `json:",omitempty"`
76 GoMod string `json:",omitempty"`
77 Zip string `json:",omitempty"`
78 Dir string `json:",omitempty"`
79 Sum string `json:",omitempty"`
80 GoModSum string `json:",omitempty"`
81 }
82
83 func runDownload(ctx context.Context, cmd *base.Command, args []string) {
84
85 modload.ForceUseModules = true
86 if !modload.HasModRoot() && len(args) == 0 {
87 base.Fatalf("go mod download: no modules specified (see 'go help mod download')")
88 }
89 haveExplicitArgs := len(args) > 0
90 if !haveExplicitArgs {
91 args = []string{"all"}
92 }
93 if modload.HasModRoot() {
94 modload.LoadModFile(ctx)
95 targetAtUpgrade := modload.Target.Path + "@upgrade"
96 targetAtPatch := modload.Target.Path + "@patch"
97 for _, arg := range args {
98 switch arg {
99 case modload.Target.Path, targetAtUpgrade, targetAtPatch:
100 os.Stderr.WriteString("go mod download: skipping argument " + arg + " that resolves to the main module\n")
101 }
102 }
103 }
104
105 downloadModule := func(m *moduleJSON) {
106 var err error
107 m.Info, err = modfetch.InfoFile(m.Path, m.Version)
108 if err != nil {
109 m.Error = err.Error()
110 return
111 }
112 m.GoMod, err = modfetch.GoModFile(m.Path, m.Version)
113 if err != nil {
114 m.Error = err.Error()
115 return
116 }
117 m.GoModSum, err = modfetch.GoModSum(m.Path, m.Version)
118 if err != nil {
119 m.Error = err.Error()
120 return
121 }
122 mod := module.Version{Path: m.Path, Version: m.Version}
123 m.Zip, err = modfetch.DownloadZip(ctx, mod)
124 if err != nil {
125 m.Error = err.Error()
126 return
127 }
128 m.Sum = modfetch.Sum(mod)
129 m.Dir, err = modfetch.Download(ctx, mod)
130 if err != nil {
131 m.Error = err.Error()
132 return
133 }
134 }
135
136 var mods []*moduleJSON
137 type token struct{}
138 sem := make(chan token, runtime.GOMAXPROCS(0))
139 infos, infosErr := modload.ListModules(ctx, args, 0)
140 if !haveExplicitArgs {
141
142
143
144
145
146
147
148
149 modload.DisallowWriteGoMod()
150 }
151
152 for _, info := range infos {
153 if info.Replace != nil {
154 info = info.Replace
155 }
156 if info.Version == "" && info.Error == nil {
157
158
159 continue
160 }
161 m := &moduleJSON{
162 Path: info.Path,
163 Version: info.Version,
164 }
165 mods = append(mods, m)
166 if info.Error != nil {
167 m.Error = info.Error.Err
168 continue
169 }
170 sem <- token{}
171 go func() {
172 downloadModule(m)
173 <-sem
174 }()
175 }
176
177
178 for n := cap(sem); n > 0; n-- {
179 sem <- token{}
180 }
181
182 if *downloadJSON {
183 for _, m := range mods {
184 b, err := json.MarshalIndent(m, "", "\t")
185 if err != nil {
186 base.Fatalf("go mod download: %v", err)
187 }
188 os.Stdout.Write(append(b, '\n'))
189 if m.Error != "" {
190 base.SetExitStatus(1)
191 }
192 }
193 } else {
194 for _, m := range mods {
195 if m.Error != "" {
196 base.Errorf("go mod download: %v", m.Error)
197 }
198 }
199 base.ExitIfErrors()
200 }
201
202
203
204
205
206
207
208 if haveExplicitArgs {
209 modload.WriteGoMod(ctx)
210 }
211
212
213
214
215 if infosErr != nil {
216 base.Errorf("go mod download: %v", infosErr)
217 }
218 }
219
View as plain text