Ticket #2425: 0001-Add-new-numbering-scheme-2425.patch

File 0001-Add-new-numbering-scheme-2425.patch, 8.7 KB (added by erikos, 14 years ago)

toolkit: add class NormalizedVersion to parse and compare the new activity versions, change the bundlebuilder and activitybundle to use the new scheme

  • src/sugar/activity/bundlebuilder.py

    From aff5384700da45ad2af8424295c38733b45415e2 Mon Sep 17 00:00:00 2001
    From: Simon Schampijer <simon@schampijer.de>
    Date: Thu, 28 Oct 2010 09:45:08 +0200
    Subject: [PATCH] Add new numbering scheme #2425
    
    - add class NormalizedVersion to parse and compare the new activity versions
    - change the bundlebuilder and activitybundle to use the new scheme, instead
    of an int version we expect a string that matches the format defined in
    NormalizedVersion
    ---
     src/sugar/activity/bundlebuilder.py |    6 +-
     src/sugar/bundle/Makefile.am        |    1 +
     src/sugar/bundle/activitybundle.py  |   14 ++--
     src/sugar/bundle/bundleversion.py   |  157 +++++++++++++++++++++++++++++++++++
     4 files changed, 169 insertions(+), 9 deletions(-)
     create mode 100644 src/sugar/bundle/bundleversion.py
    
    diff --git a/src/sugar/activity/bundlebuilder.py b/src/sugar/activity/bundlebuilder.py
    index fc8ebc8..d9dd96d 100644
    a b class Config(object): 
    8686        self.bundle_id = bundle.get_bundle_id()
    8787        self.bundle_name = reduce(lambda x, y: x+y, self.activity_name.split())
    8888        self.bundle_root_dir = self.bundle_name + '.activity'
    89         self.tar_root_dir = '%s-%d' % (self.bundle_name, self.version)
     89        self.tar_root_dir = '%s-%s' % (self.bundle_name, self.version)
    9090
    9191        if self.dist_name:
    9292            self.xo_name = self.tar_name = self.dist_name
    9393        else:
    94             self.xo_name = '%s-%d.xo' % (self.bundle_name, self.version)
    95             self.tar_name = '%s-%d.tar.bz2' % (self.bundle_name, self.version)
     94            self.xo_name = '%s-%s.xo' % (self.bundle_name, self.version)
     95            self.tar_name = '%s-%s.tar.bz2' % (self.bundle_name, self.version)
    9696
    9797
    9898class Builder(object):
  • src/sugar/bundle/Makefile.am

    diff --git a/src/sugar/bundle/Makefile.am b/src/sugar/bundle/Makefile.am
    index f1af791..50c93de 100644
    a b sugar_PYTHON = \ 
    33        __init__.py                     \
    44        bundle.py                       \
    55        activitybundle.py               \
     6        bundleversion.py                \
    67        contentbundle.py
  • src/sugar/bundle/activitybundle.py

    diff --git a/src/sugar/bundle/activitybundle.py b/src/sugar/bundle/activitybundle.py
    index 3bbc250..f70afaa 100644
    a b from sugar import env 
    3232from sugar import util
    3333from sugar.bundle.bundle import Bundle, \
    3434    MalformedBundleException, NotInstalledException
    35 
     35from sugar.bundle.bundleversion import NormalizedVersion
     36from sugar.bundle.bundleversion import InvalidVersionError
    3637
    3738class ActivityBundle(Bundle):
    3839    """A Sugar activity bundle
    class ActivityBundle(Bundle): 
    5960        self._mime_types = None
    6061        self._show_launcher = True
    6162        self._tags = None
    62         self._activity_version = 0
     63        self._activity_version = '0'
    6364        self._installation_time = os.stat(path).st_mtime
    6465        self._manifest = None
    6566
    class ActivityBundle(Bundle): 
    197198        if cp.has_option(section, 'activity_version'):
    198199            version = cp.get(section, 'activity_version')
    199200            try:
    200                 self._activity_version = int(version)
    201             except ValueError:
    202                 raise MalformedBundleException(
    203                     'Activity bundle %s has invalid version number %s' %
     201                NormalizedVersion(version)
     202            except InvalidVersionError:
     203                raise MalformedBundleException( 
     204                    'Activity bundle %s has invalid version number %s' % 
    204205                    (self._path, version))
     206            self._activity_version = version
    205207
    206208    def _get_linfo_file(self):
    207209        lang = locale.getdefaultlocale()[0]
  • new file src/sugar/bundle/bundleversion.py

    diff --git a/src/sugar/bundle/bundleversion.py b/src/sugar/bundle/bundleversion.py
    new file mode 100644
    index 0000000..e763231
    - +  
     1# Copyright (C) 2010, OLPC
     2#
     3# This library is free software; you can redistribute it and/or
     4# modify it under the terms of the GNU Lesser General Public
     5# License as published by the Free Software Foundation; either
     6# version 2 of the License, or (at your option) any later version.
     7#
     8# This library is distributed in the hope that it will be useful,
     9# but WITHOUT ANY WARRANTY; without even the implied warranty of
     10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     11# Lesser General Public License for more details.
     12#
     13# You should have received a copy of the GNU Lesser General Public
     14# License along with this library; if not, write to the
     15# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     16# Boston, MA 02111-1307, USA.
     17
     18#
     19# Based on the implementation of PEP 386, but adapted to our
     20# numeration schema.
     21#
     22
     23import re
     24
     25
     26class InvalidVersionError(Exception):
     27    """The passed activity version can not be normalized."""
     28    pass
     29
     30VERSION_RE = re.compile(r'''
     31    ^
     32    (?P<version>\d+)               # minimum 'N'
     33    (?P<extraversion>(?:\.\d+)*)   # any number of extra '.N' segments
     34    (?:
     35    (?P<local>\-[a-zA-Z]*)         # ignore any string in the comparison
     36    )?
     37    $''', re.VERBOSE)
     38
     39
     40class NormalizedVersion(object):
     41    """A normalized version.
     42
     43    Good:
     44        1
     45        1.2
     46        1.2.3
     47        1.2.3-peru
     48
     49    Bad:
     50        1.2peru        # must be separated with -
     51        1.2.           # can't end with '.'
     52        1.02.5         # can't have a leading zero
     53
     54    """
     55
     56    def __init__(self, activity_version):
     57        """Create a NormalizedVersion instance from a version string.
     58
     59        Keyword arguments:
     60        activity_version -- The version string
     61
     62        """
     63        self._activity_version = activity_version
     64        self.parts = []
     65        self._local = None
     66
     67        if not isinstance(self._activity_version, str):
     68            raise InvalidVersionError(self._activity_version)
     69
     70        match = VERSION_RE.search(self._activity_version)
     71        if not match:
     72            raise InvalidVersionError(self._activity_version)
     73
     74        groups = match.groupdict()
     75
     76        version = self._parse_version(groups['version'])
     77        self.parts.append(version)
     78
     79        if groups['extraversion'] not in ('', None):
     80            versions = self._parse_extraversions(groups['extraversion'][1:])
     81            self.parts.extend(versions)
     82
     83        self._local = groups['local']
     84
     85    def _parse_version(self, version_string):
     86        """Verify that there is no leading zero and convert to integer.
     87
     88        Keyword arguments:
     89        version -- string to be parsed
     90
     91        Return: Version
     92
     93        """
     94        if len(version_string) > 1 and version_string[0] == '0':
     95            raise InvalidVersionError("Can not have leading zero in segment"
     96                                      " %s in %r" % (version_string,
     97                                      self._activity_version))
     98
     99        return int(version_string)
     100
     101    def _parse_extraversions(self, extraversion_string):
     102        """Split into N versions and convert them to integers, verify
     103        that there are no leading zeros and drop trailing zeros.
     104
     105        Keyword arguments:
     106        extraversion -- 'N.N.N...' sequence to be parsed
     107
     108        Return: List of extra versions
     109
     110        """
     111        nums = []
     112        for n in extraversion_string.split("."):
     113            if len(n) > 1 and n[0] == '0':
     114                raise InvalidVersionError("Can not have leading zero in "
     115                                          "segment %s in %r" % (n,
     116                                          self._activity_version))
     117            nums.append(int(n))
     118
     119        while nums and nums[-1] == 0:
     120            nums.pop()
     121
     122        return nums
     123
     124    def __str__(self):
     125        version_string = '.'.join(str(v) for v in self.parts)
     126        if self._local != None:
     127            version_string += self._local
     128        return version_string
     129
     130    def __repr__(self):
     131        return "%s('%s')" % (self.__class__.__name__, self)
     132
     133    def _cannot_compare(self, other):
     134        raise TypeError("Can not compare %s and %s"
     135                % (type(self).__name__, type(other).__name__))
     136
     137    def __eq__(self, other):
     138        if not isinstance(other, NormalizedVersion):
     139            self._cannot_compare(other)
     140        return self.parts == other.parts
     141
     142    def __lt__(self, other):
     143        if not isinstance(other, NormalizedVersion):
     144            self._cannot_compare(other)
     145        return self.parts < other.parts
     146
     147    def __ne__(self, other):
     148        return not self.__eq__(other)
     149
     150    def __gt__(self, other):
     151        return not (self.__lt__(other) or self.__eq__(other))
     152
     153    def __le__(self, other):
     154        return self.__eq__(other) or self.__lt__(other)
     155
     156    def __ge__(self, other):
     157        return self.__eq__(other) or self.__gt__(other)