@@ -32,10 +32,9 @@ import (
3232 "path"
3333 "path/filepath"
3434 "runtime"
35- "sort"
3635 "strings"
3736
38- "github.com/blang /semver/v4 "
37+ "github.com/Masterminds /semver/v3 "
3938 "sigs.k8s.io/yaml"
4039)
4140
@@ -111,6 +110,33 @@ type archive struct {
111110 SelfLink string `json:"selfLink"`
112111}
113112
113+ // interpretVersion parses a "SemVer-ish" request into a single [semver.Version]
114+ // or a looser set of [semver.Constraints].
115+ //
116+ // This does *not* understand wildcards, comparators, ranges, or other special syntax.
117+ func interpretVersion (request string ) (* semver.Version , * semver.Constraints ) {
118+ // When no version is requested, look for one in the release index.
119+ if request == "" {
120+ c , _ := semver .NewConstraint ("*" )
121+ return nil , c
122+ }
123+
124+ // When an exact version is requested, don't look for it in the release index.
125+ if v , err := semver .StrictNewVersion (strings .TrimPrefix (request , "v" )); err == nil {
126+ return v , nil
127+ }
128+
129+ // When it is an inexact version, turn it into a search of the release index.
130+ if _ , err := semver .NewVersion (request ); err == nil {
131+ if c , err := semver .NewConstraint (request ); err == nil {
132+ return nil , c
133+ }
134+ }
135+
136+ // The request isn't a version at all.
137+ return nil , nil
138+ }
139+
114140func downloadBinaryAssets (ctx context.Context , binaryAssetsDirectory , binaryAssetsVersion , binaryAssetsIndexURL string ) (string , string , string , error ) {
115141 if binaryAssetsIndexURL == "" {
116142 binaryAssetsIndexURL = DefaultBinaryAssetsIndexURL
@@ -124,54 +150,24 @@ func downloadBinaryAssets(ctx context.Context, binaryAssetsDirectory, binaryAsse
124150 }
125151 }
126152
127- var requestedRange semver.Range
128- if binaryAssetsVersion != "" {
129- binaryAssetsVersion = strings .TrimPrefix (binaryAssetsVersion , "v" )
130- parsedVersion , errV := semver .ParseTolerant (binaryAssetsVersion )
131- parsedRange , errR := semver .ParseRange (binaryAssetsVersion )
132-
133- switch {
134- // When an exact version is requested, don't look for it in the release index.
135- case errV == nil && parsedVersion .String () == binaryAssetsVersion :
136- requestedRange = nil
137-
138- // When the version looks like a range, apply it to the index.
139- case errR == nil :
140- requestedRange = parsedRange
141-
142- // When the version isn't exact, turn it into a range.
143- //
144- // The `setup-envtest` tool interprets a partial version to mean "latest stable with that prefix."
145- // For example, "1" and "1.2" are akin to "1.x.x" and "1.2.x" in [semver.ParseRange].
146- // [semver.ParseTolerant] fills in missing minor or patch with "0", so this replaces those with "x".
147- //
148- // That *should* produce a valid range. If it doesn't, use the original value and skip the index.
149- case errV == nil :
150- suffix := strings .TrimPrefix (parsedVersion .FinalizeVersion (), binaryAssetsVersion )
151- suffix = strings .ReplaceAll (suffix , "0" , "x" )
152- parsedRange , errR = semver .ParseRange (binaryAssetsVersion + suffix )
153-
154- if errR == nil {
155- requestedRange = parsedRange
156- } else {
157- requestedRange = nil
158- }
159- }
160- } else {
161- // When no version is requested, look for one in the release index.
162- requestedRange = semver .MustParseRange (">0.0.0" )
153+ version , search := interpretVersion (binaryAssetsVersion )
154+
155+ // When an exact version is requested, use its canonical form to download without the release index.
156+ if version != nil {
157+ binaryAssetsVersion = version .String ()
163158 }
164159
165- // When a range a versions is requested, select one from the release index.
160+ // When a range of versions is requested, select a stable one from the release index.
166161 var binaryAssetsIndex * index
167- if requestedRange != nil {
162+ if search != nil {
168163 var err error
169164 binaryAssetsIndex , err = getIndex (ctx , binaryAssetsIndexURL )
170165 if err != nil {
171166 return "" , "" , "" , err
172167 }
173168
174- binaryAssetsVersion , err = latestStableVersionFromIndex (binaryAssetsIndex , requestedRange )
169+ search .IncludePrerelease = false
170+ binaryAssetsVersion , err = latestVersionFromIndex (binaryAssetsIndex , search )
175171 if err != nil {
176172 return "" , "" , "" , err
177173 }
@@ -293,34 +289,33 @@ func downloadBinaryAssetsArchive(ctx context.Context, index *index, version stri
293289 return readBody (resp , out , archiveName , archive .Hash )
294290}
295291
296- func latestStableVersionFromIndex (index * index , satisfying semver.Range ) (string , error ) {
292+ func latestVersionFromIndex (index * index , satisfying * semver.Constraints ) (string , error ) {
297293 if len (index .Releases ) == 0 {
298- return "" , fmt .Errorf ("failed to find latest stable version from index: index is empty" )
294+ return "" , fmt .Errorf ("failed to find latest version from index: index is empty" )
299295 }
300296
301- parsedVersions := [] semver.Version {}
297+ var maxVersion * semver.Version
302298 for releaseVersion := range index .Releases {
303- v , err := semver .ParseTolerant (releaseVersion )
299+ v , err := semver .NewVersion (releaseVersion )
304300 if err != nil {
305301 return "" , fmt .Errorf ("failed to parse version %q: %w" , releaseVersion , err )
306302 }
307303
308- // Filter out pre-releases and undesirable versions.
309- if len ( v . Pre ) > 0 || ! satisfying (v ) {
304+ // Filter out undesirable versions.
305+ if ! satisfying . Check (v ) {
310306 continue
311307 }
312308
313- parsedVersions = append (parsedVersions , v )
309+ if maxVersion == nil || v .GreaterThan (maxVersion ) {
310+ maxVersion = v
311+ }
314312 }
315313
316- if len ( parsedVersions ) == 0 {
317- return "" , fmt .Errorf ("failed to find latest stable version from index: index does not have stable versions" )
314+ if maxVersion == nil {
315+ return "" , fmt .Errorf ("failed to find latest version from index: nothing matches %q" , satisfying )
318316 }
319317
320- sort .Slice (parsedVersions , func (i , j int ) bool {
321- return parsedVersions [i ].GT (parsedVersions [j ])
322- })
323- return "v" + parsedVersions [0 ].String (), nil
318+ return "v" + maxVersion .String (), nil
324319}
325320
326321func getIndex (ctx context.Context , indexURL string ) (* index , error ) {
0 commit comments