@@ -54,11 +54,13 @@ func NewConstraint(c string) (*Constraints, error) {
5454
5555// Check tests if a version satisfies the constraints.
5656func (cs Constraints ) Check (v * Version ) bool {
57+ // TODO(mattfarina): For v4 of this library consolidate the Check and Validate
58+ // functions as the underlying functions make that possible now.
5759 // loop over the ORs and check the inner ANDs
5860 for _ , o := range cs .constraints {
5961 joy := true
6062 for _ , c := range o {
61- if ! c .check (v ) {
63+ if check , _ := c .check (v ); ! check {
6264 joy = false
6365 break
6466 }
@@ -96,9 +98,8 @@ func (cs Constraints) Validate(v *Version) (bool, []error) {
9698
9799 } else {
98100
99- if ! c .check (v ) {
100- em := fmt .Errorf (constraintMsg [c .origfunc ], v , c .orig )
101- e = append (e , em )
101+ if _ , err := c .check (v ); err != nil {
102+ e = append (e , err )
102103 joy = false
103104 }
104105 }
@@ -134,7 +135,6 @@ func (cs Constraints) String() string {
134135}
135136
136137var constraintOps map [string ]cfunc
137- var constraintMsg map [string ]string
138138var constraintRegex * regexp.Regexp
139139var constraintRangeRegex * regexp.Regexp
140140
@@ -164,21 +164,6 @@ func init() {
164164 "^" : constraintCaret ,
165165 }
166166
167- constraintMsg = map [string ]string {
168- "" : "%s is not equal to %s" ,
169- "=" : "%s is not equal to %s" ,
170- "!=" : "%s is equal to %s" ,
171- ">" : "%s is less than or equal to %s" ,
172- "<" : "%s is greater than or equal to %s" ,
173- ">=" : "%s is less than %s" ,
174- "=>" : "%s is less than %s" ,
175- "<=" : "%s is greater than %s" ,
176- "=<" : "%s is greater than %s" ,
177- "~" : "%s does not have same major and minor version as %s" ,
178- "~>" : "%s does not have same major and minor version as %s" ,
179- "^" : "%s does not have same major version as %s" ,
180- }
181-
182167 ops := make ([]string , 0 , len (constraintOps ))
183168 for k := range constraintOps {
184169 ops = append (ops , regexp .QuoteMeta (k ))
@@ -223,7 +208,7 @@ type constraint struct {
223208}
224209
225210// Check if a version meets the constraint
226- func (c * constraint ) check (v * Version ) bool {
211+ func (c * constraint ) check (v * Version ) ( bool , error ) {
227212 return constraintOps [c.origfunc ](v , c )
228213}
229214
@@ -232,7 +217,7 @@ func (c *constraint) string() string {
232217 return c .origfunc + c .orig
233218}
234219
235- type cfunc func (v * Version , c * constraint ) bool
220+ type cfunc func (v * Version , c * constraint ) ( bool , error )
236221
237222func parseConstraint (c string ) (* constraint , error ) {
238223 if len (c ) > 0 {
@@ -301,111 +286,148 @@ func parseConstraint(c string) (*constraint, error) {
301286}
302287
303288// Constraint functions
304- func constraintNotEqual (v * Version , c * constraint ) bool {
289+ func constraintNotEqual (v * Version , c * constraint ) ( bool , error ) {
305290 if c .dirty {
306291
307292 // If there is a pre-release on the version but the constraint isn't looking
308293 // for them assume that pre-releases are not compatible. See issue 21 for
309294 // more details.
310295 if v .Prerelease () != "" && c .con .Prerelease () == "" {
311- return false
296+ return false , fmt . Errorf ( "%s is a prerelease version and the constraint is only looking for release versions" , v )
312297 }
313298
314299 if c .con .Major () != v .Major () {
315- return true
300+ return true , nil
316301 }
317302 if c .con .Minor () != v .Minor () && ! c .minorDirty {
318- return true
303+ return true , nil
319304 } else if c .minorDirty {
320- return false
305+ return false , fmt . Errorf ( "%s is equal to %s" , v , c . orig )
321306 } else if c .con .Patch () != v .Patch () && ! c .patchDirty {
322- return true
307+ return true , nil
323308 } else if c .patchDirty {
324309 // Need to handle prereleases if present
325310 if v .Prerelease () != "" || c .con .Prerelease () != "" {
326- return comparePrerelease (v .Prerelease (), c .con .Prerelease ()) != 0
311+ eq := comparePrerelease (v .Prerelease (), c .con .Prerelease ()) != 0
312+ if eq {
313+ return true , nil
314+ }
315+ return false , fmt .Errorf ("%s is equal to %s" , v , c .orig )
327316 }
328- return false
317+ return false , fmt . Errorf ( "%s is equal to %s" , v , c . orig )
329318 }
330319 }
331320
332- return ! v .Equal (c .con )
321+ eq := v .Equal (c .con )
322+ if eq {
323+ return false , fmt .Errorf ("%s is equal to %s" , v , c .orig )
324+ }
325+
326+ return true , nil
333327}
334328
335- func constraintGreaterThan (v * Version , c * constraint ) bool {
329+ func constraintGreaterThan (v * Version , c * constraint ) ( bool , error ) {
336330
337331 // If there is a pre-release on the version but the constraint isn't looking
338332 // for them assume that pre-releases are not compatible. See issue 21 for
339333 // more details.
340334 if v .Prerelease () != "" && c .con .Prerelease () == "" {
341- return false
335+ return false , fmt . Errorf ( "%s is a prerelease version and the constraint is only looking for release versions" , v )
342336 }
343337
338+ var eq bool
339+
344340 if ! c .dirty {
345- return v .Compare (c .con ) == 1
341+ eq = v .Compare (c .con ) == 1
342+ if eq {
343+ return true , nil
344+ }
345+ return false , fmt .Errorf ("%s is less than or equal to %s" , v , c .orig )
346346 }
347347
348348 if v .Major () > c .con .Major () {
349- return true
349+ return true , nil
350350 } else if v .Major () < c .con .Major () {
351- return false
351+ return false , fmt . Errorf ( "%s is less than or equal to %s" , v , c . orig )
352352 } else if c .minorDirty {
353353 // This is a range case such as >11. When the version is something like
354354 // 11.1.0 is it not > 11. For that we would need 12 or higher
355- return false
355+ return false , fmt . Errorf ( "%s is less than or equal to %s" , v , c . orig )
356356 } else if c .patchDirty {
357357 // This is for ranges such as >11.1. A version of 11.1.1 is not greater
358358 // which one of 11.2.1 is greater
359- return v .Minor () > c .con .Minor ()
359+ eq = v .Minor () > c .con .Minor ()
360+ if eq {
361+ return true , nil
362+ }
363+ return false , fmt .Errorf ("%s is less than or equal to %s" , v , c .orig )
360364 }
361365
362366 // If we have gotten here we are not comparing pre-preleases and can use the
363367 // Compare function to accomplish that.
364- return v .Compare (c .con ) == 1
368+ eq = v .Compare (c .con ) == 1
369+ if eq {
370+ return true , nil
371+ }
372+ return false , fmt .Errorf ("%s is less than or equal to %s" , v , c .orig )
365373}
366374
367- func constraintLessThan (v * Version , c * constraint ) bool {
375+ func constraintLessThan (v * Version , c * constraint ) ( bool , error ) {
368376 // If there is a pre-release on the version but the constraint isn't looking
369377 // for them assume that pre-releases are not compatible. See issue 21 for
370378 // more details.
371379 if v .Prerelease () != "" && c .con .Prerelease () == "" {
372- return false
380+ return false , fmt . Errorf ( "%s is a prerelease version and the constraint is only looking for release versions" , v )
373381 }
374382
375- return v .Compare (c .con ) < 0
383+ eq := v .Compare (c .con ) < 0
384+ if eq {
385+ return true , nil
386+ }
387+ return false , fmt .Errorf ("%s is greater than or equal to %s" , v , c .orig )
376388}
377389
378- func constraintGreaterThanEqual (v * Version , c * constraint ) bool {
390+ func constraintGreaterThanEqual (v * Version , c * constraint ) ( bool , error ) {
379391
380392 // If there is a pre-release on the version but the constraint isn't looking
381393 // for them assume that pre-releases are not compatible. See issue 21 for
382394 // more details.
383395 if v .Prerelease () != "" && c .con .Prerelease () == "" {
384- return false
396+ return false , fmt . Errorf ( "%s is a prerelease version and the constraint is only looking for release versions" , v )
385397 }
386398
387- return v .Compare (c .con ) >= 0
399+ eq := v .Compare (c .con ) >= 0
400+ if eq {
401+ return true , nil
402+ }
403+ return false , fmt .Errorf ("%s is less than %s" , v , c .orig )
388404}
389405
390- func constraintLessThanEqual (v * Version , c * constraint ) bool {
406+ func constraintLessThanEqual (v * Version , c * constraint ) ( bool , error ) {
391407 // If there is a pre-release on the version but the constraint isn't looking
392408 // for them assume that pre-releases are not compatible. See issue 21 for
393409 // more details.
394410 if v .Prerelease () != "" && c .con .Prerelease () == "" {
395- return false
411+ return false , fmt . Errorf ( "%s is a prerelease version and the constraint is only looking for release versions" , v )
396412 }
397413
414+ var eq bool
415+
398416 if ! c .dirty {
399- return v .Compare (c .con ) <= 0
417+ eq = v .Compare (c .con ) <= 0
418+ if eq {
419+ return true , nil
420+ }
421+ return false , fmt .Errorf ("%s is greater than %s" , v , c .orig )
400422 }
401423
402424 if v .Major () > c .con .Major () {
403- return false
425+ return false , fmt . Errorf ( "%s is greater than %s" , v , c . orig )
404426 } else if v .Major () == c .con .Major () && v .Minor () > c .con .Minor () && ! c .minorDirty {
405- return false
427+ return false , fmt . Errorf ( "%s is greater than %s" , v , c . orig )
406428 }
407429
408- return true
430+ return true , nil
409431}
410432
411433// ~*, ~>* --> >= 0.0.0 (any)
@@ -414,51 +436,56 @@ func constraintLessThanEqual(v *Version, c *constraint) bool {
414436// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0
415437// ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0
416438// ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0
417- func constraintTilde (v * Version , c * constraint ) bool {
439+ func constraintTilde (v * Version , c * constraint ) ( bool , error ) {
418440 // If there is a pre-release on the version but the constraint isn't looking
419441 // for them assume that pre-releases are not compatible. See issue 21 for
420442 // more details.
421443 if v .Prerelease () != "" && c .con .Prerelease () == "" {
422- return false
444+ return false , fmt . Errorf ( "%s is a prerelease version and the constraint is only looking for release versions" , v )
423445 }
424446
425447 if v .LessThan (c .con ) {
426- return false
448+ return false , fmt . Errorf ( "%s is less than %s" , v , c . orig )
427449 }
428450
429451 // ~0.0.0 is a special case where all constraints are accepted. It's
430452 // equivalent to >= 0.0.0.
431453 if c .con .Major () == 0 && c .con .Minor () == 0 && c .con .Patch () == 0 &&
432454 ! c .minorDirty && ! c .patchDirty {
433- return true
455+ return true , nil
434456 }
435457
436458 if v .Major () != c .con .Major () {
437- return false
459+ return false , fmt . Errorf ( "%s does not have same major version as %s" , v , c . orig )
438460 }
439461
440462 if v .Minor () != c .con .Minor () && ! c .minorDirty {
441- return false
463+ return false , fmt . Errorf ( "%s does not have same major and minor version as %s" , v , c . orig )
442464 }
443465
444- return true
466+ return true , nil
445467}
446468
447469// When there is a .x (dirty) status it automatically opts in to ~. Otherwise
448470// it's a straight =
449- func constraintTildeOrEqual (v * Version , c * constraint ) bool {
471+ func constraintTildeOrEqual (v * Version , c * constraint ) ( bool , error ) {
450472 // If there is a pre-release on the version but the constraint isn't looking
451473 // for them assume that pre-releases are not compatible. See issue 21 for
452474 // more details.
453475 if v .Prerelease () != "" && c .con .Prerelease () == "" {
454- return false
476+ return false , fmt . Errorf ( "%s is a prerelease version and the constraint is only looking for release versions" , v )
455477 }
456478
457479 if c .dirty {
458480 return constraintTilde (v , c )
459481 }
460482
461- return v .Equal (c .con )
483+ eq := v .Equal (c .con )
484+ if eq {
485+ return true , nil
486+ }
487+
488+ return false , fmt .Errorf ("%s is not equal to %s" , v , c .orig )
462489}
463490
464491// ^* --> (any)
@@ -470,40 +497,54 @@ func constraintTildeOrEqual(v *Version, c *constraint) bool {
470497// ^0.0.3 --> >=0.0.3 <0.0.4
471498// ^0.0 --> >=0.0.0 <0.1.0
472499// ^0 --> >=0.0.0 <1.0.0
473- func constraintCaret (v * Version , c * constraint ) bool {
500+ func constraintCaret (v * Version , c * constraint ) ( bool , error ) {
474501 // If there is a pre-release on the version but the constraint isn't looking
475502 // for them assume that pre-releases are not compatible. See issue 21 for
476503 // more details.
477504 if v .Prerelease () != "" && c .con .Prerelease () == "" {
478- return false
505+ return false , fmt . Errorf ( "%s is a prerelease version and the constraint is only looking for release versions" , v )
479506 }
480507
481508 // This less than handles prereleases
482509 if v .LessThan (c .con ) {
483- return false
510+ return false , fmt . Errorf ( "%s is less than %s" , v , c . orig )
484511 }
485512
513+ var eq bool
514+
486515 // ^ when the major > 0 is >=x.y.z < x+1
487516 if c .con .Major () > 0 || c .minorDirty {
488517
489518 // ^ has to be within a major range for > 0. Everything less than was
490519 // filtered out with the LessThan call above. This filters out those
491520 // that greater but not within the same major range.
492- return v .Major () == c .con .Major ()
521+ eq = v .Major () == c .con .Major ()
522+ if eq {
523+ return true , nil
524+ }
525+ return false , fmt .Errorf ("%s does not have same major version as %s" , v , c .orig )
493526 }
494527
495528 // ^ when the major is 0 and minor > 0 is >=0.y.z < 0.y+1
496529 if c .con .Major () == 0 && v .Major () > 0 {
497- return false
530+ return false , fmt . Errorf ( "%s does not have same major version as %s" , v , c . orig )
498531 }
499532 // If the con Minor is > 0 it is not dirty
500533 if c .con .Minor () > 0 || c .patchDirty {
501- return v .Minor () == c .con .Minor ()
534+ eq = v .Minor () == c .con .Minor ()
535+ if eq {
536+ return true , nil
537+ }
538+ return false , fmt .Errorf ("%s does not have same minor version as %s. Expected minor versions to match when constraint major version is 0" , v , c .orig )
502539 }
503540
504541 // At this point the major is 0 and the minor is 0 and not dirty. The patch
505542 // is not dirty so we need to check if they are equal. If they are not equal
506- return c .con .Patch () == v .Patch ()
543+ eq = c .con .Patch () == v .Patch ()
544+ if eq {
545+ return true , nil
546+ }
547+ return false , fmt .Errorf ("%s does not equal %s. Expect version and constraint to equal when major and minor versions are 0" , v , c .orig )
507548}
508549
509550func isX (x string ) bool {
0 commit comments