44#
55# Visit https://aboutcode.org and https://github.com/nexB/univers for support and download.
66
7- import functools
8- from functools import total_ordering
9-
107import attr
118import semantic_version
129from packaging import version as packaging_version
@@ -58,7 +55,7 @@ def is_valid_alpine_version(s):
5855 return str (i ) == left
5956
6057
61- @attr .s (frozen = True , order = False , hash = True )
58+ @attr .s (frozen = True , order = True , eq = True , hash = True )
6259class Version :
6360 """
6461 Base version mixin to subclass for each version syntax implementation.
@@ -72,14 +69,16 @@ class Version:
7269 """
7370
7471 # the original string used to build this Version
75- string = attr .ib (type = str )
72+ string = attr .ib (type = str , eq = False , order = False , hash = False )
7673
7774 # the normalized string for this Version, stored without spaces and
7875 # lowercased. Any leading v is removed too.
79- normalized_string = attr .ib (type = str , default = None , repr = False )
76+ normalized_string = attr .ib (
77+ type = str , default = None , repr = False , eq = False , order = False , hash = False
78+ )
8079
8180 # a comparable scheme-specific version object constructed from the version string
82- value = attr .ib (default = None , repr = False )
81+ value = attr .ib (default = None , repr = False , eq = True , order = True , hash = True )
8382
8483 def __attrs_post_init__ (self ):
8584 normalized_string = self .normalize (self .string )
@@ -109,7 +108,7 @@ def normalize(cls, string):
109108 Return a normalized version string from ``string ``. Subclass can override.
110109 """
111110 # FIXME: Is removing spaces and strip v the right thing to do?
112- return remove_spaces (string ).rstrip ( "v " ). strip ( )
111+ return remove_spaces (string ).lstrip ( "vV" )
113112
114113 @classmethod
115114 def build_value (self , string ):
@@ -132,33 +131,7 @@ def satisfies(self, constraint):
132131 def __str__ (self ):
133132 return str (self .value )
134133
135- def __eq__ (self , other ):
136- if not isinstance (other , self .__class__ ):
137- return NotImplemented
138- return self .value .__eq__ (other .value )
139-
140- def __lt__ (self , other ):
141- if not isinstance (other , self .__class__ ):
142- return NotImplemented
143- return self .value .__lt__ (other .value )
144134
145- def __gt__ (self , other ):
146- if not isinstance (other , self .__class__ ):
147- return NotImplemented
148- return self .value .__gt__ (other .value )
149-
150- def __le__ (self , other ):
151- if not isinstance (other , self .__class__ ):
152- return NotImplemented
153- return self .value .__le__ (other .value )
154-
155- def __ge__ (self , other ):
156- if not isinstance (other , self .__class__ ):
157- return NotImplemented
158- return self .value .__ge__ (other .value )
159-
160-
161- @attr .s (frozen = True , order = False , hash = True )
162135class GenericVersion (Version ):
163136 @classmethod
164137 def is_valid (cls , string ):
@@ -173,13 +146,13 @@ def is_valid(cls, string):
173146 return super (GenericVersion , cls ).is_valid (string )
174147
175148
176- @attr .s (frozen = True , order = False , eq = False , hash = True )
177149class PypiVersion (Version ):
178150 """
179151 Python PEP 440 version as implemented in packaging with fallback to "legacy"
180152 """
181153
182154 # TODO: ensure we deal with triple equal
155+ # TODO: use packvers and handle legacy versions
183156
184157 @classmethod
185158 def build_value (cls , string ):
@@ -198,18 +171,22 @@ def is_valid(cls, string):
198171 except packaging_version .InvalidVersion :
199172 return False
200173
201- return False
174+
175+ class EnhancedSemanticVersion (semantic_version .Version ):
176+ @property
177+ def precedence_key (self ):
178+ key = super (EnhancedSemanticVersion , self ).precedence_key
179+ return key + (self .build or ())
202180
203181
204- @attr .s (frozen = True , order = False , eq = False , hash = True )
205182class SemverVersion (Version ):
206183 """
207184 Strict semver v2.0 with 3 segments.
208185 """
209186
210187 @classmethod
211188 def build_value (cls , string ):
212- return semantic_version . Version .coerce (string )
189+ return EnhancedSemanticVersion .coerce (string )
213190
214191 @classmethod
215192 def is_valid (cls , string ):
@@ -264,7 +241,6 @@ def is_even(s):
264241 return (int (s ) % 2 ) == 0
265242
266243
267- @attr .s (frozen = True , order = False , eq = False , hash = True )
268244class NginxVersion (SemverVersion ):
269245 """
270246 Semver with 3 segments and extra attribute for stable vs. unstable branches
@@ -278,7 +254,6 @@ def is_stable(self):
278254 return is_even (self .minor )
279255
280256
281- @attr .s (frozen = True , order = False , eq = False , hash = True )
282257class RubygemsVersion (Version ):
283258 """
284259 Rubygems encourages semver version but does not enforce it.
@@ -295,7 +270,6 @@ def is_valid(cls, string):
295270 return gem .GemVersion .is_correct (string )
296271
297272
298- @attr .s (frozen = True , order = False , eq = False , hash = True )
299273class ArchLinuxVersion (Version ):
300274 def __eq__ (self , other ):
301275 if not isinstance (other , self .__class__ ):
@@ -323,7 +297,6 @@ def __ge__(self, other):
323297 return arch .vercmp (self .value , other .value ) >= 0
324298
325299
326- @attr .s (frozen = True , order = False , eq = False , hash = True )
327300class DebianVersion (Version ):
328301 @classmethod
329302 def build_value (cls , string ):
@@ -334,7 +307,6 @@ def is_valid(cls, string):
334307 return debian .Version .is_valid (string )
335308
336309
337- @attr .s (frozen = True , order = False , eq = False , hash = True )
338310class MavenVersion (Version ):
339311 # See https://maven.apache.org/enforcer/enforcer-rules/versionRanges.html
340312 # https://github.com/apache/maven/tree/master/maven-artifact/src/main/java/org/apache/maven/artifact/versioning
@@ -345,8 +317,6 @@ def build_value(cls, string):
345317
346318
347319# We will use total ordering to sort the versions, since these versions also consider prereleases.
348- @attr .s (frozen = True , order = False , eq = False , hash = True )
349- @functools .total_ordering
350320class NugetVersion (Version ):
351321 # See https://docs.microsoft.com/en-us/nuget/concepts/package-versioning
352322
@@ -362,33 +332,17 @@ def is_valid(cls, string):
362332 except ValueError :
363333 return False
364334
365- def __str__ (self ):
366- return str (self .string )
367-
368- def __lt__ (self , other ):
369- return nuget .Version .from_string (self .string ) < nuget .Version .from_string (other .string )
370-
371- def __eq__ (self , other ):
372- return nuget .Version .from_string (self .string ) == nuget .Version .from_string (other .string )
373335
374-
375- @attr .s (frozen = True , order = False , eq = False , hash = True )
376336class RpmVersion (Version ):
377337 """
378338 Represent an RPM version.
379-
380- For example::
381-
382- # 1:1.1.4|>=2.8.16|<=2.8.16-z
383339 """
384340
385341 @classmethod
386342 def build_value (cls , string ):
387343 return rpm .RpmVersion .from_string (string )
388344
389345
390- @total_ordering
391- @attr .s (frozen = True , order = False , eq = False , hash = True )
392346class GentooVersion (Version ):
393347 @classmethod
394348 def is_valid (cls , string ):
@@ -404,44 +358,30 @@ def __lt__(self, other):
404358 return NotImplemented
405359 return gentoo .vercmp (self .value , other .value ) == - 1
406360
407-
408- @attr .s (frozen = True , order = False , eq = False , hash = True )
409- class AlpineLinuxVersion (Version ):
410- @classmethod
411- def is_valid (cls , string ):
412- return is_valid_alpine_version (string ) and gentoo .is_valid (string )
413-
414- def __eq__ (self , other ):
361+ def __gt__ (self , other ):
415362 if not isinstance (other , self .__class__ ):
416363 return NotImplemented
417- return gentoo .vercmp (self .value , other .value ) == 0
364+ return gentoo .vercmp (self .value , other .value ) == 1
418365
419- def __lt__ (self , other ):
420- if not isinstance (other , self .__class__ ):
421- return NotImplemented
422- return gentoo .vercmp (self .value , other .value ) < 0
423366
424- def __gt__ ( self , other ):
425- if not isinstance ( other , self . __class__ ):
426- return NotImplemented
427- return gentoo . vercmp ( self . value , other . value ) > 0
367+ class AlpineLinuxVersion ( GentooVersion ):
368+ @ classmethod
369+ def is_valid ( cls , string ):
370+ return is_valid_alpine_version ( string ) and gentoo . is_valid ( string )
428371
429372
430- @attr .s (frozen = True , order = False , eq = False , hash = True )
431373class ComposerVersion (SemverVersion ):
432374 @classmethod
433375 def build_value (cls , string ):
434- return semantic_version . Version . coerce (string .lstrip ("vV" ))
376+ return super (). build_value (string .lstrip ("vV" ))
435377
436378
437- @attr .s (frozen = True , order = False , eq = False , hash = True )
438379class GolangVersion (SemverVersion ):
439380 @classmethod
440381 def build_value (cls , string ):
441- return semantic_version . Version . coerce (string .lstrip ("vV" ))
382+ return super (). build_value (string .lstrip ("vV" ))
442383
443384
444- @attr .s (frozen = True , order = False , eq = False , hash = True )
445385class LegacyOpensslVersion (Version ):
446386 """
447387 Represent an Legacy Openssl Version.
@@ -557,7 +497,6 @@ def is_prerelease(self):
557497 return self .patch .startswith (("-beta" , "-alpha" ))
558498
559499
560- @attr .s (frozen = True , order = False , eq = False , hash = True )
561500class OpensslVersion (Version ):
562501 """
563502 Internally tracks two types of openssl versions
@@ -650,3 +589,22 @@ def __ge__(self, other):
650589 return self .value .__ge__ (other .value )
651590 # version value are of diff type, then semver one is always ahead of legacy
652591 return isinstance (self .value , SemverVersion )
592+
593+
594+ AVAILABLE_VERSIONS = [
595+ SemverVersion ,
596+ GolangVersion ,
597+ PypiVersion ,
598+ GenericVersion ,
599+ ComposerVersion ,
600+ NginxVersion ,
601+ ArchLinuxVersion ,
602+ DebianVersion ,
603+ RpmVersion ,
604+ MavenVersion ,
605+ NugetVersion ,
606+ GentooVersion ,
607+ OpensslVersion ,
608+ LegacyOpensslVersion ,
609+ AlpineLinuxVersion ,
610+ ]
0 commit comments