1
2
3
4
5 package modload
6
7 import (
8 "bytes"
9 "context"
10 "encoding/hex"
11 "errors"
12 "fmt"
13 "internal/goroot"
14 "os"
15 "path/filepath"
16 "strings"
17
18 "cmd/go/internal/base"
19 "cmd/go/internal/cfg"
20 "cmd/go/internal/modfetch"
21 "cmd/go/internal/modinfo"
22 "cmd/go/internal/search"
23
24 "golang.org/x/mod/module"
25 "golang.org/x/mod/semver"
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 goroot.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(pkgpath string) *modinfo.ModulePublic {
54 if isStandardImportPath(pkgpath) || !Enabled() {
55 return nil
56 }
57 m, ok := findModule(pkgpath)
58 if !ok {
59 return nil
60 }
61 fromBuildList := true
62 listRetracted := false
63 return moduleInfo(context.TODO(), m, fromBuildList, listRetracted)
64 }
65
66 func ModuleInfo(ctx context.Context, path string) *modinfo.ModulePublic {
67 if !Enabled() {
68 return nil
69 }
70
71 listRetracted := false
72 if i := strings.Index(path, "@"); i >= 0 {
73 m := module.Version{Path: path[:i], Version: path[i+1:]}
74 fromBuildList := false
75 return moduleInfo(ctx, m, fromBuildList, listRetracted)
76 }
77
78 for _, m := range buildList {
79 if m.Path == path {
80 fromBuildList := true
81 return moduleInfo(ctx, m, fromBuildList, listRetracted)
82 }
83 }
84
85 return &modinfo.ModulePublic{
86 Path: path,
87 Error: &modinfo.ModuleError{
88 Err: "module not in current build",
89 },
90 }
91 }
92
93
94 func addUpdate(ctx context.Context, m *modinfo.ModulePublic) {
95 if m.Version == "" {
96 return
97 }
98
99 if info, err := Query(ctx, m.Path, "upgrade", m.Version, CheckAllowed); err == nil && semver.Compare(info.Version, m.Version) > 0 {
100 m.Update = &modinfo.ModulePublic{
101 Path: m.Path,
102 Version: info.Version,
103 Time: &info.Time,
104 }
105 }
106 }
107
108
109
110
111 func addVersions(ctx context.Context, m *modinfo.ModulePublic, listRetracted bool) {
112 allowed := CheckAllowed
113 if listRetracted {
114 allowed = CheckExclusions
115 }
116 m.Versions, _ = versions(ctx, m.Path, allowed)
117 }
118
119
120
121 func addRetraction(ctx context.Context, m *modinfo.ModulePublic) {
122 if m.Version == "" {
123 return
124 }
125
126 err := CheckRetractions(ctx, module.Version{Path: m.Path, Version: m.Version})
127 var rerr *ModuleRetractedError
128 if errors.As(err, &rerr) {
129 if len(rerr.Rationale) == 0 {
130 m.Retracted = []string{"retracted by module author"}
131 } else {
132 m.Retracted = rerr.Rationale
133 }
134 } else if err != nil && m.Error == nil {
135 m.Error = &modinfo.ModuleError{Err: err.Error()}
136 }
137 }
138
139 func moduleInfo(ctx context.Context, m module.Version, fromBuildList, listRetracted bool) *modinfo.ModulePublic {
140 if m == Target {
141 info := &modinfo.ModulePublic{
142 Path: m.Path,
143 Version: m.Version,
144 Main: true,
145 }
146 if HasModRoot() {
147 info.Dir = ModRoot()
148 info.GoMod = ModFilePath()
149 if modFile.Go != nil {
150 info.GoVersion = modFile.Go.Version
151 }
152 }
153 return info
154 }
155
156 info := &modinfo.ModulePublic{
157 Path: m.Path,
158 Version: m.Version,
159 Indirect: fromBuildList && loaded != nil && !loaded.direct[m.Path],
160 }
161 if v, ok := rawGoVersion.Load(m); ok {
162 info.GoVersion = v.(string)
163 }
164
165
166 completeFromModCache := func(m *modinfo.ModulePublic) {
167 mod := module.Version{Path: m.Path, Version: m.Version}
168
169 if m.Version != "" {
170 if q, err := Query(ctx, m.Path, m.Version, "", nil); err != nil {
171 m.Error = &modinfo.ModuleError{Err: err.Error()}
172 } else {
173 m.Version = q.Version
174 m.Time = &q.Time
175 }
176
177 gomod, err := modfetch.CachePath(mod, "mod")
178 if err == nil {
179 if info, err := os.Stat(gomod); err == nil && info.Mode().IsRegular() {
180 m.GoMod = gomod
181 }
182 }
183 dir, err := modfetch.DownloadDir(mod)
184 if err == nil {
185 m.Dir = dir
186 }
187
188 if listRetracted {
189 addRetraction(ctx, m)
190 }
191 }
192
193 if m.GoVersion == "" {
194 if summary, err := rawGoModSummary(mod); err == nil && summary.goVersionV != "" {
195 m.GoVersion = summary.goVersionV[1:]
196 }
197 }
198 }
199
200 if !fromBuildList {
201
202
203 completeFromModCache(info)
204 return info
205 }
206
207 r := Replacement(m)
208 if r.Path == "" {
209 if cfg.BuildMod == "vendor" {
210
211
212
213
214
215 } else {
216 completeFromModCache(info)
217 }
218 return info
219 }
220
221
222
223
224
225 info.Replace = &modinfo.ModulePublic{
226 Path: r.Path,
227 Version: r.Version,
228 }
229 if v, ok := rawGoVersion.Load(m); ok {
230 info.Replace.GoVersion = v.(string)
231 }
232 if r.Version == "" {
233 if filepath.IsAbs(r.Path) {
234 info.Replace.Dir = r.Path
235 } else {
236 info.Replace.Dir = filepath.Join(ModRoot(), r.Path)
237 }
238 info.Replace.GoMod = filepath.Join(info.Replace.Dir, "go.mod")
239 }
240 if cfg.BuildMod != "vendor" {
241 completeFromModCache(info.Replace)
242 info.Dir = info.Replace.Dir
243 info.GoMod = info.Replace.GoMod
244 info.Retracted = info.Replace.Retracted
245 }
246 info.GoVersion = info.Replace.GoVersion
247 return info
248 }
249
250
251
252
253 func PackageBuildInfo(path string, deps []string) string {
254 if isStandardImportPath(path) || !Enabled() {
255 return ""
256 }
257
258 target := mustFindModule(path, path)
259 mdeps := make(map[module.Version]bool)
260 for _, dep := range deps {
261 if !isStandardImportPath(dep) {
262 mdeps[mustFindModule(path, dep)] = true
263 }
264 }
265 var mods []module.Version
266 delete(mdeps, target)
267 for mod := range mdeps {
268 mods = append(mods, mod)
269 }
270 module.Sort(mods)
271
272 var buf bytes.Buffer
273 fmt.Fprintf(&buf, "path\t%s\n", path)
274
275 writeEntry := func(token string, m module.Version) {
276 mv := m.Version
277 if mv == "" {
278 mv = "(devel)"
279 }
280 fmt.Fprintf(&buf, "%s\t%s\t%s", token, m.Path, mv)
281 if r := Replacement(m); r.Path == "" {
282 fmt.Fprintf(&buf, "\t%s\n", modfetch.Sum(m))
283 } else {
284 fmt.Fprintf(&buf, "\n=>\t%s\t%s\t%s\n", r.Path, r.Version, modfetch.Sum(r))
285 }
286 }
287
288 writeEntry("mod", target)
289 for _, mod := range mods {
290 writeEntry("dep", mod)
291 }
292
293 return buf.String()
294 }
295
296
297
298
299
300
301 func mustFindModule(target, path string) module.Version {
302 pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
303 if ok {
304 if pkg.err != nil {
305 base.Fatalf("build %v: cannot load %v: %v", target, path, pkg.err)
306 }
307 return pkg.mod
308 }
309
310 if path == "command-line-arguments" {
311 return Target
312 }
313
314 base.Fatalf("build %v: cannot find module for path %v", target, path)
315 panic("unreachable")
316 }
317
318
319
320
321 func findModule(path string) (module.Version, bool) {
322 if pkg, ok := loaded.pkgCache.Get(path).(*loadPkg); ok {
323 return pkg.mod, pkg.mod != module.Version{}
324 }
325 if path == "command-line-arguments" {
326 return Target, true
327 }
328 return module.Version{}, false
329 }
330
331 func ModInfoProg(info string, isgccgo bool) []byte {
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347 if !isgccgo {
348 return []byte(fmt.Sprintf(`package main
349 import _ "unsafe"
350 //go:linkname __debug_modinfo__ runtime.modinfo
351 var __debug_modinfo__ = %q
352 `, string(infoStart)+info+string(infoEnd)))
353 } else {
354 return []byte(fmt.Sprintf(`package main
355 import _ "unsafe"
356 //go:linkname __set_debug_modinfo__ runtime.setmodinfo
357 func __set_debug_modinfo__(string)
358 func init() { __set_debug_modinfo__(%q) }
359 `, string(infoStart)+info+string(infoEnd)))
360 }
361 }
362
View as plain text