[IMP] use the function from setuptools for compare the versions
bzr revid: christophe@tinyerp.com-20081201150404-if1qmgfl0f54po91
This commit is contained in:
parent
e8faaf5006
commit
cf6e0129fb
|
@ -35,112 +35,7 @@ import addons
|
|||
import pooler
|
||||
import netsvc
|
||||
|
||||
ver_regexp = re.compile("^(\\d+)((\\.\\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\\d*)*)(-r(\\d+))?$")
|
||||
suffix_regexp = re.compile("^(alpha|beta|rc|pre|p)(\\d*)$")
|
||||
|
||||
def vercmp(ver1, ver2):
|
||||
"""
|
||||
Compare two versions
|
||||
Take from portage_versions.py
|
||||
@param ver1: version to compare with
|
||||
@type ver1: string (example "1.2-r3")
|
||||
@param ver2: version to compare again
|
||||
@type ver2: string (example "2.1-r1")
|
||||
@rtype: None or float
|
||||
@return:
|
||||
1. position if ver1 is greater than ver2
|
||||
2. negative if ver1 is less than ver2
|
||||
3. 0 if ver1 equals ver2
|
||||
4. None if ver1 or ver2 are invalid
|
||||
"""
|
||||
|
||||
match1 = ver_regexp.match(ver1)
|
||||
match2 = ver_regexp.match(ver2)
|
||||
|
||||
if not match1 or not match1.groups():
|
||||
return None
|
||||
if not match2 or not match2.groups():
|
||||
return None
|
||||
|
||||
list1 = [int(match1.group(1))]
|
||||
list2 = [int(match2.group(1))]
|
||||
|
||||
if len(match1.group(2)) or len(match2.group(2)):
|
||||
vlist1 = match1.group(2)[1:].split(".")
|
||||
vlist2 = match2.group(2)[1:].split(".")
|
||||
for i in range(0, max(len(vlist1), len(vlist2))):
|
||||
# Implicit .0 is given -1, so 1.0.0 > 1.0
|
||||
# would be ambiguous if two versions that aren't literally equal
|
||||
# are given the same value (in sorting, for example).
|
||||
if len(vlist1) <= i or len(vlist1[i]) == 0:
|
||||
list1.append(-1)
|
||||
list2.append(int(vlist2[i]))
|
||||
elif len(vlist2) <= i or len(vlist2[i]) == 0:
|
||||
list1.append(int(vlist1[i]))
|
||||
list2.append(-1)
|
||||
# Let's make life easy and use integers unless we're forced to use floats
|
||||
elif (vlist1[i][0] != "0" and vlist2[i][0] != "0"):
|
||||
list1.append(int(vlist1[i]))
|
||||
list2.append(int(vlist2[i]))
|
||||
# now we have to use floats so 1.02 compares correctly against 1.1
|
||||
else:
|
||||
list1.append(float("0."+vlist1[i]))
|
||||
list2.append(float("0."+vlist2[i]))
|
||||
# and now the final letter
|
||||
if len(match1.group(4)):
|
||||
list1.append(ord(match1.group(4)))
|
||||
if len(match2.group(4)):
|
||||
list2.append(ord(match2.group(4)))
|
||||
|
||||
for i in range(0, max(len(list1), len(list2))):
|
||||
if len(list1) <= i:
|
||||
return -1
|
||||
elif len(list2) <= i:
|
||||
return 1
|
||||
elif list1[i] != list2[i]:
|
||||
return list1[i] - list2[i]
|
||||
|
||||
# main version is equal, so now compare the _suffix part
|
||||
list1 = match1.group(5).split("_")[1:]
|
||||
list2 = match2.group(5).split("_")[1:]
|
||||
|
||||
for i in range(0, max(len(list1), len(list2))):
|
||||
# Implicit _p0 is given a value of -1, so that 1 < 1_p0
|
||||
if len(list1) <= i:
|
||||
s1 = ("p","-1")
|
||||
else:
|
||||
s1 = suffix_regexp.match(list1[i]).groups()
|
||||
if len(list2) <= i:
|
||||
s2 = ("p","-1")
|
||||
else:
|
||||
s2 = suffix_regexp.match(list2[i]).groups()
|
||||
if s1[0] != s2[0]:
|
||||
return suffix_value[s1[0]] - suffix_value[s2[0]]
|
||||
if s1[1] != s2[1]:
|
||||
# it's possible that the s(1|2)[1] == ''
|
||||
# in such a case, fudge it.
|
||||
try:
|
||||
r1 = int(s1[1])
|
||||
except ValueError:
|
||||
r1 = 0
|
||||
try:
|
||||
r2 = int(s2[1])
|
||||
except ValueError:
|
||||
r2 = 0
|
||||
if r1 - r2:
|
||||
return r1 - r2
|
||||
|
||||
# the suffix part is equal to, so finally check the revision
|
||||
if match1.group(9):
|
||||
r1 = int(match1.group(9))
|
||||
else:
|
||||
r1 = 0
|
||||
if match2.group(9):
|
||||
r2 = int(match2.group(9))
|
||||
else:
|
||||
r2 = 0
|
||||
return r1 - r2
|
||||
|
||||
from parse_version import parse_version
|
||||
|
||||
class module_repository(osv.osv):
|
||||
_name = "ir.module.repository"
|
||||
|
@ -403,7 +298,7 @@ class module(osv.osv):
|
|||
terp = self.get_module_info(mod_name)
|
||||
if terp.get('installable', True) and mod.state == 'uninstallable':
|
||||
self.write(cr, uid, id, {'state': 'uninstalled'})
|
||||
if vercmp(terp.get('version', ''), mod.latest_version or '0') > 0:
|
||||
if parse_version(terp.get('version', '')) > parse_version(mod.latest_version or ''):
|
||||
self.write(cr, uid, id, {
|
||||
'latest_version': terp.get('version'),
|
||||
'url': ''})
|
||||
|
@ -472,7 +367,7 @@ class module(osv.osv):
|
|||
if version == 'x': # 'x' version was a mistake
|
||||
version = '0'
|
||||
if name in mod_sort:
|
||||
if vercmp(version, mod_sort[name][0]) <= 0:
|
||||
if parse_version(version) <= parse_version(mod_sort[name][0]):
|
||||
continue
|
||||
mod_sort[name] = [version, extension]
|
||||
for name in mod_sort.keys():
|
||||
|
@ -494,8 +389,7 @@ class module(osv.osv):
|
|||
['latest_version']
|
||||
if latest_version == 'x': # 'x' version was a mistake
|
||||
latest_version = '0'
|
||||
c = vercmp(version, latest_version)
|
||||
if c > 0:
|
||||
if parse_version(version) > parse_version(latest_version):
|
||||
self.write(cr, uid, id,
|
||||
{'latest_version': version, 'url': url})
|
||||
res[0] += 1
|
||||
|
@ -503,8 +397,7 @@ class module(osv.osv):
|
|||
['published_version']
|
||||
if published_version == 'x' or not published_version:
|
||||
published_version = '0'
|
||||
c = vercmp(version, published_version)
|
||||
if c > 0:
|
||||
if parse_version(version) > parse_version(published_version):
|
||||
self.write(cr, uid, id,
|
||||
{'published_version': version})
|
||||
return res
|
||||
|
@ -518,7 +411,7 @@ class module(osv.osv):
|
|||
version = '0'
|
||||
if match:
|
||||
version = match.group(1)
|
||||
if vercmp(mod.installed_version or '0', version) >= 0:
|
||||
if parse_version(mod.installed_version or '0') >= parse_version(version):
|
||||
continue
|
||||
res.append(mod.url)
|
||||
if not download:
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
|
||||
# $Id$
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
## this functions are taken from the setuptools package (version 0.6c8)
|
||||
## http://peak.telecommunity.com/DevCenter/PkgResources#parsing-utilities
|
||||
|
||||
import re
|
||||
|
||||
component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE)
|
||||
replace = {'pre':'c', 'preview':'c','-':'final-','rc':'c','dev':'@'}.get
|
||||
|
||||
def _parse_version_parts(s):
|
||||
for part in component_re.split(s):
|
||||
part = replace(part,part)
|
||||
if not part or part=='.':
|
||||
continue
|
||||
if part[:1] in '0123456789':
|
||||
yield part.zfill(8) # pad for numeric comparison
|
||||
else:
|
||||
yield '*'+part
|
||||
|
||||
yield '*final' # ensure that alpha/beta/candidate are before final
|
||||
|
||||
def parse_version(s):
|
||||
"""Convert a version string to a chronologically-sortable key
|
||||
|
||||
This is a rough cross between distutils' StrictVersion and LooseVersion;
|
||||
if you give it versions that would work with StrictVersion, then it behaves
|
||||
the same; otherwise it acts like a slightly-smarter LooseVersion. It is
|
||||
*possible* to create pathological version coding schemes that will fool
|
||||
this parser, but they should be very rare in practice.
|
||||
|
||||
The returned value will be a tuple of strings. Numeric portions of the
|
||||
version are padded to 8 digits so they will compare numerically, but
|
||||
without relying on how numbers compare relative to strings. Dots are
|
||||
dropped, but dashes are retained. Trailing zeros between alpha segments
|
||||
or dashes are suppressed, so that e.g. "2.4.0" is considered the same as
|
||||
"2.4". Alphanumeric parts are lower-cased.
|
||||
|
||||
The algorithm assumes that strings like "-" and any alpha string that
|
||||
alphabetically follows "final" represents a "patch level". So, "2.4-1"
|
||||
is assumed to be a branch or patch of "2.4", and therefore "2.4.1" is
|
||||
considered newer than "2.4-1", whic in turn is newer than "2.4".
|
||||
|
||||
Strings like "a", "b", "c", "alpha", "beta", "candidate" and so on (that
|
||||
come before "final" alphabetically) are assumed to be pre-release versions,
|
||||
so that the version "2.4" is considered newer than "2.4a1".
|
||||
|
||||
Finally, to handle miscellaneous cases, the strings "pre", "preview", and
|
||||
"rc" are treated as if they were "c", i.e. as though they were release
|
||||
candidates, and therefore are not as new as a version string that does not
|
||||
contain them.
|
||||
"""
|
||||
parts = []
|
||||
for part in _parse_version_parts(s.lower()):
|
||||
if part.startswith('*'):
|
||||
if part<'*final': # remove '-' before a prerelease tag
|
||||
while parts and parts[-1]=='*final-': parts.pop()
|
||||
# remove trailing zeros from each series of numeric parts
|
||||
while parts and parts[-1]=='00000000':
|
||||
parts.pop()
|
||||
parts.append(part)
|
||||
return tuple(parts)
|
||||
|
||||
if __name__ == '__main__':
|
||||
pvs = []
|
||||
for v in ('0', '4.2', '4.2.3.4', '5.0.0-alpha', '5.0.0-rc1', '5.0.0-rc1.1', '5.0.0'):
|
||||
pv = parse_version(v)
|
||||
print v, pv
|
||||
pvs.append(pv)
|
||||
|
||||
def cmp(a, b):
|
||||
assert(a < b)
|
||||
return b
|
||||
|
||||
reduce(cmp, pvs)
|
||||
|
Loading…
Reference in New Issue