Home | History | Annotate | Download | only in common_lib
      1 #
      2 # kernel_versions.py -- linux kernel version comparisons
      3 #
      4 __author__ = """Copyright Andy Whitcroft 2007"""
      5 
      6 import sys,re
      7 
      8 #
      9 # Sort key for ordering versions chronologically.  The key ordering
     10 # problem is between that introduced by -rcN.  These come _before_
     11 # their accompanying version.
     12 #
     13 #   2.6.0 -> 2.6.1-rc1 -> 2.6.1
     14 #
     15 # In order to sort them we convert all non-rc releases to a pseudo
     16 # -rc99 release.  We also convert all numbers to two digits.  The
     17 # result is then sortable textually.
     18 #
     19 #   02.06.00-rc99 -> 02.06.01-rc01 -> 02.06.01-rc99
     20 #
     21 encode_sep = re.compile(r'(\D+)')
     22 
     23 def version_encode(version):
     24     bits = encode_sep.split(version)
     25     n = 9
     26     if len(bits[0]) == 0:
     27         n += 2
     28     if len(bits) == n or (len(bits) > n and bits[n] != '_rc'):
     29         # Insert missing _rc99 after 2 . 6 . 18 -smp- 220 . 0
     30         bits.insert(n, '_rc')
     31         bits.insert(n+1, '99')
     32     n = 5
     33     if len(bits[0]) == 0:
     34         n += 2
     35     if len(bits) <= n or bits[n] != '-rc':
     36         bits.insert(n, '-rc')
     37         bits.insert(n+1, '99')
     38     for n in range(0, len(bits), 2):
     39         if len(bits[n]) == 1:
     40             bits[n] = '0' + bits[n]
     41 
     42     return ''.join(bits)
     43 
     44 
     45 def version_limit(version, n):
     46     bits = encode_sep.split(version)
     47     return ''.join(bits[0:n])
     48 
     49 
     50 def version_len(version):
     51     return len(encode_sep.split(version))
     52 
     53 #
     54 # Given a list of versions find the nearest version which is deemed
     55 # less than or equal to the target.  Versions are in linux order
     56 # as follows:
     57 #
     58 #   2.6.0 -> 2.6.1 -> 2.6.2-rc1 -> 2.6.2-rc2 -> 2.6.2 -> 2.6.3-rc1
     59 #              |        |\
     60 #              |        | 2.6.2-rc1-mm1 -> 2.6.2-rc1-mm2
     61 #              |        \
     62 #              |         2.6.2-rc1-ac1 -> 2.6.2-rc1-ac2
     63 #              \
     64 #               2.6.1-mm1 -> 2.6.1-mm2
     65 #
     66 # Note that a 2.6.1-mm1 is not a predecessor of 2.6.2-rc1-mm1.
     67 #
     68 def version_choose_config(version, candidates):
     69     # Check if we have an exact match ... if so magic
     70     if version in candidates:
     71         return version
     72 
     73     # Sort the search key into the list ordered by 'age'
     74     deco = [ (version_encode(v), i, v) for i, v in
     75                                     enumerate(candidates + [ version ]) ]
     76     deco.sort()
     77     versions = [ v for _, _, v in deco ]
     78 
     79     # Everything sorted below us is of interst.
     80     for n in range(len(versions) - 1, -1, -1):
     81         if versions[n] == version:
     82             break
     83     n -= 1
     84 
     85     # Try ever shorter 'prefixes' 2.6.20-rc3-mm, 2.6.20-rc, 2.6. etc
     86     # to match against the ordered list newest to oldest.
     87     length = version_len(version) - 1
     88     version = version_limit(version, length)
     89     while length > 1:
     90         for o in range(n, -1, -1):
     91             if version_len(versions[o]) == (length + 1) and \
     92                                 version_limit(versions[o], length) == version:
     93                 return versions[o]
     94         length -= 2
     95         version = version_limit(version, length)
     96 
     97     return None
     98 
     99 
    100 def is_released_kernel(version):
    101     # True if version name suggests a released kernel,
    102     #   not some release candidate or experimental kernel name
    103     #   e.g.  2.6.18-smp-200.0  includes no other text, underscores, etc
    104     version = version.strip('01234567890.-')
    105     return version in ['', 'smp', 'smpx', 'pae']
    106 
    107 
    108 def is_release_candidate(version):
    109     # True if version names a released kernel or release candidate,
    110     #   not some experimental name containing arbitrary text
    111     #   e.g.  2.6.18-smp-220.0_rc3  but not  2.6.18_patched
    112     version = re.sub(r'[_-]rc\d+', '', version)
    113     return is_released_kernel(version)
    114