github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/go/modload/mvs.go (about) 1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package modload 6 7 import ( 8 "context" 9 "errors" 10 "os" 11 "sort" 12 13 "github.com/go-asm/go/cmd/go/gover" 14 "github.com/go-asm/go/cmd/go/modfetch" 15 "github.com/go-asm/go/cmd/go/modfetch/codehost" 16 17 "golang.org/x/mod/module" 18 ) 19 20 // cmpVersion implements the comparison for versions in the module loader. 21 // 22 // It is consistent with gover.ModCompare except that as a special case, 23 // the version "" is considered higher than all other versions. 24 // The main module (also known as the target) has no version and must be chosen 25 // over other versions of the same module in the module dependency graph. 26 func cmpVersion(p string, v1, v2 string) int { 27 if v2 == "" { 28 if v1 == "" { 29 return 0 30 } 31 return -1 32 } 33 if v1 == "" { 34 return 1 35 } 36 return gover.ModCompare(p, v1, v2) 37 } 38 39 // mvsReqs implements mvs.Reqs for module semantic versions, 40 // with any exclusions or replacements applied internally. 41 type mvsReqs struct { 42 roots []module.Version 43 } 44 45 func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) { 46 if mod.Version == "" && MainModules.Contains(mod.Path) { 47 // Use the build list as it existed when r was constructed, not the current 48 // global build list. 49 return r.roots, nil 50 } 51 52 if mod.Version == "none" { 53 return nil, nil 54 } 55 56 summary, err := goModSummary(mod) 57 if err != nil { 58 return nil, err 59 } 60 return summary.require, nil 61 } 62 63 // Max returns the maximum of v1 and v2 according to gover.ModCompare. 64 // 65 // As a special case, the version "" is considered higher than all other 66 // versions. The main module (also known as the target) has no version and must 67 // be chosen over other versions of the same module in the module dependency 68 // graph. 69 func (*mvsReqs) Max(p, v1, v2 string) string { 70 if cmpVersion(p, v1, v2) < 0 { 71 return v2 72 } 73 return v1 74 } 75 76 // Upgrade is a no-op, here to implement mvs.Reqs. 77 // The upgrade logic for go get -u is in ../modget/get.go. 78 func (*mvsReqs) Upgrade(m module.Version) (module.Version, error) { 79 return m, nil 80 } 81 82 func versions(ctx context.Context, path string, allowed AllowedFunc) (versions []string, origin *codehost.Origin, err error) { 83 // Note: modfetch.Lookup and repo.Versions are cached, 84 // so there's no need for us to add extra caching here. 85 err = modfetch.TryProxies(func(proxy string) error { 86 repo, err := lookupRepo(ctx, proxy, path) 87 if err != nil { 88 return err 89 } 90 allVersions, err := repo.Versions(ctx, "") 91 if err != nil { 92 return err 93 } 94 allowedVersions := make([]string, 0, len(allVersions.List)) 95 for _, v := range allVersions.List { 96 if err := allowed(ctx, module.Version{Path: path, Version: v}); err == nil { 97 allowedVersions = append(allowedVersions, v) 98 } else if !errors.Is(err, ErrDisallowed) { 99 return err 100 } 101 } 102 versions = allowedVersions 103 origin = allVersions.Origin 104 return nil 105 }) 106 return versions, origin, err 107 } 108 109 // previousVersion returns the tagged version of m.Path immediately prior to 110 // m.Version, or version "none" if no prior version is tagged. 111 // 112 // Since the version of a main module is not found in the version list, 113 // it has no previous version. 114 func previousVersion(ctx context.Context, m module.Version) (module.Version, error) { 115 if m.Version == "" && MainModules.Contains(m.Path) { 116 return module.Version{Path: m.Path, Version: "none"}, nil 117 } 118 119 list, _, err := versions(ctx, m.Path, CheckAllowed) 120 if err != nil { 121 if errors.Is(err, os.ErrNotExist) { 122 return module.Version{Path: m.Path, Version: "none"}, nil 123 } 124 return module.Version{}, err 125 } 126 i := sort.Search(len(list), func(i int) bool { return gover.ModCompare(m.Path, list[i], m.Version) >= 0 }) 127 if i > 0 { 128 return module.Version{Path: m.Path, Version: list[i-1]}, nil 129 } 130 return module.Version{Path: m.Path, Version: "none"}, nil 131 } 132 133 func (*mvsReqs) Previous(m module.Version) (module.Version, error) { 134 // TODO(golang.org/issue/38714): thread tracing context through MVS. 135 return previousVersion(context.TODO(), m) 136 }