@@ -13,7 +13,6 @@ import (
1313 "github.com/github/codeql-go/extractor/toolchain"
1414 "github.com/github/codeql-go/extractor/util"
1515 "golang.org/x/mod/modfile"
16- "golang.org/x/mod/semver"
1716)
1817
1918// DependencyInstallerMode is an enum describing how dependencies should be installed
@@ -49,53 +48,47 @@ type GoWorkspace struct {
4948}
5049
5150// Represents a nullable version string.
52- type GoVersionInfo struct {
53- // The version string, if any
54- Version string
55- // A value indicating whether a version string was found
56- Found bool
57- }
51+ type GoVersionInfo = util.SemVer
5852
5953// Determines the version of Go that is required by this workspace. This is, in order of preference:
6054// 1. The Go version specified in the `go.work` file, if any.
6155// 2. The greatest Go version specified in any `go.mod` file, if any.
62- func (workspace * GoWorkspace ) RequiredGoVersion () GoVersionInfo {
56+ func (workspace * GoWorkspace ) RequiredGoVersion () util. SemVer {
6357 if workspace .WorkspaceFile != nil && workspace .WorkspaceFile .Go != nil {
6458 // If we have parsed a `go.work` file, return the version number from it.
65- return GoVersionInfo { Version : workspace .WorkspaceFile .Go .Version , Found : true }
59+ return util . NewSemVer ( workspace .WorkspaceFile .Go .Version )
6660 } else if workspace .Modules != nil && len (workspace .Modules ) > 0 {
6761 // Otherwise, if we have `go.work` files, find the greatest Go version in those.
68- var greatestVersion string = ""
62+ var greatestVersion util. SemVer = nil
6963 for _ , module := range workspace .Modules {
7064 if module .Module != nil && module .Module .Go != nil {
7165 // If we have parsed the file, retrieve the version number we have already obtained.
72- if greatestVersion == "" || semver .Compare ("v" + module .Module .Go .Version , "v" + greatestVersion ) > 0 {
73- greatestVersion = module .Module .Go .Version
66+ modVersion := util .NewSemVer (module .Module .Go .Version )
67+ if greatestVersion == nil || modVersion .IsNewerThan (greatestVersion ) {
68+ greatestVersion = modVersion
7469 }
7570 } else {
7671 modVersion := tryReadGoDirective (module .Path )
77- if modVersion . Found && (greatestVersion == "" || semver . Compare ( "v" + modVersion .Version , "v" + greatestVersion ) > 0 ) {
78- greatestVersion = modVersion . Version
72+ if modVersion != nil && (greatestVersion == nil || modVersion .IsNewerThan ( greatestVersion )) {
73+ greatestVersion = modVersion
7974 }
8075 }
8176 }
8277
8378 // If we have found some version, return it.
84- if greatestVersion != "" {
85- return GoVersionInfo {Version : greatestVersion , Found : true }
86- }
79+ return greatestVersion
8780 }
8881
89- return GoVersionInfo { Version : "" , Found : false }
82+ return nil
9083}
9184
9285// Finds the greatest Go version required by any of the given `workspaces`.
9386// Returns a `GoVersionInfo` value with `Found: false` if no version information is available.
94- func RequiredGoVersion (workspaces * []GoWorkspace ) GoVersionInfo {
95- greatestGoVersion := GoVersionInfo { Version : "" , Found : false }
87+ func RequiredGoVersion (workspaces * []GoWorkspace ) util. SemVer {
88+ var greatestGoVersion util. SemVer = nil
9689 for _ , workspace := range * workspaces {
9790 goVersionInfo := workspace .RequiredGoVersion ()
98- if goVersionInfo . Found && (! greatestGoVersion . Found || semver . Compare ( "v" + goVersionInfo .Version , "v" + greatestGoVersion . Version ) > 0 ) {
91+ if goVersionInfo != nil && (greatestGoVersion == nil || goVersionInfo .IsNewerThan ( greatestGoVersion ) ) {
9992 greatestGoVersion = goVersionInfo
10093 }
10194 }
@@ -182,8 +175,9 @@ var toolchainVersionRe *regexp.Regexp = regexp.MustCompile(`(?m)^([0-9]+\.[0-9]+
182175// Returns true if the `go.mod` file specifies a Go language version, that version is `1.21` or greater, and
183176// there is no `toolchain` directive, and the Go language version is not a valid toolchain version.
184177func hasInvalidToolchainVersion (modFile * modfile.File ) bool {
178+ v1_21 := util .NewSemVer ("v1.21.0" )
185179 return modFile .Toolchain == nil && modFile .Go != nil &&
186- ! toolchainVersionRe .Match ([]byte (modFile .Go .Version )) && semver . Compare ( "v" + modFile .Go .Version , "v1.21.0" ) >= 0
180+ ! toolchainVersionRe .Match ([]byte (modFile .Go .Version )) && util . NewSemVer ( modFile .Go .Version ). IsAtLeast ( v1_21 )
187181}
188182
189183// Given a list of `go.mod` file paths, try to parse them all. The resulting array of `GoModule` objects
@@ -537,17 +531,15 @@ const (
537531
538532// argsForGoVersion returns the arguments to pass to the Go compiler for the given `ModMode` and
539533// Go version
540- func (m ModMode ) ArgsForGoVersion (version string ) []string {
534+ func (m ModMode ) ArgsForGoVersion (version util. SemVer ) []string {
541535 switch m {
542536 case ModUnset :
543537 return []string {}
544538 case ModReadonly :
545539 return []string {"-mod=readonly" }
546540 case ModMod :
547- if ! semver .IsValid (version ) {
548- log .Fatalf ("Invalid Go semver: '%s'" , version )
549- }
550- if semver .Compare (version , "v1.14" ) < 0 {
541+ v1_14 := util .NewSemVer ("v1.14" )
542+ if version .IsOlderThan (v1_14 ) {
551543 return []string {} // -mod=mod is the default behaviour for go <= 1.13, and is not accepted as an argument
552544 } else {
553545 return []string {"-mod=mod" }
@@ -574,7 +566,7 @@ func getModMode(depMode DependencyInstallerMode, baseDir string) ModMode {
574566
575567// Tries to open `go.mod` and read a go directive, returning the version and whether it was found.
576568// The version string is returned in the "1.2.3" format.
577- func tryReadGoDirective (path string ) GoVersionInfo {
569+ func tryReadGoDirective (path string ) util. SemVer {
578570 versionRe := regexp .MustCompile (`(?m)^go[ \t\r]+([0-9]+\.[0-9]+(\.[0-9]+)?)` )
579571 goMod , err := os .ReadFile (path )
580572 if err != nil {
@@ -583,9 +575,9 @@ func tryReadGoDirective(path string) GoVersionInfo {
583575 matches := versionRe .FindSubmatch (goMod )
584576 if matches != nil {
585577 if len (matches ) > 1 {
586- return GoVersionInfo { string (matches [1 ]), true }
578+ return util . NewSemVer ( string (matches [1 ]))
587579 }
588580 }
589581 }
590- return GoVersionInfo { "" , false }
582+ return nil
591583}
0 commit comments