"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/fsys"
+ "cmd/go/internal/gover"
"cmd/go/internal/imports"
"cmd/go/internal/modfetch"
"cmd/go/internal/modindex"
for mod := range mdeps {
sortedMods = append(sortedMods, mod)
}
- module.Sort(sortedMods)
+ gover.ModSort(sortedMods)
deps := make([]*debug.Module, len(sortedMods))
for i, mod := range sortedMods {
deps[i] = mdeps[mod]
vendorMods = append(vendorMods, m)
}
}
- module.Sort(vendorMods)
+ gover.ModSort(vendorMods)
var (
buf bytes.Buffer
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/gover"
"cmd/go/internal/imports"
"cmd/go/internal/modfetch"
"cmd/go/internal/modload"
"golang.org/x/mod/modfile"
"golang.org/x/mod/module"
- "golang.org/x/mod/semver"
)
var CmdGet = &base.Command{
r.work.Add(func() {
if _, err := modfetch.DownloadZip(ctx, mActual); err != nil {
verb := "upgraded"
- if semver.Compare(m.Version, old.Version) < 0 {
+ if gover.ModCompare(m.Path, m.Version, old.Version) < 0 {
verb = "downgraded"
}
replaced := ""
fmt.Fprintf(os.Stderr, "go: added %s %s\n", c.path, c.new)
} else if c.new == "none" || c.new == "" {
fmt.Fprintf(os.Stderr, "go: removed %s %s\n", c.path, c.old)
- } else if semver.Compare(c.new, c.old) > 0 {
+ } else if gover.ModCompare(c.path, c.new, c.old) > 0 {
fmt.Fprintf(os.Stderr, "go: upgraded %s %s => %s\n", c.path, c.old, c.new)
} else {
fmt.Fprintf(os.Stderr, "go: downgraded %s %s => %s\n", c.path, c.old, c.new)
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/gover"
"cmd/go/internal/modfetch"
"cmd/go/internal/modfetch/codehost"
"cmd/go/internal/modindex"
"cmd/go/internal/search"
"golang.org/x/mod/module"
- "golang.org/x/mod/semver"
)
var (
return
}
- if semver.Compare(info.Version, m.Version) > 0 {
+ if gover.ModCompare(m.Path, info.Version, m.Version) > 0 {
m.Update = &modinfo.ModulePublic{
Path: m.Path,
Version: info.Version,
import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/gover"
"cmd/go/internal/mvs"
"cmd/go/internal/par"
"cmd/go/internal/slices"
"sync/atomic"
"golang.org/x/mod/module"
- "golang.org/x/mod/semver"
)
// A Requirements represents a logically-immutable set of root module requirements.
// The dependencies of the roots will be loaded lazily at the first call to the
// Graph method.
//
-// The rootModules slice must be sorted according to module.Sort.
+// The rootModules slice must be sorted according to gover.ModSort.
// The caller must not modify the rootModules slice or direct map after passing
// them to newRequirements.
//
}
if i > 0 {
prev := rootModules[i-1]
- if prev.Path > m.Path || (prev.Path == m.Path && semver.Compare(prev.Version, m.Version) > 0) {
+ if prev.Path > m.Path || (prev.Path == m.Path && gover.ModCompare(m.Path, prev.Version, m.Version) > 0) {
panic(fmt.Sprintf("newRequirements called with unsorted roots: %v", rootModules))
}
}
}
for _, m := range rootModules {
- if v, ok := rs.maxRootVersion[m.Path]; ok && cmpVersion(v, m.Version) >= 0 {
+ if v, ok := rs.maxRootVersion[m.Path]; ok && gover.ModCompare(m.Path, v, m.Version) >= 0 {
continue
}
rs.maxRootVersion[m.Path] = m.Version
reqs, _ := mg.g.RequiredBy(m)
for _, r := range reqs {
s := module.Version{Path: r.Path, Version: mg.g.Selected(r.Path)}
- if cmpVersion(s.Version, r.Version) > 0 && !seen[s] {
+ if gover.ModCompare(r.Path, s.Version, r.Version) > 0 && !seen[s] {
needsEnqueueing[s] = true
}
}
queue = append(queue, pkg)
queued[pkg] = true
}
- module.Sort(roots)
+ gover.ModSort(roots)
tidy := newRequirements(pruned, roots, direct)
for len(queue) > 0 {
}
if !pathIsRoot[m.Path] {
- if s := mg.Selected(m.Path); cmpVersion(s, m.Version) < 0 {
+ if s := mg.Selected(m.Path); gover.ModCompare(m.Path, s, m.Version) < 0 {
roots = append(roots, m)
pathIsRoot[m.Path] = true
}
}
if len(roots) > len(tidy.rootModules) {
- module.Sort(roots)
+ gover.ModSort(roots)
tidy = newRequirements(pruned, roots, tidy.direct)
}
}
}
for _, m := range add {
- if v, ok := rs.rootSelected(m.Path); !ok || cmpVersion(v, m.Version) < 0 {
+ if v, ok := rs.rootSelected(m.Path); !ok || gover.ModCompare(m.Path, v, m.Version) < 0 {
roots = append(roots, m)
rootsUpgraded = true
needSort = true
}
}
if needSort {
- module.Sort(roots)
+ gover.ModSort(roots)
}
// "Each root appears only once, at the selected version of its path ….”
}
for _, r := range summary.require {
- if v, ok := rs.rootSelected(r.Path); ok && cmpVersion(v, r.Version) < 0 {
+ if v, ok := rs.rootSelected(r.Path); ok && gover.ModCompare(r.Path, v, r.Version) < 0 {
cancel()
return
}
// in go.mod. See comment on altMods above.
keptAltMod := false
for _, m := range buildList {
- if v, ok := altMods[m.Path]; ok && semver.Compare(m.Version, v) < 0 {
+ if v, ok := altMods[m.Path]; ok && gover.ModCompare(m.Path, m.Version, v) < 0 {
keep = append(keep, module.Version{Path: m.Path, Version: v})
keptAltMod = true
}
roots = append(roots, min...)
}
if MainModules.Len() > 1 {
- module.Sort(roots)
+ gover.ModSort(roots)
}
if rs.pruning == unpruned && reflect.DeepEqual(roots, rs.rootModules) && reflect.DeepEqual(direct, rs.direct) {
// The root set is unchanged and rs was already unpruned, so keep rs to
import (
"cmd/go/internal/cfg"
+ "cmd/go/internal/gover"
"cmd/go/internal/mvs"
"cmd/go/internal/par"
"context"
}
for _, r := range tryUpgrade {
- if v, ok := selectedRoot[r.Path]; ok && cmpVersion(v, r.Version) >= 0 {
+ if v, ok := selectedRoot[r.Path]; ok && gover.ModCompare(r.Path, v, r.Version) >= 0 {
continue
}
if cfg.BuildV {
for _, r := range mustSelect {
if v, ok := mustSelectVersion[r.Path]; ok && v != r.Version {
prev := module.Version{Path: r.Path, Version: v}
- if cmpVersion(v, r.Version) > 0 {
+ if gover.ModCompare(r.Path, v, r.Version) > 0 {
conflicts = append(conflicts, Conflict{Path: []module.Version{prev}, Constraint: r})
} else {
conflicts = append(conflicts, Conflict{Path: []module.Version{r}, Constraint: prev})
roots = append(roots, module.Version{Path: p, Version: v})
}
}
- module.Sort(roots)
+ gover.ModSort(roots)
// First, we extend the graph so that it includes the selected version
// of every root. The upgraded roots are in addition to the original
// Now check the resulting extended graph for errors and incompatibilities.
t := dqTracker{extendedRootPruning: extendedRootPruning}
mg.g.WalkBreadthFirst(func(m module.Version) {
- if max, ok := mustSelectVersion[m.Path]; ok && cmpVersion(m.Version, max) > 0 {
+ if max, ok := mustSelectVersion[m.Path]; ok && gover.ModCompare(m.Path, m.Version, max) > 0 {
// m itself violates mustSelect, so it cannot appear in the module graph
// even if its transitive dependencies would be pruned out.
t.disqualify(m, pruned, dqState{dep: m})
// violates mustSelect disqualifies m, even if the requirements of r are
// themselves pruned out.
for _, r := range reqs {
- if max, ok := mustSelectVersion[r.Path]; ok && cmpVersion(r.Version, max) > 0 {
+ if max, ok := mustSelectVersion[r.Path]; ok && gover.ModCompare(r.Path, r.Version, max) > 0 {
t.disqualify(m, pruned, dqState{dep: r})
return
}
prev := m
for {
prev, err = previousVersion(ctx, prev)
- if cmpVersion(m.Version, origV) > 0 && (cmpVersion(prev.Version, origV) < 0 || err != nil) {
+ if gover.ModCompare(m.Path, m.Version, origV) > 0 && (gover.ModCompare(m.Path, prev.Version, origV) < 0 || err != nil) {
// previousVersion skipped over origV. Insert it into the order.
prev.Version = origV
} else if err != nil {
}
if rootsDirty {
if cfg.BuildV {
- module.Sort(upgradedFrom) // Make logging deterministic.
+ gover.ModSort(upgradedFrom) // Make logging deterministic.
for _, m := range upgradedFrom {
fmt.Fprintf(os.Stderr, "go: accepting indirect upgrade from %v to %s\n", m, selectedRoot[m.Path])
}
"cmd/go/internal/cfg"
"cmd/go/internal/fsys"
+ "cmd/go/internal/gover"
"cmd/go/internal/modfetch"
"cmd/go/internal/modindex"
"cmd/go/internal/par"
"cmd/go/internal/str"
"golang.org/x/mod/module"
- "golang.org/x/mod/semver"
)
type ImportMissingError struct {
if err != nil {
return module.Version{}, err
}
- if cmpVersion(mg.Selected(mp), mv) >= 0 {
+ if gover.ModCompare(mp, mg.Selected(mp), mv) >= 0 {
// We can't resolve the import by adding mp@mv to the module graph,
// because the selected version of mp is already at least mv.
continue
candidate0MissingVersion := ""
for i, c := range candidates {
- if v := mg.Selected(c.Mod.Path); semver.Compare(v, c.Mod.Version) > 0 {
+ if v := mg.Selected(c.Mod.Path); gover.ModCompare(c.Mod.Path, v, c.Mod.Version) > 0 {
// QueryPattern proposed that we add module c.Mod to provide the package,
// but we already depend on a newer version of that module (and that
// version doesn't have the package).
"golang.org/x/mod/modfile"
"golang.org/x/mod/module"
- "golang.org/x/mod/semver"
)
// Variables set by other packages.
}
replacedByWorkFile[r.Old.Path] = true
v, ok := mainModules.highestReplaced[r.Old.Path]
- if !ok || semver.Compare(r.Old.Version, v) > 0 {
+ if !ok || gover.ModCompare(r.Old.Path, r.Old.Version, v) > 0 {
mainModules.highestReplaced[r.Old.Path] = r.Old.Version
}
replacements[r.Old] = r.New
replacements[r.Old] = newV
v, ok := mainModules.highestReplaced[r.Old.Path]
- if !ok || semver.Compare(r.Old.Version, v) > 0 {
+ if !ok || gover.ModCompare(r.Old.Path, r.Old.Version, v) > 0 {
mainModules.highestReplaced[r.Old.Path] = r.Old.Version
}
}
}
}
}
- module.Sort(roots)
+ gover.ModSort(roots)
rs := newRequirements(pruning, roots, direct)
return rs
}
for m := range modAddedBy {
toAdd = append(toAdd, m)
}
- module.Sort(toAdd) // to make errors deterministic
+ gover.ModSort(toAdd) // to make errors deterministic
// We ran updateRequirements before resolving missing imports and it didn't
// make any changes, so we know that the requirement graph is already
for m := range need {
toAdd = append(toAdd, m)
}
- module.Sort(toAdd)
+ gover.ModSort(toAdd)
rs, err := updateRoots(ctx, ld.requirements.direct, ld.requirements, nil, toAdd, ld.AssumeRootsImported)
if err != nil {
var rationale []string
isRetracted := false
for _, r := range summary.retract {
- if semver.Compare(r.Low, m.Version) <= 0 && semver.Compare(m.Version, r.High) <= 0 {
+ if gover.ModCompare(m.Path, r.Low, m.Version) <= 0 && gover.ModCompare(m.Path, m.Version, r.High) <= 0 {
isRetracted = true
if r.Rationale != "" {
rationale = append(rationale, r.Rationale)
"os"
"sort"
+ "cmd/go/internal/gover"
"cmd/go/internal/modfetch"
"cmd/go/internal/modfetch/codehost"
"golang.org/x/mod/module"
- "golang.org/x/mod/semver"
)
// cmpVersion implements the comparison for versions in the module loader.
//
-// It is consistent with semver.Compare except that as a special case,
+// It is consistent with gover.ModCompare except that as a special case,
// the version "" is considered higher than all other versions.
// The main module (also known as the target) has no version and must be chosen
// over other versions of the same module in the module dependency graph.
-func cmpVersion(v1, v2 string) int {
+func cmpVersion(p string, v1, v2 string) int {
if v2 == "" {
if v1 == "" {
return 0
if v1 == "" {
return 1
}
- return semver.Compare(v1, v2)
+ return gover.ModCompare(p, v1, v2)
}
// mvsReqs implements mvs.Reqs for module semantic versions,
// versions. The main module (also known as the target) has no version and must
// be chosen over other versions of the same module in the module dependency
// graph.
-func (*mvsReqs) Max(v1, v2 string) string {
- if cmpVersion(v1, v2) < 0 {
+func (*mvsReqs) Max(p, v1, v2 string) string {
+ if cmpVersion(p, v1, v2) < 0 {
return v2
}
return v1
}
return module.Version{}, err
}
- i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) >= 0 })
+ i := sort.Search(len(list), func(i int) bool { return gover.ModCompare(m.Path, list[i], m.Version) >= 0 })
if i > 0 {
return module.Version{Path: m.Path, Version: list[i-1]}, nil
}
{a: "none", b: "", want: ""},
{a: "", b: "none", want: ""},
} {
- max := reqs.Max(tc.a, tc.b)
+ max := reqs.Max("", tc.a, tc.b)
if max != tc.want {
t.Errorf("(%T).Max(%q, %q) = %q; want %q", reqs, tc.a, tc.b, max, tc.want)
}
"time"
"cmd/go/internal/cfg"
+ "cmd/go/internal/gover"
"cmd/go/internal/imports"
"cmd/go/internal/modfetch"
"cmd/go/internal/modfetch/codehost"
ctx, span := trace.StartSpan(ctx, "modload.queryProxy "+path+" "+query)
defer span.Done()
- if current != "" && current != "none" && !semver.IsValid(current) {
+ if current != "" && current != "none" && !gover.ModIsValid(path, current) {
return nil, fmt.Errorf("invalid previous version %q", current)
}
if cfg.BuildMod == "vendor" {
qm.mayUseLatest = true
} else {
qm.mayUseLatest = module.IsPseudoVersion(current)
- qm.filter = func(mv string) bool { return semver.Compare(mv, current) >= 0 }
+ qm.filter = func(mv string) bool { return gover.ModCompare(qm.path, mv, current) >= 0 }
}
case query == "patch":
} else {
qm.mayUseLatest = module.IsPseudoVersion(current)
qm.prefix = semver.MajorMinor(current) + "."
- qm.filter = func(mv string) bool { return semver.Compare(mv, current) >= 0 }
+ qm.filter = func(mv string) bool { return gover.ModCompare(qm.path, mv, current) >= 0 }
}
case strings.HasPrefix(query, "<="):
// Refuse to say whether <=v1.2 allows v1.2.3 (remember, @v1.2 might mean v1.2.3).
return nil, fmt.Errorf("ambiguous semantic version %q in range %q", v, query)
}
- qm.filter = func(mv string) bool { return semver.Compare(mv, v) <= 0 }
+ qm.filter = func(mv string) bool { return gover.ModCompare(qm.path, mv, v) <= 0 }
if !matchesMajor(v) {
qm.preferIncompatible = true
}
if !semver.IsValid(v) {
return badVersion(v)
}
- qm.filter = func(mv string) bool { return semver.Compare(mv, v) < 0 }
+ qm.filter = func(mv string) bool { return gover.ModCompare(qm.path, mv, v) < 0 }
if !matchesMajor(v) {
qm.preferIncompatible = true
}
if !semver.IsValid(v) {
return badVersion(v)
}
- qm.filter = func(mv string) bool { return semver.Compare(mv, v) >= 0 }
+ qm.filter = func(mv string) bool { return gover.ModCompare(qm.path, mv, v) >= 0 }
qm.preferLower = true
if !matchesMajor(v) {
qm.preferIncompatible = true
// Refuse to say whether >v1.2 allows v1.2.3 (remember, @v1.2 might mean v1.2.3).
return nil, fmt.Errorf("ambiguous semantic version %q in range %q", v, query)
}
- qm.filter = func(mv string) bool { return semver.Compare(mv, v) > 0 }
+ qm.filter = func(mv string) bool { return gover.ModCompare(qm.path, mv, v) > 0 }
qm.preferLower = true
if !matchesMajor(v) {
qm.preferIncompatible = true
qm.prefix = query + "."
// Do not allow the query "v1.2" to match versions lower than "v1.2.0",
// such as prereleases for that version. (https://golang.org/issue/31972)
- qm.filter = func(mv string) bool { return semver.Compare(mv, query) >= 0 }
+ qm.filter = func(mv string) bool { return gover.ModCompare(qm.path, mv, query) >= 0 }
} else {
qm.canStat = true
- qm.filter = func(mv string) bool { return semver.Compare(mv, query) == 0 }
+ qm.filter = func(mv string) bool { return gover.ModCompare(qm.path, mv, query) == 0 }
qm.prefix = semver.Canonical(query)
}
if !matchesMajor(query) {
return repoVersions, nil
}
+ path := rr.ModulePath()
sort.Slice(versions, func(i, j int) bool {
- return semver.Compare(versions[i], versions[j]) < 0
+ return gover.ModCompare(path, versions[i], versions[j]) < 0
})
str.Uniq(&versions)
return &modfetch.Versions{List: versions}, nil
}
}
- if err != nil || semver.Compare(v, info.Version) > 0 {
+ if err != nil || gover.ModCompare(path, v, info.Version) > 0 {
return rr.replacementStat(v)
}
}
// Since this module provides a package for the build, we know that it
// is in the build list and is the selected version of its path.
// If this information is new, record it.
- if v, ok := vendorVersion[mod.Path]; !ok || semver.Compare(v, mod.Version) < 0 {
+ if v, ok := vendorVersion[mod.Path]; !ok || gover.ModCompare(mod.Path, v, mod.Version) < 0 {
vendorList = append(vendorList, mod)
vendorVersion[mod.Path] = mod.Version
}
package mvs
import (
+ "cmd/go/internal/gover"
"cmd/go/internal/slices"
"fmt"
// Graph implements an incremental version of the MVS algorithm, with the
// requirements pushed by the caller instead of pulled by the MVS traversal.
type Graph struct {
- cmp func(v1, v2 string) int
+ cmp func(p, v1, v2 string) int
roots []module.Version
required map[module.Version][]module.Version
//
// The caller must ensure that the root slice is not modified while the Graph
// may be in use.
-func NewGraph(cmp func(v1, v2 string) int, roots []module.Version) *Graph {
+func NewGraph(cmp func(p, v1, v2 string) int, roots []module.Version) *Graph {
g := &Graph{
cmp: cmp,
roots: slices.Clip(roots),
for _, m := range roots {
g.isRoot[m] = true
- if g.cmp(g.Selected(m.Path), m.Version) < 0 {
+ if g.cmp(m.Path, g.Selected(m.Path), m.Version) < 0 {
g.selected[m.Path] = m.Version
}
}
g.isRoot[dep] = false
}
- if g.cmp(g.Selected(dep.Path), dep.Version) < 0 {
+ if g.cmp(dep.Path, g.Selected(dep.Path), dep.Version) < 0 {
g.selected[dep.Path] = dep.Version
}
}
list = append(list, module.Version{Path: path, Version: version})
}
}
- module.Sort(list[len(uniqueRoots):])
+ gover.ModSort(list[len(uniqueRoots):])
return list
}
// The caller must not modify the returned list.
Required(m module.Version) ([]module.Version, error)
- // Max returns the maximum of v1 and v2 (it returns either v1 or v2).
+ // Max returns the maximum of v1 and v2 (it returns either v1 or v2)
+ // in the module with path p.
//
// For all versions v, Max(v, "none") must be v,
// and for the target passed as the first argument to MVS functions,
//
// Note that v1 < v2 can be written Max(v1, v2) != v1
// and similarly v1 <= v2 can be written Max(v1, v2) == v2.
- Max(v1, v2 string) string
+ Max(p, v1, v2 string) string
}
// An UpgradeReqs is a Reqs that can also identify available upgrades.
}
func buildList(targets []module.Version, reqs Reqs, upgrade func(module.Version) (module.Version, error)) ([]module.Version, error) {
- cmp := func(v1, v2 string) int {
- if reqs.Max(v1, v2) != v1 {
+ cmp := func(p, v1, v2 string) int {
+ if reqs.Max(p, v1, v2) != v1 {
return -1
}
- if reqs.Max(v2, v1) != v2 {
+ if reqs.Max(p, v2, v1) != v2 {
return 1
}
return 0
list = append(list, module.Version{Path: u.Path, Version: "none"})
}
if prev, dup := upgradeTo[u.Path]; dup {
- upgradeTo[u.Path] = reqs.Max(prev, u.Version)
+ upgradeTo[u.Path] = reqs.Max(u.Path, prev, u.Version)
} else {
upgradeTo[u.Path] = u.Version
}
max[r.Path] = r.Version
}
for _, d := range downgrade {
- if v, ok := max[d.Path]; !ok || reqs.Max(v, d.Version) != d.Version {
+ if v, ok := max[d.Path]; !ok || reqs.Max(d.Path, v, d.Version) != d.Version {
max[d.Path] = d.Version
}
}
return
}
added[m] = true
- if v, ok := max[m.Path]; ok && reqs.Max(m.Version, v) != v {
+ if v, ok := max[m.Path]; ok && reqs.Max(m.Path, m.Version, v) != v {
// m would upgrade an existing dependency — it is not a strict downgrade,
// and because it was already present as a dependency, it could affect the
// behavior of other relevant packages.
// included when iterating over prior versions using reqs.Previous.
// Insert it into the right place in the iteration.
// If v is excluded, p should be returned again by reqs.Previous on the next iteration.
- if v := max[r.Path]; reqs.Max(v, r.Version) != v && reqs.Max(p.Version, v) != p.Version {
+ if v := max[r.Path]; reqs.Max(r.Path, v, r.Version) != v && reqs.Max(r.Path, p.Version, v) != p.Version {
p.Version = v
}
if p.Version == "none" {
type reqsMap map[module.Version][]module.Version
-func (r reqsMap) Max(v1, v2 string) string {
+func (r reqsMap) Max(_, v1, v2 string) string {
if v1 == "none" || v2 == "" {
return v2
}
func (r reqsMap) Upgrade(m module.Version) (module.Version, error) {
u := module.Version{Version: "none"}
for k := range r {
- if k.Path == m.Path && r.Max(u.Version, k.Version) == k.Version && !strings.HasSuffix(k.Version, ".hidden") {
+ if k.Path == m.Path && r.Max(k.Path, u.Version, k.Version) == k.Version && !strings.HasSuffix(k.Version, ".hidden") {
u = k
}
}
import (
"cmd/go/internal/base"
+ "cmd/go/internal/gover"
"cmd/go/internal/imports"
"cmd/go/internal/modload"
"context"
inMustSelect[r] = true
}
}
- module.Sort(mustSelect) // ensure determinism
+ gover.ModSort(mustSelect) // ensure determinism
mustSelectFor[m] = mustSelect
}