diff options
-rw-r--r-- | src/sugar/bundle/activitybundle.py | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/src/sugar/bundle/activitybundle.py b/src/sugar/bundle/activitybundle.py index 542fa00..a87d01b 100644 --- a/src/sugar/bundle/activitybundle.py +++ b/src/sugar/bundle/activitybundle.py @@ -21,8 +21,10 @@ UNSTABLE. """ from ConfigParser import ConfigParser +import gettext import locale import os +import re import shutil import tempfile import logging @@ -36,6 +38,14 @@ from sugar.bundle.bundleversion import NormalizedVersion from sugar.bundle.bundleversion import InvalidVersionError +_ = lambda msg: gettext.dgettext('sugar-toolkit', msg) + + +class DependencyException(Exception): + """Required dependencies were not found.""" + pass + + class ActivityBundle(Bundle): """A Sugar activity bundle @@ -63,6 +73,7 @@ class ActivityBundle(Bundle): self._tags = None self._activity_version = '0' self._installation_time = os.stat(path).st_mtime + self._requires = [] info_file = self.get_file('activity/activity.info') if info_file is None: @@ -137,6 +148,11 @@ class ActivityBundle(Bundle): (self._path, version)) self._activity_version = version + if cp.has_option(section, 'requires'): + requires = cp.get(section, 'requires') + for dep in requires.replace('\n', ';').split(';'): + self._requires.extend(_parse_condition(dep)) + def _get_linfo_file(self): lang = locale.getdefaultlocale()[0] if not lang: @@ -339,3 +355,57 @@ class ActivityBundle(Bundle): def is_user_activity(self): return self.get_path().startswith(env.get_user_activities_path()) + + def meets_restriction(self, req_name, req_version): + version = _parse_version(req_version) + + for dep, dep_rels, dep_version, error_msg in self._requires: + if dep != req_name: + continue + errors = set() + for rel in dep_rels: + if cmp(version, dep_version) == rel: + errors.clear() + break + else: + errors.add(error_msg) + if errors: + error = _('Restriction was not met: %s') % ', '.join(errors) + raise DependencyException(error) + + +def _format_version(version): + return '.'.join([str(i) for i in version]) + + +def _parse_version(version): + return [int(i) if i.isdigit() else 0 for i in version.strip().split('.')] + + +def _parse_condition(dep): + match = re.split('(=|==|<|<=|>|>=|!=)\s*([0-9.]+)', dep) + if len(match) == 1: + return [] + if len(match) != 4 or match[-1]: + raise MalformedBundleException(_('Malformed requires, "%s"') % dep) + + result = [] + dep = match[0].strip() + arg = _parse_version(match[2]) + error_msg = '%s %s %s' % (dep, match[1], _format_version(arg)) + + if match[1] == '=' or match[1] == '==': + result.append((dep, [0, 1], arg, error_msg)) + result.append((dep, [-1], arg[:-1] + [arg[-1] + 1], error_msg)) + elif match[1] == '<': + result.append((dep, [-1], arg, error_msg)) + elif match[1] == '<=': + result.append((dep, [-1, 0], arg, error_msg)) + elif match[1] == '>': + result.append((dep, [1], arg, error_msg)) + elif match[1] == '>=': + result.append((dep, [1, 0], arg, error_msg)) + elif match[1] == '!=': + result.append((dep, [-1, 1], arg, error_msg)) + + return result |