addon-sdk/source/python-lib/cuddlefish/version_comparator.py

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 # This Source Code Form is subject to the terms of the Mozilla Public
     2 # License, v. 2.0. If a copy of the MPL was not distributed with this
     3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
     5 '''
     6     This is a really crummy, slow Python implementation of the Mozilla
     7     platform's nsIVersionComparator interface:
     9       https://developer.mozilla.org/En/NsIVersionComparator
    11     For more information, also see:
    13       http://mxr.mozilla.org/mozilla/source/xpcom/glue/nsVersionComparator.cpp
    14 '''
    16 import re
    17 import sys
    19 class VersionPart(object):
    20     '''
    21     Examples:
    23       >>> VersionPart('1')
    24       (1, None, 0, None)
    26       >>> VersionPart('1pre')
    27       (1, 'pre', 0, None)
    29       >>> VersionPart('1pre10')
    30       (1, 'pre', 10, None)
    32       >>> VersionPart('1pre10a')
    33       (1, 'pre', 10, 'a')
    35       >>> VersionPart('1+')
    36       (2, 'pre', 0, None)
    38       >>> VersionPart('*').numA == sys.maxint
    39       True
    41       >>> VersionPart('1') < VersionPart('2')
    42       True
    44       >>> VersionPart('2') > VersionPart('1')
    45       True
    47       >>> VersionPart('1') == VersionPart('1')
    48       True
    50       >>> VersionPart('1pre') > VersionPart('1')
    51       False
    53       >>> VersionPart('1') < VersionPart('1pre')
    54       False
    56       >>> VersionPart('1pre1') < VersionPart('1pre2')
    57       True
    59       >>> VersionPart('1pre10b') > VersionPart('1pre10a')
    60       True
    62       >>> VersionPart('1pre10b') == VersionPart('1pre10b')
    63       True
    65       >>> VersionPart('1pre10a') < VersionPart('1pre10b')
    66       True
    68       >>> VersionPart('1') > VersionPart('')
    69       True
    70     '''
    72     _int_part = re.compile('[+-]?(\d*)(.*)')
    73     _num_chars = '0123456789+-'
    75     def __init__(self, part):
    76         self.numA = 0
    77         self.strB = None
    78         self.numC = 0
    79         self.extraD = None
    81         if not part:
    82             return
    84         if part == '*':
    85             self.numA = sys.maxint
    86         else:
    87             match = self._int_part.match(part)
    88             self.numA = int(match.group(1))
    89             self.strB = match.group(2) or None
    90         if self.strB == '+':
    91             self.strB = 'pre'
    92             self.numA += 1
    93         elif self.strB:
    94             i = 0
    95             num_found = -1
    96             for char in self.strB:
    97                 if char in self._num_chars:
    98                     num_found = i
    99                     break
   100                 i += 1
   101             if num_found != -1:
   102                 match = self._int_part.match(self.strB[num_found:])
   103                 self.numC = int(match.group(1))
   104                 self.extraD = match.group(2) or None
   105                 self.strB = self.strB[:num_found]
   107     def _strcmp(self, str1, str2):
   108         # Any string is *before* no string.
   109         if str1 is None:
   110             if str2 is None:
   111                 return 0
   112             else:
   113                 return 1
   115         if str2 is None:
   116             return -1
   118         return cmp(str1, str2)
   120     def __cmp__(self, other):
   121         r = cmp(self.numA, other.numA)
   122         if r:
   123             return r
   125         r = self._strcmp(self.strB, other.strB)
   126         if r:
   127             return r
   129         r = cmp(self.numC, other.numC)
   130         if r:
   131             return r
   133         return self._strcmp(self.extraD, other.extraD)
   135     def __repr__(self):
   136         return repr((self.numA, self.strB, self.numC, self.extraD))
   138 def compare(a, b):
   139     '''
   140     Examples:
   142       >>> compare('1', '2')
   143       -1
   145       >>> compare('1', '1')
   146       0
   148       >>> compare('2', '1')
   149       1
   151       >>> compare('1.0pre1', '1.0pre2')
   152       -1
   154       >>> compare('1.0pre2', '1.0')
   155       -1
   157       >>> compare('1.0', '1.0.0')
   158       0
   160       >>> compare('1.0.0', '1.0.0.0')
   161       0
   163       >>> compare('1.0.0.0', '1.1pre')
   164       -1
   166       >>> compare('1.1pre', '1.1pre0')
   167       0
   169       >>> compare('1.1pre0', '1.0+')
   170       0
   172       >>> compare('1.0+', '1.1pre1a')
   173       -1
   175       >>> compare('1.1pre1a', '1.1pre1')
   176       -1
   178       >>> compare('1.1pre1', '1.1pre10a')
   179       -1
   181       >>> compare('1.1pre10a', '1.1pre10')
   182       -1
   184       >>> compare('1.1pre10a', '1.*')
   185       -1
   186     '''
   188     a_parts = a.split('.')
   189     b_parts = b.split('.')
   191     if len(a_parts) < len(b_parts):
   192         a_parts.extend([''] * (len(b_parts) - len(a_parts)))
   193     else:
   194         b_parts.extend([''] * (len(a_parts) - len(b_parts)))
   196     for a_part, b_part in zip(a_parts, b_parts):
   197         r = cmp(VersionPart(a_part), VersionPart(b_part))
   198         if r:
   199             return r
   201     return 0
   203 if __name__ == '__main__':
   204     import doctest
   206     doctest.testmod(verbose=True)

mercurial