Package platformids

Source Code for Package platformids

   1  # -*- coding: utf-8 -*- 
   2  """The package 'platformids' provides canonical enumerations of bit encoded numeric platform IDs 
   3  for the Python implementations CPython, IPython, IronPython, Jython, and PyPy. 
   4  """ 
   5  ############################################# 
   6  # 
   7  # See manuals for the detailed API. 
   8  # 
   9  ############################################# 
  10   
  11  from __future__ import absolute_import 
  12   
  13  import os 
  14  import sys 
  15  import re 
  16  import platform 
  17   
  18  # 
  19  # load Python syntax and implementation basics - requires support by 'pythonids.pythondist' 
  20  # 
  21  from pythonids import PYV35Plus,ISSTR, PYVxyz, PYV33, PYV2 
  22  from pythonids.pythondist import isJython, ISINT, PYDIST, PYE_DIST, PYE_JYTHON 
  23  from yapyutils.modules.loader import get_modulelocation, load_module 
  24   
  25   
  26  __author__ = 'Arno-Can Uestuensoez' 
  27  __license__ = "Artistic-License-2.0 + Forced-Fairplay-Constraints" 
  28  __copyright__ = "Copyright (C) 2010-2018 Arno-Can Uestuensoez" \ 
  29                  " @Ingenieurbuero Arno-Can Uestuensoez" 
  30  __version__ = '0.1.31' 
  31  __uuid__ = "7add5ded-c39b-4b6e-8c87-1b3a1c150ee9" 
  32   
  33  __docformat__ = "restructuredtext en" 
  34   
  35  # central debug and verbose control of curretn package 
  36  _debug = 0 
  37  _verbose = 0 
  38   
  39  # 
  40  # static pre-compiled scanner 
  41  # 
  42   
  43  # version conversion and normalization 
  44  DSKORG_ID = re.compile(r'^(?s)ID=["\']*([^"\'\n\r]*).*') 
  45  DSKORG_ID_LIKE = re.compile(r'^(?s)ID_LIKE=["\']*([^"\'\n\r]*).*') 
  46  DSKORG_NAME_RELEASE = re.compile(r'(?s)^NAME=["\']*([^ ]*) *([^"\']*).*') 
  47  DSKORG_RELEASE = re.compile(r'(?s)^VERSION=["\']*([^"\']*)["\']*[^(]*[(]*([^)]*)[)]*.*') 
  48  DSKORG_VERSION = re.compile(r'(?s)^VERSION=["\']*([^"\']*)["\']*.*') 
  49  PRENONNUM = re.compile(r'([^0-9]+[^ \t0-9]).*') 
  50  VERSION_ID = re.compile(r'(?s)^VERSION_ID=["\']*([^"\']*)["\']*.*') 
  51  VERSNUM = re.compile(r'([0-9]+)[.]*([0-9]*)[.]*([0-9]*)') 
  52   
  53   
  54  # 
  55  # shared exceptions 
  56  # 
57 -class PlatformIDsError(Exception):
58 """Subsystem *PlatformIDs*.""" 59 pass
60 61
62 -class PlatformIDsEnumerationError(PlatformIDsError):
63 """Enumeration of dynamic assigned values.""" 64 pass
65 66
67 -class PlatformIDsUnknownError(PlatformIDsError):
68 """Unknown value.""" 69 pass
70 71
72 -class PlatformIDsPresentError(PlatformIDsError):
73 """Item already present, prohibited in strict mode.""" 74 pass
75 76
77 -class PlatformIDsCustomError(PlatformIDsError):
78 """No more custom keys are available.""" 79 pass
80 81
82 -class PlatformIDsKeyError(PlatformIDsError):
83 """Key invalid.""" 84 pass
85 86 87 # 88 # prepare Jython vs. others - the most significant impact on available libraries 89 # 90 if not isJython: 91 try: 92 osname = os.name 93 except AttributeError: 94 # e.g. CirctuiPython, MicroPython 95 raise NotImplementedError('requires special module') 96 97 if PYV35Plus: 98 PlatformIDsFileCheck = (FileNotFoundError,) # @UndefinedVariable 99 100 else: 101 PlatformIDsFileCheck = (Exception,) 102 103 else: 104 osname = os._name # @UndefinedVariable # set to the platform name 105 PlatformIDsFileCheck = (IOError,) # @UndefinedVariable 106 107 108 RTE = 0 #: the numeric bitmask record 109 110 # 111 # current platform as bit-array with following bitmasks 112 # 113 RTE_CATEGORY_B = 0xf0000000 # : bit: 31-28 114 RTE_OSTYPE_B = 0x0f800000 # : bit: 27-23 115 RTE_DIST_B = 0x007f0000 # : bit: 22-16 116 RTE_DISTREL_B = 0x0000ffff # : bit: 15-0 117 118 RTE_CATEGORY_OFFSET = 0x0fffffff # : bit: 28 119 RTE_OSTYPE_OFFSET = 0x007fffff # : bit: 23 120 RTE_DIST_OFFSET = 0x0000ffff # : bit: 16 121 RTE_DISTREL_OFFSET = 0x00000000 # : bit: 0 122 123 RTE_CATEGORY_SHIFT = 28 # : bit: 28 124 RTE_OSTYPE_SHIFT = 23 # : bit: 23 125 RTE_DIST_SHIFT = 16 # : bit: 16 126 RTE_DISTREL_SHIFT = 0 # : bit: 0 127 128 RTE_CATEGORY = 0xf0000000 # : bit: 31-28 129 RTE_OSTYPE = 0xff800000 # : bit: 31-23 130 RTE_DIST = 0xffff0000 # : bit: 31-16 131 RTE_DISTREL = 0xffffffff # : bit: 31-0 132 133 # 134 # Distribution with optional non-standard version scheme and optional callback 135 # the value is used as common offset for the *dist* defines 136 # 137 RTE_DISTEXT = 0x00400000 # : bit: 22 flag for distribution schemes with optional callback 138 139 # 140 # category 141 # 142 RTE_POSIX = 0x10000000 # : Posix systems using *fcntl* [POSIX]_. 143 RTE_WIN32 = 0x20000000 # : all Windows systems 144 RTE_WIN = 0x20000000 # : all Windows systems 145 RTE_WINDOWS = 0x20000000 # : all Windows systems 146 RTE_EMU = 0x40000000 # : Logical Emulation Layer - Meta-Category providing a bit 147 RTE_PWEMU = 0x70000000 # : Cygwin [CYGWIN]_ - special virtual environment 148 RTE_WPEMU = 0x50000000 # : Windows emulation on Posix 149 RTE_EMBEDDED = 0x80000000 # : Embedded OS/dist 150 151 152 # 153 # ostype 154 # 155 156 # context: RTE_WIN32 157 RTE_NT = RTE_WIN32 + 0x00800000 # : all Windows workstation systems 158 159 RTE_CYGWINNT = RTE_PWEMU + 0x00800000 # : all Windows workstation systems - the 'os.uname' is 'posix' 160 161 # context: RTE_POSIX 162 RTE_LINUX = RTE_POSIX + 0x00800000 # : all LINUX systems 163 RTE_BSD = RTE_POSIX + 0x01000000 # : all BSD systems 164 RTE_DARWIN = RTE_POSIX + 0x02000000 # : Darwin, as Posix OS/Core system 165 RTE_UNIX = RTE_POSIX + 0x04000000 # : all UNIX systems 166 167 # 168 # dist 169 # 170 171 # context: RTE_POSIX.RTE_LINUX - standard distributions 172 RTE_FEDORA = RTE_LINUX + 0x00010000 # : Fedora 173 RTE_CENTOS = RTE_LINUX + 0x00020000 # : CentOS 174 RTE_DEBIAN = RTE_LINUX + 0x00030000 # : Debian 175 RTE_RHEL = RTE_LINUX + 0x00040000 # : RedHat Enterprise Linux 176 RTE_SLES = RTE_LINUX + 0x00050000 # : Suse Enterprise Linux 177 RTE_UBUNTU = RTE_LINUX + 0x00060000 # : Ubuntu 178 179 RTE_OPENWRT = RTE_LINUX + 0x00070000 # : OpenWRT 180 RTE_RASPBIAN = RTE_LINUX + 0x00080000 # : Raspbian 181 182 # 183 # *** rolling distributions *** 184 # 185 RTE_KALI = RTE_LINUX + RTE_DISTEXT + 0x00010000 # : Kali Linux - rolling dist 186 RTE_ARCHLINUX = RTE_LINUX + RTE_DISTEXT + 0x00020000 #: ArchLinux - rolling dist 187 188 # context: RTE_POSIX.RTE_UNIX 189 RTE_SUNOS5 = RTE_UNIX + 0x00020000 # : UNIX/SunOS5 is Solaris 190 RTE_SOLARIS = RTE_SUNOS5 # : UNIX/SunOS5 is Solaris 191 192 # context: RTE_POSIX.RTE_DARWIN 193 RTE_OSX = RTE_DARWIN + 0x00020000 # : Mac OS-X RTE_OSX is basically the short form of RTE_OSX10 194 RTE_OSX10 = RTE_OSX # : Mac OS-X v10.x, as Posix system [POSIX]_, no macpath-legacy. 195 196 # context: RTE_POSIX.RTE_BSD 197 RTE_OPENBSD = RTE_BSD + 0x00020000 # : OpenBSD 198 199 # 200 # category - perform basic platform identification 201 # 202 if 'posix' == osname: # unix, linux, bsd, osx 203 if platform.system().startswith('CYGW'): 204 # Cygwin 205 category = RTE_PWEMU 206 else: 207 category = RTE_POSIX 208 209 # TODO" RTE_WPEMU 210 211 elif 'nt' == osname: # modern windows 212 category = RTE_WIN32 213 214
215 -class ProtectedDict(dict):
216 """Implements a 'dict' with protection against modification of items. This is 217 in order to protect a repository from erroneous modifications of it's 218 entries by malicious code. The deletion is still supported, which is 219 considered as intentional, thus done beeing aware of the consequences. 220 221 The main intention for the *platformids* is to avoid inconsistencies of 222 hard-coded values of assigned enumerations by runtime redefinitions. 223 Unintentional redefinitions also may proof as hard to debug. 224 225 The member attribute *self.strict_check* controls how new items are added: 226 227 0. single new item: 228 add silently 229 230 1. single item which is already present: 231 * strict_check == True: raises exception 232 * strict_check == False: ignores silently 233 234 2. set of items, where none of the new set is present: 235 add silently 236 237 3. set of items, where at least one is present: 238 * strict_check == True: raises exception 239 * strict_check == False: add silently new, ignore present silently 240 241 242 The common variables such as central dictionaries are thus read-only protected 243 during the runtime of the process. The response style for the attempt to alter 244 a value could be modified - raised to a stronger level - by the attribute 245 'strict_check', which raises an exception once set. 246 """
247 - def __init__(self, *args, **kargs):
248 """ 249 Args: 250 args: 251 pass-through to dict 252 253 kargs: 254 non-defined are passed-through to dict 255 256 int_keys_only: 257 Controls type of valid keys. :: 258 259 int_keys_only := ( 260 True # permits interger keys only 261 | False # permits any valid *dict* key 262 ) 263 264 strict_check: 265 Defines the handling of values for present keys. :: 266 267 True: when True raises exception for present 268 items, 269 270 False: silently ignores new values for present 271 items 272 273 Returns: 274 Initialized object, or raises exception. 275 276 Raises: 277 pass-through 278 279 """ 280 self.strict_check = kargs.get('strict_check', False) 281 try: 282 kargs.pop('strict_check') 283 except: 284 pass 285 286 self.int_keys_only = kargs.get('int_keys_only', False) 287 try: 288 kargs.pop('int_keys_only') 289 except: 290 pass 291 292 super(ProtectedDict, self).__init__(*args, **kargs)
293
294 - def __delattr__(self, name):
295 "" 296 if name in ('strict_check_reset', 'strict_check',): 297 raise PlatformIDsCustomError("deletion not permitted for attribute: " + str(name)) 298 return dict.__delattr__(self, name)
299
300 - def __setattr__(self, name, value):
301 """Filters and controls attribute values to be set. 302 303 Args: 304 name: 305 Sets the attribute named by *name*. Establishes special 306 handling for the in-band control attributes. 307 308 **strict_check**: 309 The value can only be raised to *True* in order to 310 strengthen the strictness. 311 312 **strict_check_reset**: 313 If the value is set to *True*, than the member attribute 314 '*strict_check*' is set to *False*. 315 316 Else calls '*dict.__setattr__*'. 317 318 value: 319 The value is passed through to *dict*, see also for special 320 values of *name*. 321 322 Returns: 323 Either filters defined control attributes - see *name*, or 324 calls *dict.__setattr__*. 325 326 Raises: 327 pass-through 328 329 """ 330 if name == 'strict_check_reset' and value == True: 331 return dict.__setattr__(self, 'strict_check', False) 332 333 elif name == 'strict_check': 334 if self.__dict__.get('strict_check'): 335 if value != True: 336 return 337 # initial value, this could later only be modified to the 'stronger' True 338 return dict.__setattr__(self, name, value) 339 340 return dict.__setattr__(self, name, value)
341
342 - def __setitem__(self, key, value):
343 """Filter for already present mappings controlled by the 344 member *strict_check*. 345 346 Args: 347 name: 348 Sets the item named by *name*. Controlled by 349 the attribute *strict_check*. :: 350 351 self.strict_check := ( 352 True # permits only creation of non-present 353 | False # normal behaviour 354 ) 355 356 Dependent on the presence raises an exception when 357 strict is enabled. 358 359 value: 360 The value is passed through to *dict*, see also for special 361 values of *name*. 362 363 Returns: 364 dict.__setitem__ 365 366 Raises: 367 PlatformIDsPresentError 368 Conditional based on *strict_check*, if *True* raises 369 for present attributes *PlatformIDsPresentError*. 370 371 PlatformIDsKeyError 372 For non-int keys when *int_keys_only* is set. 373 374 pass-through 375 376 """ 377 try: 378 if dict.__getitem__(self, key): 379 if self.strict_check: 380 raise PlatformIDsPresentError("key-present: " + str(key)) 381 return 382 except KeyError: 383 if self.int_keys_only and type(key) not in ISINT: 384 raise PlatformIDsKeyError("Integer keys only: " + str(key)) 385 386 return dict.__setitem__(self, key, value)
387
388 - def update(self, dict2, *args, **kargs):
389 """Adds a set of items, filters each for presence. 390 391 * none of the new set is present: 392 adds all silently 393 394 * at least one is present: 395 * strict_check == True: raises exception 396 * strict_check == False: add silently 397 398 Args: 399 400 dict2: 401 Adds items controlled by the attribute *strict_check*. :: 402 403 self.strict_check := ( 404 True # permits only creation of non-present 405 | False # normal behaviour 406 ) 407 408 Dependent on the presence of at least one raises an 409 exception when strict is enabled. 410 411 args: 412 Passed to *dict.update*. 413 414 kargs: 415 Passed to *dict.update*. 416 417 Returns: 418 dict.update or None 419 420 Raises: 421 PlatformIDsPresentError 422 Conditional based on *strict_check*, if *True* raises 423 for present attributes *PlatformIDsPresentError*. 424 425 PlatformIDsKeyError 426 For non-int keys when *int_keys_only* is set. 427 428 pass-through 429 430 """ 431 432 # should not be called frequently, thus ok. 433 if self.int_keys_only: 434 for k in dict2.keys(): 435 if type(k) not in ISINT: 436 if isJython: 437 try: 438 if type(k) is not long: # @UndefinedVariable 439 raise PlatformIDsKeyError("Numeric keys only: " + str(k)) 440 except: 441 pass 442 else: 443 raise PlatformIDsKeyError("Numeric keys only: " + str(k)) 444 445 if set(self.keys()) & set(dict2.keys()): 446 # has keys already present 447 448 if self.strict_check: 449 # strict is enabled 450 _str = [] 451 452 # get list of present keys 453 for x in set(self.keys()) & set(dict2.keys()): 454 if type(x) in ISSTR: 455 _str.append(x) 456 else: 457 _str.append(str(x)) 458 459 # notify with complete list 460 raise PlatformIDsPresentError( 461 "keys-present:\n %s\n" % ( 462 str(sorted(_str)))) 463 464 else: 465 # not in strict mode, thus normal procedure 466 467 common = set(self.keys()) & set(dict2.keys()) 468 for k, v in dict2.items(): 469 if type(k) in common: 470 continue 471 self[k] = v 472 473 else: 474 # normal procedure 475 return super(ProtectedDict, self).update(dict2, *args, **kargs)
476 477
478 -class ProtectedDictEnum(ProtectedDict):
479 """Implements the dynamic creation and management of numeric enumeration 480 values. These are used as dynamic assigned constants with the life time 481 of the process itself. The enums are optimized to be used in conjunction 482 with numeric bitmask vectors. 483 The values are created on-demand, e.g. for dynamic loaded packages, and 484 could be removed when no longer required. Thus are released than for the 485 reuse. 486 487 The management of the unused numeric values for assignment is performed 488 by two levels. 489 490 0. The value is managed by a protected counter within the defined range. 491 1. Once the values are exhausted, the dictionary is used as release map. 492 This is required due to the possible storage of the values by the 493 application, thus assigned values cannot be reassigned and though 494 the ranges could become used sparse. 495 496 This level is much slower, though it is based on the lookup and remove 497 form the unused-map. 498 And of course, previous releases has to be present |smilecool|. 499 500 Anyhow, e.g. in case of *platformids* for the *ostype* 501 and *dist* the ranges for the additional dynamic assigments in are 502 about 100 for the distribution *dist*, about 25 for the OS 503 type *ostype*, and about 12 for the category *category*. This should be 504 in practical realworld use-cases more than sufficient. 505 506 507 REMARK: Implemented as *dict* for coming extensions. 508 509 """
510 - def __init__(self, **kargs):
511 """Initializes key reservation. 512 The custom range values has to comply to the bitmask segments. 513 These define the minimal and maximal values in accordance to the common ranges 514 by the mathematical notation: 515 516 .. parsed-literal:: 517 518 values := [custom_min, custom_max) # excluding custom_max 519 520 The values could be processed by the application of the helper constants, 521 see :ref:`Helper Constants <BITMASK_HELPERCONSTS>`. 522 E.g. in case of *dist* for the *ostype* context of *RTE_LINUX* : 523 524 .. parsed-literal:: 525 526 custom_min == ((RTE_LINUX + RTE_DISTEXT + RTE_DIST_OFFSET + 0) & RTE_DIST_B) 527 custom_max == ((RTE_LINUX + RTE_DISTEXT + RTE_DIST_OFFSET + 126) & RTE_DIST_B) 528 529 or 530 531 .. parsed-literal:: 532 533 (custom_min >> 16) == 0 534 (custom_max >> 16) == 126 535 536 537 538 The caller is responsible for the appropriate values. 539 540 Args: 541 kargs: 542 default pass-through to dict 543 544 custom_max: 545 Defines the maximum of custom range. 546 When missing no custom range os available. 547 548 .. parsed-literal:: 549 550 custom_max > custom_min 551 552 default := None 553 554 custom_min: 555 Defines the minimum of custom range. 556 When missing no custom range os available. 557 558 default := None 559 560 custom_offset: 561 Defines the offset for the increment and decrement. 562 This is required e.g. in case of bitmask fields 563 with segments starts at bits greater than 0. 564 565 default := 0 566 567 Returns: 568 Initialized object, or raises exception. 569 570 Raises: 571 PlatformIDsEnumerationError 572 Erroneous custom range is provided. 573 574 pass-through 575 576 """ 577 ProtectedDict.__setattr__(self, 'custom_offset', kargs.get('custom_offset', 0)) 578 try: 579 # drop for parent __init__ 580 kargs.pop('custom_offset') 581 except: 582 pass 583 584 # : the last permitted reservation 585 _cm = kargs.get('custom_max', 0) 586 ProtectedDict.__setattr__(self, 'custom_max', _cm) 587 588 try: 589 # drop for parent __init__ 590 kargs.pop('custom_max') 591 592 # the current 593 ProtectedDict.__setattr__(self, 'reserved', _cm) 594 except: 595 # the current 596 ProtectedDict.__setattr__(self, 'reserved', _cm) 597 598 ProtectedDict.__setattr__(self, 'custom_min', kargs.get('custom_min', 0)) 599 try: 600 # drop for parent __init__ 601 kargs.pop('custom_min') 602 except: 603 pass 604 605 if self.custom_min > self.custom_max or (self.custom_min == self.custom_max and self.custom_min != 0): 606 raise PlatformIDsEnumerationError( 607 "Invalid custom range min = %s - max = %s" % (str(self.custom_min), str(self.custom_max)) 608 ) 609 610 kargs['int_keys_only'] = True 611 super(ProtectedDictEnum, self).__init__(**kargs) 612 613 # deleted non-continous entries 614 self.free = {}
615
616 - def __delitem__(self, enum):
617 """Prohibits unmanaged access to the enum pool, use method *delete_enum* instead for 618 managed release. 619 620 Args: 621 enum: 622 Enum key. 623 624 Returns: 625 Raises exception. 626 627 Raises: 628 PlatformIDsCustomError 629 630 """ 631 raise PlatformIDsCustomError("prohibits unmanaged access, use method delete_enum")
632
633 - def __delattr__(self, name):
634 """Protects the enumeration management attributes from deletion. 635 636 Args: 637 name: 638 Excludes reserved attributes from deletion. :: 639 640 name :=( 641 'reserved' 642 | 'custom_min' 643 | 'custom_max' 644 ) 645 646 Returns: 647 None 648 649 Raises: 650 PlatformIDsEnumerationError 651 652 pass-through 653 654 """ 655 if name in ('reserved', 'custom_min', 'custom_max',): 656 raise PlatformIDsEnumerationError("attribute cannot be deleted: " + str(name)) 657 return ProtectedDict.__delattr__(self, name)
658
659 - def __setattr__(self, name, value):
660 """Protects the enumeration management attributes from non-managed 661 direct access. 662 663 Args: 664 name: 665 Excludes reserved attributes from direct access. :: 666 667 name :=( 668 'reserved' 669 | 'custom_min' 670 | 'custom_max' 671 ) 672 673 value: 674 Value to be set. 675 676 Returns: 677 None 678 679 Raises: 680 PlatformIDsEnumerationError 681 682 pass-through 683 684 """ 685 if name in ('reserved', 'custom_min', 'custom_max',): 686 raise PlatformIDsEnumerationError("attribute cannot be set direct: " + str(name)) 687 return ProtectedDict.__setattr__(self, name, value)
688
689 - def __setitem__(self, enum, value):
690 """Prohibits unmanaged access to the enum pool, use method *add_enum* instead for 691 managed release. 692 693 Args: 694 enum: 695 Enum key. 696 Returns: 697 Raises exception. 698 699 Raises: 700 PlatformIDsCustomError 701 702 """ 703 raise PlatformIDsCustomError("prohibits unmanaged access, use method add_enum")
704
705 - def add_enum(self, value=True):
706 """Reserves and assigns the next free unique key to the 707 value. The assigned key value is returned for use. 708 Custom ranges are available when the values *custom_max* 709 and *custom_min* are initialized appropriately. 710 711 Args: 712 None. 713 714 Returns: 715 Either returns the reserved key, or raises exception when range is exhausted. 716 717 Raises: 718 PlatformIDsCustomError: 719 No custom ranges are configured. 720 721 PlatformIDsEnumerationError 722 The configured range is exhausted. 723 724 pass-through 725 726 """ 727 if self.free: 728 # reuse released first 729 730 _x = self.free.popitem() 731 ProtectedDict.__setitem__(self, _x[0], value) 732 return _x[0] 733 734 else: 735 if not self.reserved: # 0 is non active 736 raise PlatformIDsCustomError( 737 "No custom ranges are available" 738 ) 739 740 if self.reserved <= self.custom_min: 741 raise PlatformIDsEnumerationError( 742 "custom range exhausted" 743 ) 744 745 # get next key 746 ProtectedDict.__setattr__(self, 'reserved', self.reserved - self.custom_offset - 1) 747 748 # add value 749 ProtectedDict.__setitem__(self, self.reserved, value) 750 751 # return key for use 752 return self.reserved
753
754 - def check_next_free_enum(self):
755 """Checks and returns the next free value. 756 757 **Does not reserve, just displays next.** 758 759 Args: 760 None 761 762 Returns: 763 Value to be used by next call of *add_enum*. 764 765 Raises: 766 PlatformIDsCustomError: 767 No custom ranges are configured. 768 769 PlatformIDsEnumerationError 770 Range exhausted, no free values are available. 771 772 """ 773 if not self.reserved: # 0 is non active 774 raise PlatformIDsCustomError( 775 "No custom ranges are available" 776 ) 777 778 if self.reserved > self.custom_min: 779 return self.reserved # - self.custom_offset - 1 780 781 raise PlatformIDsEnumerationError( 782 "Reserved range exhausted." 783 )
784
785 - def purge(self, **kargs):
786 """Clears the list of deleted non-continous enums. 787 Deletes all entries in the release map, which could be added 788 incremental and continous to the reserved-list of vallues 789 beginning at from *custom_min*. 790 This re-initializes for the purged items the pure numeric first level 791 assignement by ranges - spares for these the lookup in the non-continous 792 list. 793 794 Args: 795 kargs: 796 maxrel: 797 Maximum to be released. 798 799 minrel: 800 Minimum to be released. 801 802 Returns: 803 Returns the number of actual releases. 804 805 Raises: 806 PlatformIDsEnumerationError: 807 Could not fulfil *minrel*. 808 809 pass-through 810 811 """ 812 minrel = kargs.get('minrel', 0) 813 maxrel = kargs.get('maxrel', len(self.free)) 814 815 relcnt = 0 816 817 _n = len(self.free) 818 819 for enum in sorted(self.free.keys()): 820 if enum == self.reserved: 821 # continous optimization at low-cost 822 ProtectedDict.__setattr__(self, 'reserved', enum + self.custom_offset + 1) 823 self.free.pop(enum) 824 relcnt += 1 825 maxrel -= 1 826 if not maxrel: 827 break 828 829 else: 830 # needs continous ranges beginning at self.custom_min / self.reserved 831 break 832 833 if minrel: 834 if relcnt < minrel: 835 raise PlatformIDsEnumerationError( 836 "Could not release requested range: req = %d / done = %d / free = %d" % ( 837 minrel, 838 relcnt, 839 (self.reserved - self.custom_min), 840 ) 841 ) 842 843 return relcnt
844
845 - def delete_enum(self, enum):
846 """Releases a given enum, either continous values by changing the reserved values, 847 or by adding a non-continous values to the dict of released items. 848 The non-continous released items could be cleared by the method *purge*. 849 850 Args: 851 enum: 852 Enum key. 853 854 Returns: 855 None. 856 857 Raises: 858 pass-through 859 860 """ 861 if enum == self.reserved: 862 # continous optimization at low-cost 863 ProtectedDict.__setattr__(self, 'reserved', enum + self.custom_offset + 1) 864 self.pop(enum) 865 return True 866 867 self.free[enum] = self.pop(enum) 868 return True
869
870 - def update(self, dict2, *args, **kargs):
871 """Prohibits updates. 872 This is required in order to avoid arbitrary updates which simply 873 would complicate the management and assignment of further values. 874 Thus only individual values could be added and removed. 875 876 Args: 877 None. 878 879 Returns: 880 Raises Exception. 881 882 Raises: 883 PlatformIDsEnumerationError 884 885 """ 886 raise PlatformIDsCustomError("operation not permitted: update")
887 888 889 # : mapping of the rte string and numeric representation to the numeric value 890 rte2num = ProtectedDict( 891 { 892 'bsd': RTE_BSD, 893 'darwin': RTE_DARWIN, 894 'emu': RTE_EMU, 895 'linux': RTE_LINUX, 896 'linux2': RTE_LINUX, 897 'nt': RTE_NT, 898 'wpemu': RTE_WPEMU, 899 'posix': RTE_POSIX, 900 'pwemu': RTE_PWEMU, 901 'unix': RTE_UNIX, 902 'win': RTE_WIN32, 903 'win32': RTE_WIN32, 904 'windows': RTE_WINDOWS, 905 RTE_BSD: RTE_BSD, 906 RTE_DARWIN: RTE_DARWIN, 907 RTE_EMU: RTE_EMU, 908 RTE_LINUX: RTE_LINUX, 909 RTE_NT: RTE_NT, 910 RTE_WPEMU: RTE_WPEMU, 911 RTE_POSIX: RTE_POSIX, 912 RTE_PWEMU: RTE_PWEMU, 913 RTE_WIN32: RTE_WIN32, 914 RTE_WINDOWS: RTE_WINDOWS, 915 916 # 917 # frequent used current subsets 918 # 919 'SunOS5': RTE_SOLARIS, 920 'arch': RTE_ARCHLINUX, 921 'archlinux': RTE_ARCHLINUX, 922 'centos': RTE_CENTOS, 923 'debian': RTE_DEBIAN, 924 'fedora': RTE_FEDORA, 925 'openbsd': RTE_OPENBSD, 926 'openwrt': RTE_OPENWRT, 927 'osx': RTE_OSX, 928 'osx10': RTE_OSX10, 929 'raspbian': RTE_RASPBIAN, 930 'rhel': RTE_RHEL, 931 'solaris': RTE_SOLARIS, 932 RTE_ARCHLINUX: RTE_ARCHLINUX, 933 RTE_CENTOS: RTE_CENTOS, 934 RTE_DEBIAN: RTE_DEBIAN, 935 RTE_FEDORA: RTE_FEDORA, 936 RTE_OPENBSD: RTE_OPENBSD, 937 RTE_OPENWRT: RTE_OPENWRT, 938 RTE_OSX10: RTE_OSX10, 939 RTE_OSX: RTE_OSX, 940 RTE_RASPBIAN: RTE_RASPBIAN, 941 RTE_RHEL: RTE_RHEL, 942 RTE_SOLARIS: RTE_SOLARIS, 943 } 944 ) 945 946 # : mapping of the rte numeric representation to the string value 947 # num2rte = { 948 num2rte = ProtectedDict( 949 { 950 RTE_ARCHLINUX: 'archlinux', 951 RTE_BSD: 'bsd', 952 RTE_CENTOS: 'centos', 953 RTE_DARWIN: 'darwin', 954 RTE_DEBIAN: 'debian', 955 RTE_EMU: 'emu', 956 RTE_FEDORA: 'fedora', 957 RTE_LINUX: 'linux', 958 RTE_NT: 'nt', 959 RTE_OPENBSD: 'openbsd', 960 RTE_OPENBSD: 'openbsd', 961 RTE_OPENWRT: 'openwrt', 962 RTE_OSX10: 'osx10', 963 RTE_WPEMU: 'wpemu', 964 RTE_POSIX: 'posix', 965 RTE_PWEMU: 'pwemu', 966 RTE_RASPBIAN: 'raspbian', 967 RTE_RHEL: 'rhel', 968 RTE_SOLARIS: 'solaris', 969 RTE_UNIX: 'unix', 970 RTE_WIN32: 'win32', 971 RTE_WINDOWS: 'windows', 972 } 973 ) 974 975 # : For UI of command line tools, load on demand by update() 976 # : see platformids.map_enum_labels 977 num2enumstr = ProtectedDict( 978 { 979 # RTE_POSIX: "RTE_POSIX", 980 # RTE_WINDOWS: "RTE_WINDOWS", 981 } 982 ) 983 984 # : mapping of the rte numeric representation to the pretty string value 985 # num2pretty = { 986 num2pretty = ProtectedDict( 987 { 988 RTE_ARCHLINUX: 'Arch Linux', 989 RTE_BSD: "Berkeley Software Distribution", 990 RTE_CENTOS: "CentOS", 991 RTE_DARWIN: "Darwin", 992 RTE_DEBIAN: "Debian", 993 RTE_FEDORA: "Fedora", 994 RTE_LINUX: "Linux", 995 RTE_NT: "NT", 996 RTE_OPENBSD: "OpenBSD", 997 RTE_WPEMU: "Windows-Emulation", 998 RTE_POSIX: "POSIX", 999 RTE_PWEMU: "POSIX-Windows-Emulation", 1000 RTE_RASPBIAN: "Raspbian", 1001 RTE_RHEL: "RHEL", 1002 RTE_UNIX: "Unix", 1003 RTE_WIN32: "Windows", 1004 RTE_WIN: "Windows", 1005 RTE_WINDOWS: "Windows", 1006 } 1007 ) 1008 1009 # : registered callbacks for special handling of custom layout 1010 custom_rte_distrel2tuple = ProtectedDict( 1011 { 1012 # e.g. RTE_MINIX3: minix.platformids.my_distrel2tuple, 1013 } 1014 ) 1015 1016 # : dynamic registry for custom *category* 1017 custom_category = ProtectedDictEnum( 1018 custom_min=0x90000000, 1019 custom_max=0xf0000000, 1020 custom_offset=0x0fffffff, 1021 ) 1022 1023 # : dynamic registry for custom *ostype* 1024 custom_ostype = ProtectedDictEnum( 1025 custom_min=0x08000000, 1026 custom_max=0x0f800000, 1027 custom_offset=0x007fffff, 1028 ) 1029 1030 # : dynamic registry for custom *dist* 1031 custom_dist = ProtectedDictEnum( 1032 custom_min=0x00410000, 1033 custom_max=0x007f0000, 1034 custom_offset=0x0000ffff, 1035 ) 1036 1037
1038 -def get_modlocation(mname, mbase=None, mpaths=None, **kargs):
1039 """ Calls the *pythonids.get_modulelocation* function with specific default parameters 1040 for the *platformids*. 1041 1042 Args: 1043 mbase: 1044 Base for module search paths by default within the subdirectory of *platformids*. 1045 The filepath name with a trailing separator. :: 1046 1047 default := os.path.dirname(__file__) + os.sep 1048 1049 The base path is used within the post-processing of the eventually matched 1050 path, thus has to be appropriate for each item of *mpaths*. 1051 1052 mname: 1053 The relative path of the module in dotted *Python* notation. :: 1054 1055 mname := ( 1056 <dotted-module-name-str> 1057 | <dotted-module-name-path-name-str> 1058 ) 1059 1060 mpaths: 1061 List of module specific search paths for *platformids*, these 1062 are relative to *mbase*, :: 1063 1064 default := [ 1065 'dist', 1066 'custom', 1067 'net', 1068 'embed', 1069 '', 1070 ] 1071 1072 resulting in:: 1073 1074 default := [ 1075 mbase + 'dist' + os.sep, 1076 mbase + 'custom' + os.sep, 1077 mbase + 'net' + os.sep, 1078 mbase + 'embed' + os.sep, 1079 mbase, 1080 ] 1081 1082 kargs: 1083 permitrel: 1084 Permit the return of relative module names within *mpath*. 1085 If *False* absolute only, which is relative to an existing 1086 *sys.path* entry. :: 1087 1088 permitrel := ( 1089 True, # returns a relative module name if within subtree 1090 False # returns in any case a module name relative to sys.path 1091 ) 1092 1093 Sets relative base within *platformids* as the default: :: 1094 1095 rbase = os.path.normpath(os.path.dirname(__file__)) + os.sep 1096 1097 Returns: 1098 Returns in case of a match the resulting entry within *sys.modules*:: 1099 1100 match -> (<relative-module-name>, <module-file-path-name>,) 1101 1102 The default when no match occured is to rely on the more versatile 1103 search mechanism of the import implementation of the concrete 1104 *Python* implementation for another final trial by the caller:: 1105 1106 default -> (<mname>, None,) 1107 1108 Raises: 1109 PlatformIDsError 1110 'mbase' does not match 'mpaths' 1111 1112 PlatformIDsPresentError 1113 missing 'mbase' 1114 1115 pass-through 1116 1117 """ 1118 # not using sourceinfo package in order to avoid circular dependencies, 1119 # so keep platformids on lowest possible software-stack level 1120 _permitrel = kargs.get('permitrel', False) 1121 if _permitrel: 1122 rbase = kargs.get('rbase') 1123 if rbase == None: 1124 rbase = os.path.normpath(os.path.dirname(__file__) + os.sep) + os.sep 1125 kargs['rbase'] = rbase 1126 1127 if mbase == None: 1128 mbase = os.path.dirname(__file__) + os.sep 1129 mbase = os.path.normpath(mbase) + os.sep 1130 1131 if mpaths == None: 1132 # default 1133 mpaths = [ 1134 mbase + 'dist' + os.sep, 1135 mbase + 'custom' + os.sep, 1136 mbase + 'net' + os.sep, 1137 mbase + 'embed' + os.sep, 1138 mbase , 1139 ] 1140 elif mpaths and mpaths[0]: 1141 # permit relative to mbase only 1142 for mi in range(len(mpaths)): 1143 mpaths[mi] = os.path.normpath(mbase + mpaths[mi]) + os.sep 1144 1145 elif not mpaths: 1146 raise PlatformIDsPresentError("missing 'mpaths'") 1147 1148 if mpaths and not mpaths[0].startswith(mbase): 1149 raise PlatformIDsError( 1150 "'mbase' does not match 'mpaths'\nmbase = %s\nmpaths[0] = %s" %( 1151 mbase, mpaths[0] 1152 ) 1153 ) 1154 1155 return get_modulelocation(mname, mbase, mpaths, **kargs)
1156 1157
1158 -def decode_version_str_to_segments(v):
1159 """Split a version string separated by '.' into an integer 1160 array. :: 1161 1162 decode_version_str_to_segments('1.22.17') => (1, 22, 17) 1163 decode_version_str_to_segments('2012.02.17') => (2012, 2, 17) 1164 decode_version_str_to_segments('10.0.1809') => (10, 0, 1809) 1165 1166 A tiny utility - frequently required. 1167 1168 Args: 1169 v: Version string with maximal 3 digits:: 1170 1171 ('1.2.3') => (1, 2, 3) 1172 ('1.2') => (1, 2, 0) 1173 ('1') => (1, 0, 0) 1174 1175 Returns: 1176 Tuple of *int*. :: 1177 1178 ('1.2.3') => (1, 2, 3) 1179 ('1.2') => (1, 2, 0) 1180 ('1') => (1, 0, 0) 1181 1182 In case an error occured:: 1183 1184 (0, 0, 0) 1185 1186 Raises: 1187 None. 1188 1189 """ 1190 1191 # see manual 1192 def tonum(x): 1193 try: 1194 return int(x) 1195 except ValueError: 1196 if x == '': 1197 return 0 1198 raise
1199 1200 return tuple([tonum(x) for x in VERSNUM.split(v)[1:4]]) 1201 1202
1203 -def encode_rte_to_32bit(**kargs):
1204 """Encodes the provided 32bit bitmask of each field into 1205 the combined integer value of the bitmask vector. 1206 1207 Args: 1208 kargs: 1209 category: 1210 The numeric 32bit bitmask of the category: :: 1211 1212 category := ( 1213 <int-enum> 1214 | <category-key> 1215 ) 1216 int-enum: the integer enum, preferbly a predefined value-by-var 1217 category-key: the key value as string to be evaluated by one 1218 1219 of:: 1220 1221 *rte2num*: the common mapping dictionary 1222 *get_rte2num*: the function interface for *rte2num* 1223 1224 default is 0 1225 1226 ostype: 1227 The numeric 32bit bitmask of the ostype:: 1228 1229 ostype := ( 1230 <int-enum> 1231 | <ostype-key> 1232 ) 1233 int-enum: the integer enum, preferbly a predefined value-by-var 1234 ostype-key: the key value as string to be evaluated by one 1235 1236 of:: 1237 1238 *rte2num*: the common mapping dictionary 1239 *get_rte2num*: the function interface for *rte2num* 1240 1241 default is 0. 1242 1243 dist: 1244 The numeric 32bit bitmask of the dist:: 1245 1246 ostype := ( 1247 <int-enum> 1248 | <dist-key> 1249 ) 1250 int-enum: the integer enum, preferbly a predefined value-by-var 1251 dist-key: the key value as string to be evaluated by one 1252 1253 of:: 1254 1255 *rte2num*: the common mapping dictionary 1256 *get_rte2num*: the function interface for *rte2num* 1257 1258 default is 0. 1259 1260 distrel: 1261 The numeric 32bit encoded integer for the distrel, default is 0. 1262 1263 Returns: 1264 The 32bit compressed bitmask of the RTE. 1265 1266 Raises: 1267 pass-through 1268 1269 """ 1270 return ( 1271 get_rte2num(kargs.get('category', 0)) | get_rte2num(kargs.get('ostype', 0)) | get_rte2num(kargs.get('dist', 0)) | get_rte2num(kargs.get('distrel', 0)) 1272 )
1273 1274
1275 -def encode_rte_segments_to_32bit(**kargs):
1276 """Converts the numeric base values of the fields into a 32bit bitmask and 1277 encodes them into the combined integer value of the bitmask vector. 1278 1279 Args: 1280 kargs: 1281 category: 1282 The non-shifted base value of the category:: 1283 1284 category := ( 1285 <int-val> 1286 ) 1287 int-val: the relative integer value of the category bits 1288 1289 default is 0 1290 1291 ostype: 1292 The non-shifted base value of the ostype:: 1293 1294 ostype := ( 1295 <int-val> 1296 ) 1297 int-val: the relative integer value of the ostype bits 1298 1299 default is 0. 1300 1301 dist: 1302 The non-shifted base value of the dist:: 1303 1304 dist := ( 1305 <int-val> 1306 ) 1307 int-val: the relative integer value of the dist bits 1308 1309 default is 0. 1310 1311 distrel: 1312 The non-shifted encoded base value of the distrel, default is 0. 1313 1314 Returns: 1315 The 32bit compressed bitmask of the RTE. 1316 1317 Raises: 1318 pass-through 1319 1320 """ 1321 return ( 1322 kargs.get('category', 0) << 28 | kargs.get('ostype', 0) << 23 | kargs.get('dist', 0) << 16 | kargs.get('distrel', 0) 1323 )
1324 1325
1326 -def fetch_platform_distribution():
1327 """Scans the platform and returns the complete distribution data prepared for 1328 common post-processing. 1329 1330 Args: 1331 none 1332 1333 Returns: 1334 Returns the information about the current distribution. :: 1335 1336 result := ( 1337 <lowercase-dist-id>, # 0: lower case str including release number 1338 <dist-release-number-str>, # 1: the release number as string 1339 <original-literal-release-name>, # 2: case sensitive release name 1340 <original-literal-dist-name>, # 3: case sensitive distribution name 1341 <dist-release-number-list>, # 4: release version as list of int 1342 <lowercase-dist->, # 5: lower case str of dist name only 1343 ) 1344 1345 Raises: 1346 PlatformIDsError 1347 1348 """ 1349 # 1350 # provides a resulting canonical record, see manual 1351 # the most reliable and common code is to rely on the configuration files 1352 1353 # 0: <lowercase-dist-id>, # lower case str 1354 # 1: <dist-release-number-str>, # string 1355 # 2: <original-literal-release-name>, # case sensitive str 1356 # 3: <original-literal-dist-name>, # case sensitive str 1357 # 4: <dist-release-number-list>, # list of int 1358 # 5: <lowercase-dist->, # lower case str of dist name only 1359 # 1360 1361 if category & RTE_POSIX == RTE_POSIX: 1362 dist = ['', '', '', '', []] 1363 1364 # 1365 # a lot has to be evaluated by various extras - including some /etc/* 1366 # this is in particular the case for derived dist 1367 # 1368 1369 if os.path.exists("/etc/redhat-release"): 1370 # rhel, centos, fedora, sc, oel, ... 1371 1372 with open("/etc/redhat-release", 'r') as f: 1373 for l in f: # hopefully one only 1374 if l: 1375 dist = re.split(r'(?s)^([^0-9]*) release *([0-9.]*[^ ]*) [^(]*[(]([^)]*)[)][\n\t ]*$', l) 1376 1377 if dist[1].startswith('CentOS'): 1378 import platformids.dist.centos 1379 return tuple(platformids.dist.centos.dist) 1380 1381 elif dist[1].startswith('Red H'): 1382 import platformids.dist.rhel 1383 return tuple(platformids.dist.rhel.dist) 1384 1385 elif dist[1].startswith('Fedora'): 1386 import platformids.dist.fedora 1387 return tuple(platformids.dist.fedora.dist) 1388 1389 elif dist[1].startswith('Oracle'): 1390 import platformids.dist.oraclelinux 1391 return tuple(platformids.dist.oraclelinux.dist) 1392 1393 else: 1394 dist.pop(0) 1395 1396 dist[0] = dist[0].lower() + re.sub(r'[.-_]', '', dist[1]) 1397 dist.append(dist[3].lower()) 1398 return tuple(dist) 1399 1400 elif os.path.exists("/etc/armbian-release"): 1401 import platformids.embed.armbian 1402 return tuple(platformids.embed.armbian.dist) 1403 1404 elif os.path.exists("/etc/arch-release"): 1405 # loads ArchLinux defines, a later stage loads an eventually derived distribution 1406 import platformids.dist.archlinux 1407 return tuple(platformids.dist.archlinux.dist) 1408 1409 elif os.path.exists("/etc/alpine-release"): 1410 # loads ArchLinux defines, a later stage loads an eventually derived distribution 1411 import platformids.dist.alpinelinux 1412 return tuple(platformids.dist.alpinelinux.dist) 1413 1414 elif os.path.exists("/etc/gentoo-release"): 1415 # loads ArchLinux defines, a later stage loads an eventually derived distribution 1416 import platformids.dist.gentoo 1417 return tuple(platformids.dist.gentoo.dist) 1418 1419 elif os.path.exists("/etc/os-release"): 1420 # debian, raspbian, etc. 1421 # openSUSE 1422 # sles??? 1423 1424 if os.path.exists("/etc/debian_version"): 1425 dist = ['debian', '', '', 'Debian', ''] 1426 with open("/etc/debian_version", 'r') as f: 1427 for l in f: 1428 dist[1] = re.split(r'(?s)^([0-9.]*).*$', l)[1] 1429 dist[4] = decode_version_str_to_segments(dist[1]) 1430 1431 else: 1432 dist = ['', '', '', '', ''] 1433 1434 _ver = '' 1435 _name = '' 1436 1437 with open("/etc/os-release", 'r') as f: 1438 for l in f: 1439 if l.startswith('ID='): 1440 dist[0] = DSKORG_ID.sub(r'\1', l) 1441 elif l.startswith('VERSION='): # priority though more widespread 1442 _ver = l 1443 elif l.startswith('VERSION_ID=') and not _ver: # Ubuntu, redundant in Slackware 1444 _ver = l 1445 elif l.startswith('NAME='): 1446 _nam = l 1447 1448 if dist[0].startswith('raspbian'): 1449 import platformids.embed.raspbian 1450 return tuple(platformids.embed.raspbian.dist) 1451 1452 elif dist[0].startswith('kali'): 1453 import platformids.net.kali 1454 return tuple(platformids.net.kali.dist) 1455 1456 elif os.path.exists("/etc/openwrt_release"): 1457 import platformids.net.openwrt 1458 return tuple(platformids.net.openwrt.dist) 1459 1460 elif dist[0].startswith('debian'): 1461 import platformids.dist.debian 1462 return tuple(platformids.dist.debian.dist) 1463 1464 elif dist[0].startswith('ubuntu'): 1465 import platformids.dist.ubuntu 1466 return tuple(platformids.dist.ubuntu.dist) 1467 1468 elif dist[0].startswith('opensuse'): 1469 import platformids.dist.opensuse 1470 return tuple(platformids.dist.opensuse.dist) 1471 1472 else: 1473 # loads module in second stage only by direct import 1474 1475 _l = DSKORG_RELEASE.split(_ver) 1476 dist.append(dist[0]) 1477 dist[0] += re.sub(r'[.]', '', _l[1]) 1478 dist[1] = _l[1] 1479 dist[3] = re.sub(r'NAME=(.*)[\n]*', r'\1', _nam) 1480 dist[2] = dist[3] + '-' + _l[1] 1481 dist[4] = decode_version_str_to_segments(_l[1]) 1482 1483 return tuple(dist) 1484 1485 elif (os.path.exists('/etc/pfSense-rc')): 1486 import platformids.net.pfsense 1487 return tuple(platformids.net.pfsense.dist) 1488 1489 elif ( 1490 sys.platform.startswith('openbsd') # OpenBSD - CPython, PyPy, IPython 1491 or 1492 os.path.exists('/bsd.booted') # OpenBSD - match on Jython 1493 ): 1494 import platformids.dist.openbsd 1495 return tuple(platformids.dist.openbsd.dist) 1496 1497 elif ( 1498 sys.platform.startswith('cygwin') 1499 or 1500 os.path.exists('/cygdrive') # rely on standard path only for now 1501 ): 1502 # Cygwin is a bit special as it mimics POSIX, 1503 # but runs the OS windows. 1504 import platformids.dist.cygwin 1505 return tuple(platformids.dist.cygwin.dist) 1506 1507 elif ( 1508 sys.platform.startswith('freebsd') # FreeBSD - CPython, PyPy, IPython 1509 or 1510 os.path.exists('/etc/freebsd-update.conf') # FreeBSD - match on Jython 1511 ): 1512 import platformids.dist.freebsd 1513 return tuple(platformids.dist.freebsd.dist) 1514 1515 elif ( 1516 sys.platform.startswith('netbsd') # NetBSD - CPython, PyPy, IPython 1517 or 1518 os.path.exists('/etc/netbsd-update.conf') # NetBSD - match on Jython 1519 ): 1520 import platformids.dist.netbsd 1521 return tuple(platformids.dist.netbsd.dist) 1522 1523 elif ( 1524 sys.platform.startswith('sunos5') # Solaris10 + Solaris11 - CPython, PyPy, IPython 1525 or 1526 os.path.exists('/etc/release') # Solaris10 + Solaris11 - match on Jython 1527 ): 1528 import platformids.dist.solaris 1529 return tuple(platformids.dist.solaris.dist) 1530 1531 elif ( 1532 sys.platform.startswith('darwin') # Solaris10 + Solaris11 - CPython, PyPy, IPython 1533 or 1534 os.path.exists('/System/Library/Components/AppleScript.component') # Solaris10 + Solaris11 - match on Jython 1535 ): 1536 import platformids.dist.darwin 1537 return tuple(platformids.dist.darwin.dist) 1538 1539 else: 1540 try: 1541 # default for unknown POSIX system 1542 _u = os.uname() # @UndefinedVariable 1543 dist = [ 1544 '', 1545 re.sub(r'([0-9.]*).*', '\1', _u[2]), 1546 '', 1547 re.sub(r'([a-zA-Z-_]*).*', '\1', _u[0]), 1548 '', 1549 ] 1550 dist[0] = dist[3].lower() 1551 dist[2] = dist[3] + '-' + dist[1] 1552 dist[4] = dist[1].split('.') 1553 dist.append(dist[3].lower()) 1554 return tuple(dist) 1555 1556 except: 1557 return ('', '', '', '', '', '',) 1558 1559 elif category & RTE_WIN32 == RTE_WIN32: 1560 # 1561 # windows support of NT-releases including Windows10IoT 1562 # 1563 from platformids.dist.windows import WinVersion 1564 return tuple(WinVersion().readout_versioninfo_ext()) 1565 1566 else: 1567 raise PlatformIDsError("Platform not supported: " + str(osname))
1568 1569
1570 -def fetch_platform_distribution_num():
1571 """The numeric version of 'fetch_platform_distribution'. 1572 1573 Args: 1574 none 1575 1576 Returns: 1577 Returns the information about the current distribution. :: 1578 1579 result := ( 1580 #dist, # 0: distribution identifier 1581 #distrel, # 1: distribution release identifier 1582 #dist-release-number-list>, # 2: release version as list of int 1583 ) 1584 1585 Raises: 1586 PlatformIDsError 1587 1588 """ 1589 # 1590 # provides a resulting canonical record, see manual 1591 # 1592 # 0: <category>, # category 1593 # 1: <ostype>, # ostype 1594 # 2: <dist>, # dist 1595 # 3: <distrel>, # distrel 1596 # 4: <hexversion>, # hexversion of platform distribution release 1597 # 5: <producttype>, # producttype 1598 # 1599 return ( 1600 fetch_category(), 1601 fetch_ostype(), 1602 fetch_dist(), 1603 0, 1604 fetch_rte_hexversion(), 1605 0, 1606 )
1607 1608
1609 -def fetch_platform_os():
1610 """Scans the platform and returns the information on the OS including 1611 the name and the release version. 1612 1613 The name of the OS is commonly basically the kernel name. The *ostype* 1614 of *linux* has one common kernel only, while OS in the *bsd* and 1615 *unix* family commonly have distribution specific customized kernels. 1616 1617 Args: 1618 none 1619 1620 Returns: 1621 Returns the information about the current os. :: 1622 1623 res = ( 1624 <lowercase-os-id>, # osname: lower case str of os name 1625 <os-release-number-str>, # osrel: string of os release version 1626 <os-release-number-list>, # osrel: list of int of os release version 1627 <lowercase-os-rel-id>, # osname+osrel: lower case str rel + id 1628 ) 1629 1630 Raises: 1631 PlatformIDsError 1632 1633 """ 1634 if isJython: 1635 # Jython uname targets the JVM - need the actual underlying OS 1636 on = PRENONNUM.sub(r'\1', platform.System.getProperty('os.name').lower()) # @UndefinedVariable 1637 ov = decode_version_str_to_segments(platform.System.getProperty('os.version')) # @UndefinedVariable 1638 return ( 1639 on, 1640 '%d.%d.%d' % ov, 1641 ov, 1642 on + '-%d.%d.%d' % ov 1643 ) 1644 1645 k = platform.uname() 1646 1647 if osname == 'posix': 1648 if k[0][-3:] == 'BSD': 1649 # the kernel release is the same as the distrel 1650 ov = decode_version_str_to_segments(k[2]) 1651 return( 1652 k[0], 1653 k[2], 1654 ov, 1655 "%s%d%d" % (k[0], ov[0], ov[1]) 1656 ) 1657 1658 elif k[0] == 'SunOS': 1659 if k[2] == '5.10': 1660 # assume this release version more or less static for now 1661 _patch = re.compile(r'Generic_([0-9]*)-([0-9]*)') # e.g. Generic_147148-26 -> 14714826 1662 _p = _patch.sub(r"\1\2", k[3]) 1663 return( 1664 'sunos', 1665 '5.10.0', 1666 (5, 10, 0, int(_p)), 1667 'sunos5100' 1668 ) 1669 1670 elif k[2] == '5.11': 1671 # for now - until 2021++??? - the future of Solaris remains nebulous and unsafe 1672 ver = decode_version_str_to_segments(k[3]) 1673 return( 1674 'sunos', 1675 '5.' + k[3], 1676 (5, 11, int(ver[-2])), 1677 'sunos511' + str(ver[-2]) 1678 ) 1679 1680 ov = decode_version_str_to_segments(k[2]) 1681 return ( 1682 k[0].lower(), 1683 "%d.%d.%d" % (ov[0], ov[1], ov[2],), 1684 ov, 1685 "%s%d%d%d" % (k[0].lower(), ov[0], ov[1], ov[2],) 1686 ) 1687 1688 elif osname == 'nt': 1689 1690 if k[0] == 'Windows': 1691 ov = decode_version_str_to_segments(k[2]) 1692 return ( 1693 'nt100', 1694 k[2], 1695 ov, 1696 "%s%d%d%d" % (k[0], ov[0], ov[1], ov[2],) 1697 ) 1698 1699 ov = decode_version_str_to_segments(k[3]) 1700 return ( 1701 k[0].lower(), 1702 k[3], 1703 ov, 1704 "%s%d%d%d" % (k[0], ov[0], ov[1], ov[2],) 1705 ) 1706 1707 else: 1708 raise Exception("Platform not supported: " + str(osname))
1709 1710
1711 -def fetch_platform_os_num():
1712 """The numeric version of '`fetch_platform_os <#fetch-platform-os>`_'. 1713 1714 Args: 1715 none 1716 1717 Returns: 1718 Returns the information about the current os. :: 1719 1720 res = ( 1721 <enum-os-id>, # osname: lower case str of os name 1722 <32bit-os-release-number>, # osrel: string of os release version 1723 <os-release-number-list>, # osrel: list of int of os release version 1724 <enum-os-rel-id>, # osname+osrel: lower case str rel + id 1725 ) 1726 1727 Raises: 1728 PlatformIDsError 1729 1730 """ 1731 # 1732 # provides a resulting canonical record, see manual 1733 # 1734 # 0: <numeric-dist-id>, # lower case str 1735 # 1: <dist-release-number-str>, # enum 1736 # 2: <original-literal-release-name>, # case sensitive str 1737 # 3: <numeric-dist>, # enum 1738 # 4: <dist-release-number-list>, # list of int 1739 # 5: <numeric-dist->, # enum 1740 # 1741 _r = fetch_platform_os() 1742 return ( 1743 get_rte2num(_r[0]), 1744 0, 1745 0, 1746 get_rte2num(_r[3]), 1747 0, 1748 get_rte2num(_r[5]), 1749 1750 # 0: <lowercase-dist-id>, # lower case str 1751 # 1: <dist-release-number-str>, # string 1752 # 2: <original-literal-release-name>, # case sensitive str 1753 # 3: <original-literal-dist-name>, # case sensitive str 1754 # 4: <dist-release-number-list>, # list of int 1755 # 5: <lowercase-dist->, # lower case str of dist name only 1756 1757 )
1758 1759
1760 -def fetch_category():
1761 """Scans the platform and returns the numeric id for the current *category*. 1762 1763 Args: 1764 none 1765 1766 Returns: 1767 Returns the *category*. :: 1768 1769 res = <category-bits><ostype-bits-zero><dist-bits-zero><distrel-bits-zero> 1770 1771 Raises: 1772 PlatformIDsError 1773 1774 """ 1775 try: 1776 return rte2num[osname] 1777 except KeyError: 1778 raise Exception("Platform category not supported: " + str(osname))
1779 1780
1781 -def fetch_ostype():
1782 """Scans the platform and returns the numeric id for the current *ostype*. 1783 1784 Args: 1785 none 1786 1787 Returns: 1788 Returns the *ostype* as integer enum. The bitmask includes 1789 the *category*. :: 1790 1791 res = <category-bits><ostype-bits><dist-bits-zero><distrel-bits-zero> 1792 1793 Raises: 1794 PlatformIDsError 1795 1796 """ 1797 if osname == 'posix': 1798 if isJython: 1799 # _os = sys.getNativePlatform() # Available for 2.7.1+ 1800 # _os = platform.System.getProperty('os.name').lower() # @UndefinedVariable # seems 2.0+ 1801 try: 1802 return rte2num[platform.System.getProperty('os.name').lower()] & RTE_OSTYPE # @UndefinedVariable 1803 except KeyError: 1804 k = platform.dist() 1805 raise Exception("OS type not supported: %s.%s (platform.dist=%s)" % (str(osname), str(k[0]), str(k))) 1806 1807 else: 1808 k = platform.uname() 1809 if k[0] == 'Linux': 1810 return RTE_POSIX | RTE_LINUX 1811 1812 elif k[0][-3:] == 'BSD': 1813 return RTE_POSIX | RTE_BSD 1814 1815 else: 1816 try: 1817 # results on most supported OS for sys.platform: 1818 # 1819 # correct as ostype, with minor fuzz 1820 # cygwin, darwin 1821 # linux, linux2 1822 # sunos5 1823 # win32 1824 # 1825 # not exactly correct, these are distributions or almost distribution-releases 1826 # dragonfly5, freebsd11, netbsd8, openbsd6 1827 # 1828 # minix3 1829 # 1830 # some additional non-ostype 1831 # cli 1832 # java10.0.1, java11.0.2, java1.8.0_131, ... the jre/jdk - the world is encapsulated... 1833 1834 # 1835 # SOLUTION: matches pre-registered and isolates ostype 1836 # 1837 return rte2num[sys.platform] & RTE_OSTYPE 1838 1839 except KeyError: 1840 k = platform.dist() 1841 raise Exception("OS type not supported: %s.%s (platform.uname=%s)" % (str(osname), str(k[0]), str(k))) 1842 1843 elif osname == 'nt': 1844 return RTE_WIN | RTE_NT 1845 1846 else: 1847 # default pure dynamic by registration 1848 try: 1849 return rte2num[k[0].lower()] & RTE_OSTYPE # @UndefinedVariable 1850 except KeyError: 1851 raise Exception("Platform not supported: " + str(osname))
1852 1853
1854 -def fetch_dist():
1855 """Scans the platform and returns the numeric id for the current *dist*. 1856 1857 Args: 1858 none 1859 1860 Returns: 1861 Returns the *dist* as integer enum. The bitmask includes 1862 the *category* and *ostype*. :: 1863 1864 res = <category-bits><ostype-bits><dist-bits><distrel-bits-zero> 1865 1866 Raises: 1867 PlatformIDsError 1868 1869 """ 1870 _d = fetch_platform_distribution() 1871 try: 1872 return rte2num[_d[5]] 1873 except KeyError: 1874 return get_rte2num(_d[5])
1875 1876
1877 -def fetch_dist_tuple():
1878 """Scans the platform and returns the complete tuple for the current *dist*. 1879 1880 Args: 1881 none 1882 1883 Returns: 1884 Returns the complete tuple of information related to a distribution. :: 1885 1886 res = (<distid-string>, <distrel-string>, <distrel-tuple>, <ditst-rel-key-string>) 1887 1888 Raises: 1889 PlatformIDsError 1890 1891 """ 1892 _d = fetch_platform_distribution() 1893 return ( 1894 _d[5], 1895 _d[1], 1896 _d[4], 1897 _d[0], 1898 )
1899 1900 1901 # 1902 # first try the pre-scanned module offline created by setup.py 1903 # 1904 _impmodname = None 1905 try: 1906 with open(os.path.dirname(__file__) + os.sep + "setup_platform", 'r') as f: 1907 _impmodname = f 1908 1909 # 1910 # if 1911 # for l in f: 1912 # 1913 # dist = re.split(r'(?s)^([^0-9]*) release *([0-9.]*[^ ]*) [^(]*[(]([^)]*)[)][\n\t ]*$', l) 1914 # dist.pop(0) 1915 # dist[-1] = dist[0] 1916 except: 1917 pass 1918 1919 # 1920 # assign numeric value for current run time environment for dist(or windows) 1921 # the resulting value bootstraps the load of the details of the release distrel 1922 # exceptions: 1923 # some known are pre-loaded: windows 1924 # some known are hardcoded: see previous defines, e.g. some major Linux dists 1925 # 1926 # try to resolve the hierarchy as deep as possible 1927 # it is basically the pre-load bootstrap, so the database is not reliable yet for non-standard 1928 # 1929 if osname == 'posix': 1930 if ( 1931 os.path.exists("/etc/redhat-release") or 1932 os.path.exists("/etc/os-release") 1933 ): 1934 try: 1935 RTE = rte2num[fetch_platform_distribution()[5]] 1936 except KeyError: 1937 for r in rte2num.keys(): 1938 # iterate for something seems to be known 1939 # ATTENTION: there are ambiguities, e.g. for debian derived 1940 if type(r) in ISINT: 1941 continue 1942 if sys.platform.startswith(r): 1943 RTE = rte2num[r] 1944 1945 else: 1946 # for now we only know the category 1947 RTE = RTE_POSIX 1948 1949 elif sys.platform.startswith('openbsd'): 1950 RTE = RTE_OPENBSD 1951 1952 elif sys.platform.startswith('darwin'): 1953 RTE = RTE_DARWIN 1954 1955 elif os.path.exists("/etc/openwrt_release"): 1956 RTE = RTE_OPENWRT 1957 1958 elif sys.platform.startswith('sunos5'): 1959 # RTE = RTE_UNIX 1960 RTE = RTE_SOLARIS 1961 1962 elif sys.platform.startswith('cygwin'): 1963 RTE = RTE_PWEMU 1964 1965 else: 1966 RTE = RTE_POSIX 1967 1968 elif osname == 'nt': 1969 # due to required special handling loads initially the complete windows set 1970 RTE = RTE_WIN32 1971 1972 elif osname == 'java': 1973 # it is jython, 1974 # so have to pierce the encapsulation for getting the native platform parameters - want to do it in Python 1975 1976 RTE = 0 1977 try: 1978 _snp = sys.getNativePlatform() # @UndefinedVariable 1979 RTE = rte2num[_snp] 1980 1981 except (NameError, AttributeError): 1982 if platform.linux_distribution()[0]: 1983 RTE = RTE_LINUX 1984 1985 if os.path.exists("/etc/openwrt_release"): 1986 RTE = RTE_OPENWRT 1987 1988 elif ( 1989 os.path.exists("/etc/redhat-release") or 1990 os.path.exists("/etc/os-release") 1991 ): 1992 try: 1993 RTE = rte2num[fetch_platform_distribution()[5]] 1994 except KeyError: 1995 for r in rte2num.keys(): 1996 if type(r) in ISINT: 1997 continue 1998 if platform.linux_distribution()[0].lower().startswith(r): 1999 RTE = rte2num[r] 2000 else: 2001 RTE = RTE_POSIX 2002 2003 # elif sys.platform.startswith('openbsd'): 2004 # RTE = RTE_OPENBSD 2005 # 2006 # elif sys.platform.startswith('sunos5'): 2007 # RTE = RTE_SOLARIS 2008 # 2009 # elif sys.platform.startswith('darwin'): 2010 # RTE = RTE_DARWIN 2011 # 2012 elif sys.platform.startswith('cygwin'): 2013 RTE = RTE_PWEMU 2014 2015 else: 2016 RTE = RTE_POSIX 2017 2018 elif platform.mac_ver()[0]: 2019 RTE = RTE_DARWIN 2020 elif platform.win32_ver()[0]: 2021 RTE = RTE_WIN32 2022 2023 if not RTE: 2024 raise PlatformIDsError("Unknown platform: " + str(_snp)) 2025 2026 else: 2027 raise Exception("Platform not supported") 2028 2029 # 2030 # check setup dist exists, if not try dynamic evaluation 2031 # 2032 if not _impmodname or not os.path.exists(_impmodname): 2033 try: 2034 _impmodname = num2rte[RTE] 2035 2036 except KeyError: 2037 if RTE == RTE_WIN32: 2038 _impmodname = 'windows' 2039 else: 2040 raise PlatformIDsError("not supported, requires:" + str(num2rte.values())) 2041 2042 # 2043 # once the bootstrap module is selected load it 2044 # loads the required module only for the current dist(or windows) 2045 # 2046 modnamerel, modfpath = get_modlocation(_impmodname) 2047 if modfpath == None: 2048 2049 # system data - prohibit redefinition of present system data 2050 if RTE & RTE_WIN32 or (RTE & RTE_PWEMU) == RTE_PWEMU: 2051 mbase_altbase = os.environ['CommonProgramFiles'] + os.sep + 'platformids' 2052 else: 2053 mbase_altbase = os.sep + 'etc' + os.sep + 'platformids' 2054 2055 # alternate data - prohibit redefinition of present data 2056 if not os.path.exists(mbase_altbase): 2057 mbase_altbase = os.getenv('PLATFORMIDS_ALTBASE', None) 2058 2059 if mbase_altbase != None: 2060 modnamerel, modfpath = get_modlocation(_impmodname, mbase=mbase_altbase, ) 2061 2062 # user data 2063 if RTE & RTE_WIN32 or (RTE & RTE_PWEMU) == RTE_PWEMU: 2064 mbase_altbase = os.environ['LOCALAPPDATA'] + os.sep + 'platformids' 2065 if not os.path.exists(mbase_altbase) and RTE & RTE_LINUX: 2066 mbase_altbase = os.environ['HOME'] + os.sep + '.config' + os.sep + 'platformids' 2067 if not mbase_altbase or not os.path.exists(mbase_altbase): 2068 mbase_altbase = os.environ['HOME'] + os.sep + 'platformids' 2069 2070 try: 2071 # load module by file system path name 2072 load_module(_impmodname, modfpath) 2073 except KeyError: 2074 # continue with generic 2075 pass 2076 2077
2078 -def fetch_rte_hexversion():
2079 """Retrieves the bitmask encoding for current runtime environemnt. 2080 2081 Args: 2082 None. 2083 2084 Returns: 2085 The encoded bitmask to be used for caching and *RTE*. 2086 2087 Raises: 2088 pass-through 2089 2090 """ 2091 ret = 0 2092 try: 2093 _pi = fetch_platform_distribution() 2094 ret = rte2num[_pi[0]] 2095 # here it is at least one defined as present 2096 2097 except KeyError: 2098 # no mapping available, 2099 2100 # try next 'nearest' version to be expected compatible - for now cutting minor version numbers, 2101 # if not found step up the hierarchy "category.ostype.dist.distrel" 2102 2103 # 2104 # TODO: adapt a better strategy, decrement major version - BUT for all platform version schemes! 2105 # 2106 2107 # 1. try version steps 2108 for rx in range(len(_pi[4]), 0, -1): 2109 _k = _pi[5] + ''.join((str(x) for x in _pi[4][:rx])) 2110 try: 2111 ret = rte2num[_k] 2112 2113 except KeyError: 2114 pass 2115 2116 if not ret: 2117 try: 2118 # 2. try dist name 2119 ret = rte2num[_pi[5]] 2120 2121 except KeyError: 2122 try: 2123 # 3. try ostype 2124 ret = rte2num[fetch_platform_os()[0]] 2125 2126 except KeyError: 2127 try: 2128 # 4. try category 2129 2130 ret = rte2num[fetch_platform_distribution()] 2131 2132 except KeyError: 2133 2134 ret = rte2num[fetch_platform_os()] 2135 2136 return ret
2137 2138 2139 # 2140 # here we have the *dist*, so now set the actual release of the distribution *distrel*, when present 2141 RTE = fetch_rte_hexversion() 2142 2143 # 2144 # set: generic 2145 # 2146 2147 # : Use the current block-offset only, 2148 # : results in the current platformm enum. 2149 RTE_GENERIC = RTE & RTE_POSIX & RTE_WIN32 2150 2151 # : Dyanmic local platform, synonym for generic. 2152 RTE_LOCAL = RTE_GENERIC + 1 2153 2154
2155 -def decode_rte_category_to_num(rte=RTE):
2156 """Decodes the compressed category from the 32bit integer bitmask 2157 into the corresponding integer enum. 2158 2159 Args: 2160 rte: 2161 The comppressed runtime environment identifier bitmask. 2162 2163 default := RTE 2164 2165 Returns: 2166 Integer value of the category enum. 2167 2168 Raises: 2169 pass-through 2170 2171 """ 2172 return (get_rte2num(rte) & RTE_CATEGORY)
2173 2174
2175 -def decode_rte_ostype_to_num(rte=RTE):
2176 """Decodes the compressed ostype from the 32bit integer bitmask 2177 into the corresponding integer enum. 2178 2179 Args: 2180 rte: 2181 The comppressed runtime environment identifier bitmask. 2182 2183 default := RTE 2184 2185 Returns: 2186 Integer value of the ostype enum. 2187 2188 Raises: 2189 pass-through 2190 2191 """ 2192 return (get_rte2num(rte) & RTE_OSTYPE)
2193 2194
2195 -def decode_rte_dist_to_num(rte=RTE):
2196 """Decodes the compressed dist from the 32bit integer bitmask 2197 into the corresponding integer enum. 2198 Recognizes the *ostype* domain e.g. for *RTE_NT*. 2199 2200 Args: 2201 rte: 2202 The comppressed runtime environment identifier bitmask. 2203 2204 default := RTE 2205 2206 Returns: 2207 Integer value of the dist enum. 2208 2209 Raises: 2210 pass-through 2211 2212 """ 2213 return (get_rte2num(rte) & RTE_DIST)
2214 2215
2216 -def decode_rte_distrel_to_num(rte=RTE):
2217 """Decodes the compressed distrel from the 32bit integer bitmask 2218 into the corresponding integer enum. 2219 Recognizes the *ostype* and *dist* domain, the distrel 2220 extension flag. 2221 2222 Args: 2223 rte: 2224 The comppressed runtime environment identifier bitmask. 2225 2226 default := RTE 2227 2228 Returns: 2229 Integer value of the encoded distrel. 2230 2231 Raises: 2232 pass-through 2233 2234 """ 2235 return (get_rte2num(rte) & RTE_DISTREL)
2236 2237
2238 -def decode_rte_distrel_to_segments(rte=RTE):
2239 """Decodes the compressed distrel from the 32bit integer bitmask 2240 into the corresponding tuple of integer segments. 2241 2242 This is probably one of the most important functions, because 2243 it has the knowledge to split *distrel* including calling 2244 a custom-callback function when required. 2245 Recognizes the *ostype* and *dist* domain, the *distrel* 2246 extension flag in order to determine the further processing. 2247 The supported special cases of known and pre-loaded standard 2248 distributions are hardcoded for better performance here, 2249 currently these are: :: 2250 2251 ArchLinux, KaliLinux 2252 Windows-NT 2253 2254 BlackArch, Gentoo, 2255 Armbian, ArchLinux, BlackArch, Gentoo, KaliLinux 2256 2257 Args: 2258 rte: 2259 The comppressed runtime environment identifier bitmask. 2260 2261 default := RTE 2262 2263 Returns: 2264 Tuple of Integer values of the encoded segments, either 2265 as defined by the default layout, or any known as defined 2266 by additional extended and/or custom criteria. 2267 2268 Raises: 2269 pass-through 2270 2271 """ 2272 try: 2273 _rte = rte2num[rte] 2274 2275 except KeyError: 2276 if type(rte) in ISINT: 2277 # can split basically any number, let's see... 2278 _rte = rte 2279 2280 elif decode_version_str_to_segments(rte): 2281 # assume is a valid version string 2282 return decode_version_str_to_segments(rte) 2283 2284 else: 2285 raise PlatformIDsUnknownError("Not registered distrel = " + str(rte)) 2286 2287 if _rte & RTE_OSTYPE == RTE_NT: 2288 # known specials - Windows-NT 2289 return ( 2290 _rte & 0xffff, 2291 0, 2292 0, 2293 ) 2294 2295 elif _rte & RTE_OSTYPE == RTE_LINUX and _rte & RTE_DISTEXT: 2296 if (_rte & RTE_DIST) in (RTE_KALI, RTE_ARCHLINUX,): 2297 # known specials - date based rolling distros 2298 # fixed offset to 1970 - the UNIX-time 2299 return ( 2300 ((_rte & 0xfe00) >> 9) + 1970, 2301 (_rte & 0x01e0) >> 5, 2302 _rte & 0x001f, 2303 ) 2304 2305 elif _rte & RTE_DIST in custom_rte_distrel2tuple.keys(): 2306 # registered specials - call custom callback 2307 return custom_rte_distrel2tuple[_rte & RTE_DIST](rte) 2308 2309 # default handler - see docu for '3-number-default' 2310 return ( 2311 (_rte & 0xfc00) >> 10, 2312 (_rte & 0x03e0) >> 5, 2313 _rte & 0x001f, 2314 )
2315 2316
2317 -def decode_rte_to_segments(rte=RTE):
2318 """Decodes the compressed components from the 32bit integer bitmask 2319 into the corresponding segments of relative integer values. 2320 2321 Args: 2322 rte: 2323 The comppressed runtime environment identifier bitmask. 2324 2325 default := RTE 2326 2327 Returns: 2328 Tuple of integer values of the components. :: 2329 2330 ret := => (#category-bits, #ostype-bits, #dist-bits, #distrel-bits) 2331 2332 Where the following os true: :: 2333 2334 rte == #category-bits << 28 | #ostype-bits << 23 | #dist-bits << 16 | #distrel-bits 2335 rte == encode_rte_segments_to_32bit(#category-bits, #ostype-bits, #dist-bits, #distrel-bits) 2336 rte == encode_rte_segments_to_32bit( *decode_rte_to_segments( rte ) ) 2337 2338 Raises: 2339 pass-through 2340 2341 """ 2342 rte = get_rte2num(rte) 2343 return ((rte & RTE_CATEGORY_B), (rte & RTE_OSTYPE_B), (rte & RTE_DIST_B), (rte & RTE_DISTREL_B))
2344 2345
2346 -def decode_rte_to_tuple(rte=RTE):
2347 """Decodes the compressed components from the 32bit integer bitmask 2348 into the corresponding tuple of partial integer enums. 2349 2350 Args: 2351 rte: 2352 The comppressed runtime environment identifier bitmask. 2353 2354 default := RTE 2355 2356 Returns: 2357 Tuple of integer values of the components. :: 2358 2359 ret := => (#category-num, #ostype-num, #dist-num, #distrel-num) 2360 2361 Where the following os true: :: 2362 2363 ret == #category-num | #ostype-num | #dist-num | #distrel-num 2364 ret == #category-num + #ostype-num + #dist-num + #distrel-num 2365 2366 Raises: 2367 pass-through 2368 2369 """ 2370 rte = get_rte2num(rte) 2371 return ((rte & RTE_CATEGORY), (rte & RTE_OSTYPE), (rte & RTE_DIST), (rte & RTE_DISTREL))
2372 2373
2374 -def decode_rte_to_tuple_str(rte=RTE):
2375 """Decodes the compressed components from the 32bit integer bitmask 2376 into the corresponding tuple of string keywords. 2377 2378 Args: 2379 rte: 2380 The comppressed runtime environment identifier bitmask. 2381 2382 default := RTE 2383 2384 Returns: 2385 Tuple of keywords of string values for the components. :: 2386 2387 ret := => (<category>, <ostype>, <dist>, <distrel>) 2388 2389 Raises: 2390 pass-through 2391 2392 """ 2393 try: 2394 try: 2395 _rte = rte2num[rte] # requires registered strings 2396 except KeyError: 2397 if type(rte) not in ISINT: 2398 # currently converting strings only if registered 2399 raise 2400 2401 # so is an numeric rte - seems at least to be 2402 _rte = rte 2403 2404 if (_rte & RTE_OSTYPE) == RTE_NT: 2405 # 2406 return ( 2407 get_num2rte(_rte & RTE_CATEGORY), 2408 get_num2rte(_rte & RTE_OSTYPE), 2409 get_num2rte(_rte & RTE_DIST), 2410 get_num2rte(_rte & RTE_DIST) + str(_rte & RTE_DISTREL_B) 2411 ) 2412 2413 elif _rte & RTE_DISTEXT: 2414 # 2415 return ( 2416 get_num2rte(_rte & RTE_CATEGORY), 2417 get_num2rte(_rte & RTE_OSTYPE), 2418 get_num2rte(_rte & RTE_DIST), 2419 get_num2rte(_rte & RTE_DISTREL) 2420 ) 2421 2422 2423 else: 2424 # default handler - with expected table entries 2425 return ( 2426 num2rte[(_rte & RTE_CATEGORY)], 2427 num2rte[(_rte & RTE_OSTYPE)], 2428 num2rte[(_rte & RTE_DIST)], 2429 num2rte[(_rte & RTE_DISTREL)] 2430 ) 2431 2432 except: 2433 if type(rte) in ISINT: 2434 pass
2435
2436 -def get_num2rte(num):
2437 """Gets the corresponding string representation 2438 for the string numeric value. 2439 2440 Alternatively the official dict *num2rte* 2441 could be used. 2442 2443 Args: 2444 num: 2445 Numeric enum value of the requested platform. 2446 2447 Returns: 2448 The string value, or *None**. 2449 2450 Raises: 2451 None 2452 2453 """ 2454 if type(num) not in ISINT: 2455 return str(num) 2456 return num2rte.get(num)
2457 2458
2459 -def get_rte2num(rte):
2460 """Gets corresponding numerical representation 2461 for the numeric or string value. 2462 2463 Alternatively the official dict *rte2num* 2464 could be used. 2465 2466 Args: 2467 rte: 2468 Numeric enum value or string representation 2469 of the requested platform. 2470 2471 Returns: 2472 The numeric value, or *None**. 2473 2474 Raises: 2475 None 2476 2477 """ 2478 if type(rte) in ISINT: 2479 return rte 2480 2481 # 2482 # do not want to mix it up with platforms due to arising circular dependencies than 2483 # 2484 2485 try: 2486 return rte2num.get(rte) 2487 except TypeError: 2488 raise PlatformIDsError( 2489 "TypeError: requires a valid key for 'platformids.rte2num' (int, str)- got:" + str(type(rte)))
2490 2491
2492 -def set_num2rte(key, value):
2493 """Sets the numeric to string map. 2494 2495 Alternatively the official dict *num2rte* 2496 could be used. 2497 2498 Args: 2499 key: 2500 Numeric key value. 2501 2502 value: 2503 String value. 2504 2505 Returns: 2506 None 2507 2508 Raises: 2509 PlatformIDsError 2510 2511 """ 2512 if type(key) != int: 2513 raise PlatformIDsError("requires a int key, got: " + str(key)) 2514 if type(value) not in ISSTR: 2515 raise PlatformIDsError("requires a string value, got: " + str(value)) 2516 2517 num2rte[key] = value
2518 2519
2520 -def set_rte2num(key, value):
2521 """Sets the rte to numeric mapping 2522 2523 Alternatively the official dict *rte2num* 2524 could be used. 2525 2526 Args: 2527 key: 2528 Numeric or string key value. 2529 2530 value: 2531 Numeric value. 2532 2533 Returns: 2534 None 2535 2536 Raises: 2537 None 2538 2539 """ 2540 if type(value) != int: 2541 raise PlatformIDsError("requires an int value, got: " + str(value)) 2542 rte2num[key] = value
2543 2544 # 4debug 2545 pass 2546