1
2
3
4
5 package modload
6
7 import (
8 "context"
9 "encoding/hex"
10 "errors"
11 "fmt"
12 "io/fs"
13 "os"
14 "path/filepath"
15
16 "cmd/go/internal/base"
17 "cmd/go/internal/cfg"
18 "cmd/go/internal/gover"
19 "cmd/go/internal/modfetch"
20 "cmd/go/internal/modfetch/codehost"
21 "cmd/go/internal/modindex"
22 "cmd/go/internal/modinfo"
23 "cmd/go/internal/search"
24
25 "golang.org/x/mod/module"
26 )
27
28 var (
29 infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6")
30 infoEnd, _ = hex.DecodeString("f932433186182072008242104116d8f2")
31 )
32
33 func isStandardImportPath(path string) bool {
34 return findStandardImportPath(path) != ""
35 }
36
37 func findStandardImportPath(path string) string {
38 if path == "" {
39 panic("findStandardImportPath called with empty path")
40 }
41 if search.IsStandardImportPath(path) {
42 if modindex.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
43 return filepath.Join(cfg.GOROOT, "src", path)
44 }
45 }
46 return ""
47 }
48
49
50
51
52
53 func PackageModuleInfo(ctx context.Context, pkgpath string) *modinfo.ModulePublic {
54 if isStandardImportPath(pkgpath) || !Enabled() {
55 return nil
56 }
57 m, ok := findModule(loaded, pkgpath)
58 if !ok {
59 return nil
60 }
61
62 rs := LoadModFile(ctx)
63 return moduleInfo(ctx, rs, m, 0, nil)
64 }
65
66
67
68
69
70 func PackageModRoot(ctx context.Context, pkgpath string) string {
71 if isStandardImportPath(pkgpath) || !Enabled() || cfg.BuildMod == "vendor" {
72 return ""
73 }
74 m, ok := findModule(loaded, pkgpath)
75 if !ok {
76 return ""
77 }
78 root, _, err := fetch(ctx, m)
79 if err != nil {
80 return ""
81 }
82 return root
83 }
84
85 func ModuleInfo(ctx context.Context, path string) *modinfo.ModulePublic {
86 if !Enabled() {
87 return nil
88 }
89
90 path, vers, found, err := ParsePathVersion(path)
91 if err != nil {
92 return &modinfo.ModulePublic{
93 Path: path,
94 Error: &modinfo.ModuleError{
95 Err: err.Error(),
96 },
97 }
98 }
99 if found {
100 m := module.Version{Path: path, Version: vers}
101 return moduleInfo(ctx, nil, m, 0, nil)
102 }
103
104 rs := LoadModFile(ctx)
105
106 var (
107 v string
108 ok bool
109 )
110 if rs.pruning == pruned {
111 v, ok = rs.rootSelected(path)
112 }
113 if !ok {
114 mg, err := rs.Graph(ctx)
115 if err != nil {
116 base.Fatal(err)
117 }
118 v = mg.Selected(path)
119 }
120
121 if v == "none" {
122 return &modinfo.ModulePublic{
123 Path: path,
124 Error: &modinfo.ModuleError{
125 Err: "module not in current build",
126 },
127 }
128 }
129
130 return moduleInfo(ctx, rs, module.Version{Path: path, Version: v}, 0, nil)
131 }
132
133
134 func addUpdate(ctx context.Context, m *modinfo.ModulePublic) {
135 if m.Version == "" {
136 return
137 }
138
139 info, err := Query(ctx, m.Path, "upgrade", m.Version, CheckAllowed)
140 var noVersionErr *NoMatchingVersionError
141 if errors.Is(err, ErrDisallowed) ||
142 errors.Is(err, fs.ErrNotExist) ||
143 errors.As(err, &noVersionErr) {
144
145
146
147
148
149
150
151
152
153
154
155 return
156 } else if err != nil {
157 if m.Error == nil {
158 m.Error = &modinfo.ModuleError{Err: err.Error()}
159 }
160 return
161 }
162
163 if gover.ModCompare(m.Path, info.Version, m.Version) > 0 {
164 m.Update = &modinfo.ModulePublic{
165 Path: m.Path,
166 Version: info.Version,
167 Time: &info.Time,
168 }
169 }
170 }
171
172
173
174
175
176 func mergeOrigin(m1, m2 *codehost.Origin) *codehost.Origin {
177 if m1 == nil || m2 == nil {
178 return nil
179 }
180
181 if m2.VCS != m1.VCS ||
182 m2.URL != m1.URL ||
183 m2.Subdir != m1.Subdir {
184 return nil
185 }
186
187 merged := *m1
188 if m2.Hash != "" {
189 if m1.Hash != "" && m1.Hash != m2.Hash {
190 return nil
191 }
192 merged.Hash = m2.Hash
193 }
194 if m2.TagSum != "" {
195 if m1.TagSum != "" && (m1.TagSum != m2.TagSum || m1.TagPrefix != m2.TagPrefix) {
196 return nil
197 }
198 merged.TagSum = m2.TagSum
199 merged.TagPrefix = m2.TagPrefix
200 }
201 if m2.Ref != "" {
202 if m1.Ref != "" && m1.Ref != m2.Ref {
203 return nil
204 }
205 merged.Ref = m2.Ref
206 }
207
208 switch {
209 case merged == *m1:
210 return m1
211 case merged == *m2:
212 return m2
213 default:
214
215
216 clone := merged
217 return &clone
218 }
219 }
220
221
222
223
224 func addVersions(ctx context.Context, m *modinfo.ModulePublic, listRetracted bool) {
225
226
227
228
229 allowed := CheckAllowed
230 if listRetracted {
231 allowed = CheckExclusions
232 }
233 v, origin, err := versions(ctx, m.Path, allowed)
234 if err != nil && m.Error == nil {
235 m.Error = &modinfo.ModuleError{Err: err.Error()}
236 }
237 m.Versions = v
238 m.Origin = mergeOrigin(m.Origin, origin)
239 }
240
241
242
243 func addRetraction(ctx context.Context, m *modinfo.ModulePublic) {
244 if m.Version == "" {
245 return
246 }
247
248 err := CheckRetractions(ctx, module.Version{Path: m.Path, Version: m.Version})
249 var noVersionErr *NoMatchingVersionError
250 var retractErr *ModuleRetractedError
251 if err == nil || errors.Is(err, fs.ErrNotExist) || errors.As(err, &noVersionErr) {
252
253
254
255
256
257
258
259
260 return
261 } else if errors.As(err, &retractErr) {
262 if len(retractErr.Rationale) == 0 {
263 m.Retracted = []string{"retracted by module author"}
264 } else {
265 m.Retracted = retractErr.Rationale
266 }
267 } else if m.Error == nil {
268 m.Error = &modinfo.ModuleError{Err: err.Error()}
269 }
270 }
271
272
273
274 func addDeprecation(ctx context.Context, m *modinfo.ModulePublic) {
275 deprecation, err := CheckDeprecation(ctx, module.Version{Path: m.Path, Version: m.Version})
276 var noVersionErr *NoMatchingVersionError
277 if errors.Is(err, fs.ErrNotExist) || errors.As(err, &noVersionErr) {
278
279
280
281
282
283
284
285
286 return
287 }
288 if err != nil {
289 if m.Error == nil {
290 m.Error = &modinfo.ModuleError{Err: err.Error()}
291 }
292 return
293 }
294 m.Deprecated = deprecation
295 }
296
297
298
299
300 func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode ListMode, reuse map[module.Version]*modinfo.ModulePublic) *modinfo.ModulePublic {
301 if m.Version == "" && MainModules.Contains(m.Path) {
302 info := &modinfo.ModulePublic{
303 Path: m.Path,
304 Version: m.Version,
305 Main: true,
306 }
307 if v, ok := rawGoVersion.Load(m); ok {
308 info.GoVersion = v.(string)
309 } else {
310 panic("internal error: GoVersion not set for main module")
311 }
312 if modRoot := MainModules.ModRoot(m); modRoot != "" {
313 info.Dir = modRoot
314 info.GoMod = modFilePath(modRoot)
315 }
316 return info
317 }
318
319 info := &modinfo.ModulePublic{
320 Path: m.Path,
321 Version: m.Version,
322 Indirect: rs != nil && !rs.direct[m.Path],
323 }
324 if v, ok := rawGoVersion.Load(m); ok {
325 info.GoVersion = v.(string)
326 }
327
328
329 completeFromModCache := func(m *modinfo.ModulePublic) {
330 if gover.IsToolchain(m.Path) {
331 return
332 }
333
334 checksumOk := func(suffix string) bool {
335 return rs == nil || m.Version == "" || !mustHaveSums() ||
336 modfetch.HaveSum(module.Version{Path: m.Path, Version: m.Version + suffix})
337 }
338
339 mod := module.Version{Path: m.Path, Version: m.Version}
340
341 if m.Version != "" {
342 if old := reuse[mod]; old != nil {
343 if err := checkReuse(ctx, mod, old.Origin); err == nil {
344 *m = *old
345 m.Query = ""
346 m.Dir = ""
347 return
348 }
349 }
350
351 if q, err := Query(ctx, m.Path, m.Version, "", nil); err != nil {
352 m.Error = &modinfo.ModuleError{Err: err.Error()}
353 } else {
354 m.Version = q.Version
355 m.Time = &q.Time
356 }
357 }
358
359 if m.GoVersion == "" && checksumOk("/go.mod") {
360
361
362 if summary, err := rawGoModSummary(mod); err == nil && summary.goVersion != "" {
363 m.GoVersion = summary.goVersion
364 }
365 }
366
367 if m.Version != "" {
368 if checksumOk("/go.mod") {
369 gomod, err := modfetch.CachePath(ctx, mod, "mod")
370 if err == nil {
371 if info, err := os.Stat(gomod); err == nil && info.Mode().IsRegular() {
372 m.GoMod = gomod
373 }
374 }
375 if gomodsum, ok := modfetch.RecordedSum(modkey(mod)); ok {
376 m.GoModSum = gomodsum
377 }
378 }
379 if checksumOk("") {
380 dir, err := modfetch.DownloadDir(ctx, mod)
381 if err == nil {
382 m.Dir = dir
383 }
384 if sum, ok := modfetch.RecordedSum(mod); ok {
385 m.Sum = sum
386 }
387 }
388
389 if mode&ListRetracted != 0 {
390 addRetraction(ctx, m)
391 }
392 }
393 }
394
395 if rs == nil {
396
397
398 completeFromModCache(info)
399 return info
400 }
401
402 r := Replacement(m)
403 if r.Path == "" {
404 if cfg.BuildMod == "vendor" {
405
406
407
408
409
410 } else {
411 completeFromModCache(info)
412 }
413 return info
414 }
415
416
417
418
419
420 info.Replace = &modinfo.ModulePublic{
421 Path: r.Path,
422 Version: r.Version,
423 }
424 if v, ok := rawGoVersion.Load(m); ok {
425 info.Replace.GoVersion = v.(string)
426 }
427 if r.Version == "" {
428 if filepath.IsAbs(r.Path) {
429 info.Replace.Dir = r.Path
430 } else {
431 info.Replace.Dir = filepath.Join(replaceRelativeTo(), r.Path)
432 }
433 info.Replace.GoMod = filepath.Join(info.Replace.Dir, "go.mod")
434 }
435 if cfg.BuildMod != "vendor" {
436 completeFromModCache(info.Replace)
437 info.Dir = info.Replace.Dir
438 info.GoMod = info.Replace.GoMod
439 info.Retracted = info.Replace.Retracted
440 }
441 info.GoVersion = info.Replace.GoVersion
442 return info
443 }
444
445
446
447
448 func findModule(ld *loader, path string) (module.Version, bool) {
449 if pkg, ok := ld.pkgCache.Get(path); ok {
450 return pkg.mod, pkg.mod != module.Version{}
451 }
452 return module.Version{}, false
453 }
454
455 func ModInfoProg(info string, isgccgo bool) []byte {
456
457
458
459
460
461 if isgccgo {
462 return fmt.Appendf(nil, `package main
463 import _ "unsafe"
464 //go:linkname __set_debug_modinfo__ runtime.setmodinfo
465 func __set_debug_modinfo__(string)
466 func init() { __set_debug_modinfo__(%q) }
467 `, ModInfoData(info))
468 }
469 return nil
470 }
471
472 func ModInfoData(info string) []byte {
473 return []byte(string(infoStart) + info + string(infoEnd))
474 }
475
View as plain text