github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/go/gover/mod.go (about) 1 // Copyright 2023 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 gover 6 7 import ( 8 "sort" 9 "strings" 10 11 "golang.org/x/mod/module" 12 "golang.org/x/mod/semver" 13 ) 14 15 // IsToolchain reports whether the module path corresponds to the 16 // virtual, non-downloadable module tracking go or toolchain directives in the go.mod file. 17 // 18 // Note that IsToolchain only matches "go" and "toolchain", not the 19 // real, downloadable module "golang.org/toolchain" containing toolchain files. 20 // 21 // IsToolchain("go") = true 22 // IsToolchain("toolchain") = true 23 // IsToolchain("golang.org/x/tools") = false 24 // IsToolchain("golang.org/toolchain") = false 25 func IsToolchain(path string) bool { 26 return path == "go" || path == "toolchain" 27 } 28 29 // ModCompare returns the result of comparing the versions x and y 30 // for the module with the given path. 31 // The path is necessary because the "go" and "toolchain" modules 32 // use a different version syntax and semantics (gover, this package) 33 // than most modules (semver). 34 func ModCompare(path string, x, y string) int { 35 if path == "go" { 36 return Compare(x, y) 37 } 38 if path == "toolchain" { 39 return Compare(maybeToolchainVersion(x), maybeToolchainVersion(y)) 40 } 41 return semver.Compare(x, y) 42 } 43 44 // ModSort is like module.Sort but understands the "go" and "toolchain" 45 // modules and their version ordering. 46 func ModSort(list []module.Version) { 47 sort.Slice(list, func(i, j int) bool { 48 mi := list[i] 49 mj := list[j] 50 if mi.Path != mj.Path { 51 return mi.Path < mj.Path 52 } 53 // To help go.sum formatting, allow version/file. 54 // Compare semver prefix by semver rules, 55 // file by string order. 56 vi := mi.Version 57 vj := mj.Version 58 var fi, fj string 59 if k := strings.Index(vi, "/"); k >= 0 { 60 vi, fi = vi[:k], vi[k:] 61 } 62 if k := strings.Index(vj, "/"); k >= 0 { 63 vj, fj = vj[:k], vj[k:] 64 } 65 if vi != vj { 66 return ModCompare(mi.Path, vi, vj) < 0 67 } 68 return fi < fj 69 }) 70 } 71 72 // ModIsValid reports whether vers is a valid version syntax for the module with the given path. 73 func ModIsValid(path, vers string) bool { 74 if IsToolchain(path) { 75 if path == "toolchain" { 76 return IsValid(FromToolchain(vers)) 77 } 78 return IsValid(vers) 79 } 80 return semver.IsValid(vers) 81 } 82 83 // ModIsPrefix reports whether v is a valid version syntax prefix for the module with the given path. 84 // The caller is assumed to have checked that ModIsValid(path, vers) is true. 85 func ModIsPrefix(path, vers string) bool { 86 if IsToolchain(path) { 87 if path == "toolchain" { 88 return IsLang(FromToolchain(vers)) 89 } 90 return IsLang(vers) 91 } 92 // Semver 93 dots := 0 94 for i := 0; i < len(vers); i++ { 95 switch vers[i] { 96 case '-', '+': 97 return false 98 case '.': 99 dots++ 100 if dots >= 2 { 101 return false 102 } 103 } 104 } 105 return true 106 } 107 108 // ModIsPrerelease reports whether v is a prerelease version for the module with the given path. 109 // The caller is assumed to have checked that ModIsValid(path, vers) is true. 110 func ModIsPrerelease(path, vers string) bool { 111 if IsToolchain(path) { 112 return IsPrerelease(vers) 113 } 114 return semver.Prerelease(vers) != "" 115 } 116 117 // ModMajorMinor returns the "major.minor" truncation of the version v, 118 // for use as a prefix in "@patch" queries. 119 func ModMajorMinor(path, vers string) string { 120 if IsToolchain(path) { 121 if path == "toolchain" { 122 return "go" + Lang(FromToolchain(vers)) 123 } 124 return Lang(vers) 125 } 126 return semver.MajorMinor(vers) 127 }