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
This commit is contained in:
		
							parent
							
								
									d8217d293e
								
							
						
					
					
						commit
						c7a80a1e56
					
				| @ -86,13 +86,13 @@ class Config(object): | ||||
|         self.bundle_id = bundle.get_bundle_id() | ||||
|         self.bundle_name = reduce(lambda x, y: x+y, self.activity_name.split()) | ||||
|         self.bundle_root_dir = self.bundle_name + '.activity' | ||||
|         self.tar_root_dir = '%s-%d' % (self.bundle_name, self.version) | ||||
|         self.tar_root_dir = '%s-%s' % (self.bundle_name, self.version) | ||||
| 
 | ||||
|         if self.dist_name: | ||||
|             self.xo_name = self.tar_name = self.dist_name | ||||
|         else: | ||||
|             self.xo_name = '%s-%d.xo' % (self.bundle_name, self.version) | ||||
|             self.tar_name = '%s-%d.tar.bz2' % (self.bundle_name, self.version) | ||||
|             self.xo_name = '%s-%s.xo' % (self.bundle_name, self.version) | ||||
|             self.tar_name = '%s-%s.tar.bz2' % (self.bundle_name, self.version) | ||||
| 
 | ||||
| 
 | ||||
| class Builder(object): | ||||
|  | ||||
| @ -3,4 +3,5 @@ sugar_PYTHON =				\ | ||||
| 	__init__.py			\
 | ||||
| 	bundle.py			\
 | ||||
| 	activitybundle.py		\
 | ||||
| 	bundleversion.py		\
 | ||||
| 	contentbundle.py | ||||
|  | ||||
| @ -32,7 +32,8 @@ from sugar import env | ||||
| from sugar import util | ||||
| from sugar.bundle.bundle import Bundle, \ | ||||
|     MalformedBundleException, NotInstalledException | ||||
| 
 | ||||
| from sugar.bundle.bundleversion import NormalizedVersion | ||||
| from sugar.bundle.bundleversion import InvalidVersionError | ||||
| 
 | ||||
| class ActivityBundle(Bundle): | ||||
|     """A Sugar activity bundle | ||||
| @ -59,7 +60,7 @@ class ActivityBundle(Bundle): | ||||
|         self._mime_types = None | ||||
|         self._show_launcher = True | ||||
|         self._tags = None | ||||
|         self._activity_version = 0 | ||||
|         self._activity_version = '0' | ||||
|         self._installation_time = os.stat(path).st_mtime | ||||
|         self._manifest = None | ||||
| 
 | ||||
| @ -197,11 +198,12 @@ class ActivityBundle(Bundle): | ||||
|         if cp.has_option(section, 'activity_version'): | ||||
|             version = cp.get(section, 'activity_version') | ||||
|             try: | ||||
|                 self._activity_version = int(version) | ||||
|             except ValueError: | ||||
|                 NormalizedVersion(version) | ||||
|             except InvalidVersionError: | ||||
|                 raise MalformedBundleException( | ||||
|                     'Activity bundle %s has invalid version number %s' % | ||||
|                     (self._path, version)) | ||||
|             self._activity_version = version | ||||
| 
 | ||||
|     def _get_linfo_file(self): | ||||
|         lang = locale.getdefaultlocale()[0] | ||||
|  | ||||
							
								
								
									
										157
									
								
								src/sugar/bundle/bundleversion.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								src/sugar/bundle/bundleversion.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,157 @@ | ||||
| # Copyright (C) 2010, OLPC | ||||
| # | ||||
| # This library is free software; you can redistribute it and/or | ||||
| # modify it under the terms of the GNU Lesser General Public | ||||
| # License as published by the Free Software Foundation; either | ||||
| # version 2 of the License, or (at your option) any later version. | ||||
| # | ||||
| # This library 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 | ||||
| # Lesser General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU Lesser General Public | ||||
| # License along with this library; if not, write to the | ||||
| # Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||||
| # Boston, MA 02111-1307, USA. | ||||
| 
 | ||||
| # | ||||
| # Based on the implementation of PEP 386, but adapted to our | ||||
| # numeration schema. | ||||
| # | ||||
| 
 | ||||
| import re | ||||
| 
 | ||||
| 
 | ||||
| class InvalidVersionError(Exception): | ||||
|     """The passed activity version can not be normalized.""" | ||||
|     pass | ||||
| 
 | ||||
| VERSION_RE = re.compile(r''' | ||||
|     ^ | ||||
|     (?P<version>\d+)               # minimum 'N' | ||||
|     (?P<extraversion>(?:\.\d+)*)   # any number of extra '.N' segments | ||||
|     (?: | ||||
|     (?P<local>\-[a-zA-Z]*)         # ignore any string in the comparison | ||||
|     )? | ||||
|     $''', re.VERBOSE) | ||||
| 
 | ||||
| 
 | ||||
| class NormalizedVersion(object): | ||||
|     """A normalized version. | ||||
| 
 | ||||
|     Good: | ||||
|         1 | ||||
|         1.2 | ||||
|         1.2.3 | ||||
|         1.2.3-peru | ||||
| 
 | ||||
|     Bad: | ||||
|         1.2peru        # must be separated with - | ||||
|         1.2.           # can't end with '.' | ||||
|         1.02.5         # can't have a leading zero | ||||
| 
 | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, activity_version): | ||||
|         """Create a NormalizedVersion instance from a version string. | ||||
| 
 | ||||
|         Keyword arguments: | ||||
|         activity_version -- The version string | ||||
| 
 | ||||
|         """ | ||||
|         self._activity_version = activity_version | ||||
|         self.parts = [] | ||||
|         self._local = None | ||||
| 
 | ||||
|         if not isinstance(self._activity_version, str): | ||||
|             raise InvalidVersionError(self._activity_version) | ||||
| 
 | ||||
|         match = VERSION_RE.search(self._activity_version) | ||||
|         if not match: | ||||
|             raise InvalidVersionError(self._activity_version) | ||||
| 
 | ||||
|         groups = match.groupdict() | ||||
| 
 | ||||
|         version = self._parse_version(groups['version']) | ||||
|         self.parts.append(version) | ||||
| 
 | ||||
|         if groups['extraversion'] not in ('', None): | ||||
|             versions = self._parse_extraversions(groups['extraversion'][1:]) | ||||
|             self.parts.extend(versions) | ||||
| 
 | ||||
|         self._local = groups['local'] | ||||
| 
 | ||||
|     def _parse_version(self, version_string): | ||||
|         """Verify that there is no leading zero and convert to integer. | ||||
| 
 | ||||
|         Keyword arguments: | ||||
|         version -- string to be parsed | ||||
| 
 | ||||
|         Return: Version | ||||
| 
 | ||||
|         """ | ||||
|         if len(version_string) > 1 and version_string[0] == '0': | ||||
|             raise InvalidVersionError("Can not have leading zero in segment" | ||||
|                                       " %s in %r" % (version_string, | ||||
|                                       self._activity_version)) | ||||
| 
 | ||||
|         return int(version_string) | ||||
| 
 | ||||
|     def _parse_extraversions(self, extraversion_string): | ||||
|         """Split into N versions and convert them to integers, verify | ||||
|         that there are no leading zeros and drop trailing zeros. | ||||
| 
 | ||||
|         Keyword arguments: | ||||
|         extraversion -- 'N.N.N...' sequence to be parsed | ||||
| 
 | ||||
|         Return: List of extra versions | ||||
| 
 | ||||
|         """ | ||||
|         nums = [] | ||||
|         for n in extraversion_string.split("."): | ||||
|             if len(n) > 1 and n[0] == '0': | ||||
|                 raise InvalidVersionError("Can not have leading zero in " | ||||
|                                           "segment %s in %r" % (n, | ||||
|                                           self._activity_version)) | ||||
|             nums.append(int(n)) | ||||
| 
 | ||||
|         while nums and nums[-1] == 0: | ||||
|             nums.pop() | ||||
| 
 | ||||
|         return nums | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         version_string = '.'.join(str(v) for v in self.parts) | ||||
|         if self._local != None: | ||||
|             version_string += self._local | ||||
|         return version_string | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         return "%s('%s')" % (self.__class__.__name__, self) | ||||
| 
 | ||||
|     def _cannot_compare(self, other): | ||||
|         raise TypeError("Can not compare %s and %s" | ||||
|                 % (type(self).__name__, type(other).__name__)) | ||||
| 
 | ||||
|     def __eq__(self, other): | ||||
|         if not isinstance(other, NormalizedVersion): | ||||
|             self._cannot_compare(other) | ||||
|         return self.parts == other.parts | ||||
| 
 | ||||
|     def __lt__(self, other): | ||||
|         if not isinstance(other, NormalizedVersion): | ||||
|             self._cannot_compare(other) | ||||
|         return self.parts < other.parts | ||||
| 
 | ||||
|     def __ne__(self, other): | ||||
|         return not self.__eq__(other) | ||||
| 
 | ||||
|     def __gt__(self, other): | ||||
|         return not (self.__lt__(other) or self.__eq__(other)) | ||||
| 
 | ||||
|     def __le__(self, other): | ||||
|         return self.__eq__(other) or self.__lt__(other) | ||||
| 
 | ||||
|     def __ge__(self, other): | ||||
|         return self.__eq__(other) or self.__gt__(other) | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Simon Schampijer
						Simon Schampijer