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.

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

mercurial