@@ -343,3 +343,172 @@ def __gt__(self, other):
343
343
if not isinstance (other , self .__class__ ):
344
344
return NotImplemented
345
345
return gentoo .vercmp (self .value , other .value ) > 0
346
+
347
+
348
+ @attr .s (frozen = True , order = False , eq = False , hash = True )
349
+ class LegacyOpensslVersion (Version ):
350
+ """
351
+ Represent an Legacy Openssl Version .
352
+
353
+ For example::
354
+
355
+ # 1.0.1f|0.9.7d|1.0.2ac
356
+ """
357
+
358
+ @classmethod
359
+ def is_valid (cls , string ):
360
+ return bool (cls .parse (string ))
361
+
362
+ @classmethod
363
+ def parse (cls , string ):
364
+
365
+ """
366
+ Returns the tuple containig the 4 segments (i.e major, minor, build, patch) of Legacy Version,
367
+ False if not valid Legacy Openssl Version.
368
+
369
+ For example::
370
+ >>> LegacyOpensslVersion.parse("1.0.1f")
371
+ (1, 0, 1, 'f')
372
+ >>> LegacyOpensslVersion.parse("1.0.2ac")
373
+ (1, 0, 2, 'ac')
374
+ >>> LegacyOpensslVersion.parse("2.0.2az")
375
+ False
376
+ """
377
+
378
+ # All legacy base version of openssl that ever exited/exists.
379
+ all_legacy_base = (
380
+ "0.9.1" ,
381
+ "0.9.2" ,
382
+ "0.9.3" ,
383
+ "0.9.4" ,
384
+ "0.9.5" ,
385
+ "0.9.6" ,
386
+ "0.9.7" ,
387
+ "0.9.8" ,
388
+ "1.0.0" ,
389
+ "1.0.1" ,
390
+ "1.0.2" ,
391
+ "1.1.0" ,
392
+ "1.1.1" ,
393
+ )
394
+ # check if the starting with valid base
395
+ if not string .startswith (all_legacy_base ):
396
+ return False
397
+
398
+ segments = string .split ("." )
399
+ if not len (segments ) == 3 :
400
+ return False
401
+ major , minor , build = segments
402
+ major = int (major )
403
+ minor = int (minor )
404
+ if build .isdigit ():
405
+ build = int (build )
406
+ patch = ""
407
+ else :
408
+ patch = build [1 :]
409
+ build = int (build [0 ])
410
+ if patch and patch [0 ].isdigit ():
411
+ return False
412
+ return major , minor , build , patch
413
+
414
+ @classmethod
415
+ def build_value (cls , string ):
416
+ return cls .parse (string )
417
+
418
+ def __str__ (self ):
419
+ return self .normalized_string
420
+
421
+
422
+ @attr .s (frozen = True , order = False , eq = False , hash = True )
423
+ class OpensslVersion (Version ):
424
+
425
+ """
426
+ Openssl intenally tracks two types of openssl versions
427
+ - Legacy versions: Implemented in LegacyOpensslVersion
428
+ - New versions: Semver
429
+ For example::
430
+ >>> old = OpensslVersion("1.1.0f")
431
+ >>> new = OpensslVersion("3.0.1")
432
+ >>> assert old == OpensslVersion(string="1.1.0f")
433
+ >>> assert new == OpensslVersion(string="3.0.1")
434
+ >>> assert old.value == LegacyOpensslVersion(string="1.1.0f")
435
+ >>> assert new.value == SemverVersion(string="3.0.1")
436
+ >>> OpensslVersion("1.2.4fg")
437
+ Traceback (most recent call last):
438
+ ...
439
+ univers.versions.InvalidVersion: '1.2.4fg' is not a valid <class 'univers.versions.OpensslVersion'>
440
+ """
441
+
442
+ @classmethod
443
+ def is_valid (cls , string ):
444
+ return cls .is_valid_new (string ) or cls .is_valid_legacy (string )
445
+
446
+ @classmethod
447
+ def build_value (cls , string ):
448
+ """
449
+ Return a wrapped version "value" object depending on
450
+ whether version is legacy or semver.
451
+ """
452
+ if cls .is_valid_legacy (string ):
453
+ return LegacyOpensslVersion (string )
454
+ if cls .is_valid_new (string ):
455
+ return SemverVersion (string )
456
+
457
+ @classmethod
458
+ def is_valid_new (cls , string ):
459
+ """
460
+ Checks the validity of new Openssl Version.
461
+
462
+ For example::
463
+ >>> OpensslVersion.is_valid_new("1.0.1f")
464
+ False
465
+ >>> OpensslVersion.is_valid_new("3.0.0")
466
+ True
467
+ >>> OpensslVersion.is_valid_new("3.0.2")
468
+ True
469
+ """
470
+ if SemverVersion .is_valid (string ):
471
+ sem = semantic_version .Version .coerce (string )
472
+ return sem .major >= 3
473
+
474
+ @classmethod
475
+ def is_valid_legacy (cls , string ):
476
+ return LegacyOpensslVersion .is_valid (string )
477
+
478
+ def __eq__ (self , other ):
479
+ if not isinstance (other , self .__class__ ):
480
+ return NotImplemented
481
+ if not isinstance (other .value , self .value .__class__ ):
482
+ return NotImplemented
483
+ return self .value .__eq__ (other .value )
484
+
485
+ def __lt__ (self , other ):
486
+ if not isinstance (other , self .__class__ ):
487
+ return NotImplemented
488
+ if isinstance (other .value , self .value .__class__ ):
489
+ return self .value .__lt__ (other .value )
490
+ # By construction legacy version is always behind Semver
491
+ return isinstance (self .value , LegacyOpensslVersion )
492
+
493
+ def __gt__ (self , other ):
494
+ if not isinstance (other , self .__class__ ):
495
+ return NotImplemented
496
+ if isinstance (other .value , self .value .__class__ ):
497
+ return self .value .__gt__ (other .value )
498
+ # By construction semver version is always ahead of legacy
499
+ return isinstance (self .value , SemverVersion )
500
+
501
+ def __le__ (self , other ):
502
+ if not isinstance (other , self .__class__ ):
503
+ return NotImplemented
504
+ if isinstance (other .value , self .value .__class__ ):
505
+ return self .value .__le__ (other .value )
506
+ # if both the are dif version, then legacy one is always behind semver
507
+ return isinstance (self .value , LegacyOpensslVersion )
508
+
509
+ def __ge__ (self , other ):
510
+ if not isinstance (other , self .__class__ ):
511
+ return NotImplemented
512
+ if isinstance (other .value , self .value .__class__ ):
513
+ return self .value .__ge__ (other .value )
514
+ return isinstance (self .value , SemverVersion )
0 commit comments