Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@member.fsf.org>2011-01-12 19:37:09 (GMT)
committer Anish Mangal <anish@activitycentral.com>2012-04-27 10:04:45 (GMT)
commit4a96592ea1879a21caf4dd07bc62791e07d88395 (patch)
treee05d1f8bab292e8edc837902120a1591b533eee8
parent5313e73d0fd37d810845ce2f83da3124eb2b8bae (diff)
Parse activity dependencies
It is a mimic of sweets' requires tag that will be used only for sugar dependency. Full functional dependency tracking will come with sweets support implementation in the shell. The format for requires optin in activity.info: requires = sugar (=|==|<|<=|>|>=) version [; ...]
-rw-r--r--src/sugar/bundle/activitybundle.py70
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