diff options
Diffstat (limited to 'sugar_network')
-rw-r--r-- | sugar_network/db/directory.py | 7 | ||||
-rw-r--r-- | sugar_network/model/context.py | 39 | ||||
-rw-r--r-- | sugar_network/node/routes.py | 69 |
3 files changed, 63 insertions, 52 deletions
diff --git a/sugar_network/db/directory.py b/sugar_network/db/directory.py index 6bb2d70..60d5c57 100644 --- a/sugar_network/db/directory.py +++ b/sugar_network/db/directory.py @@ -236,11 +236,14 @@ class Directory(object): if isinstance(self.metadata[prop], StoredProperty) and \ self.metadata[prop].localized: if isinstance(value, dict): - orig_value = dict([(i, orig[prop].get(i)) for i in value]) - if orig_value == value: + if value == dict([(i, orig[prop].get(i)) for i in value]): continue elif orig.get(prop, accept_language) == value: continue + elif isinstance(self.metadata[prop], BlobProperty) and \ + isinstance(value, dict) and \ + value.get('digest') == orig[prop].get('digest'): + continue patch[prop] = value return patch diff --git a/sugar_network/model/context.py b/sugar_network/model/context.py index 053228f..e885b53 100644 --- a/sugar_network/model/context.py +++ b/sugar_network/model/context.py @@ -13,7 +13,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -from cStringIO import StringIO from os.path import join from sugar_network import db, model, static @@ -127,41 +126,3 @@ class Context(db.Resource): @db.stored_property(typecast=dict, default={}, acl=ACL.PUBLIC | ACL.LOCAL) def packages(self, value): return value - - @staticmethod - def image_props(svg): - icon = StringIO(svg.read()) - return {'artifact_icon': { - 'blob': icon, - 'mime_type': 'image/svg+xml', - }, - 'icon': { - 'blob': _svg_to_png(icon.getvalue(), 55, 55), - 'mime_type': 'image/png', - }, - 'preview': { - 'blob': _svg_to_png(icon.getvalue(), 160, 120), - 'mime_type': 'image/png', - }, - } - - -def _svg_to_png(data, w, h): - import rsvg - import cairo - - svg = rsvg.Handle(data=data) - surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) - context = cairo.Context(surface) - - scale = min(float(w) / svg.props.width, float(h) / svg.props.height) - context.translate( - int(w - svg.props.width * scale) / 2, - int(h - svg.props.height * scale) / 2) - context.scale(scale, scale) - svg.render_cairo(context) - - result = StringIO() - surface.write_to_png(result) - result.seek(0) - return result diff --git a/sugar_network/node/routes.py b/sugar_network/node/routes.py index 80caba4..9b0e27f 100644 --- a/sugar_network/node/routes.py +++ b/sugar_network/node/routes.py @@ -19,13 +19,13 @@ import shutil import gettext import logging import hashlib +from cStringIO import StringIO from contextlib import contextmanager from ConfigParser import ConfigParser from os.path import join, isdir, exists from sugar_network import node, toolkit, model from sugar_network.node import stats_node, stats_user -from sugar_network.model.context import Context # pylint: disable-msg=W0611 from sugar_network.toolkit.router import route, preroute, postroute, ACL from sugar_network.toolkit.router import Unauthorized, Request, fallbackroute @@ -418,7 +418,6 @@ def load_bundle(volume, request, bundle_path): if 'initial' in impl: initial = impl.pop('initial') data = impl.setdefault('data', {}) - data['blob'] = bundle_path contexts = volume['context'] context = impl.get('context') context_meta = None @@ -445,7 +444,8 @@ def load_bundle(volume, request, bundle_path): context = impl['context'] = spec['context'] impl['version'] = spec['version'] impl['stability'] = spec['stability'] - impl['license'] = spec['license'] + if spec['license'] is not EMPTY_LICENSE: + impl['license'] = spec['license'] data['spec'] = {'*-*': { 'commands': spec.commands, 'requires': spec.requires, @@ -463,25 +463,37 @@ def load_bundle(volume, request, bundle_path): enforce('version' in impl, 'Version is not specified') enforce(context_type in contexts.get(context)['type'], http.BadRequest, 'Inappropriate bundle type') - if impl.get('license') in (None, EMPTY_LICENSE): + if 'license' not in impl: existing, total = impls.find( context=context, order_by='-version', not_layer='deleted') enforce(total, 'License is not specified') impl['license'] = next(existing)['license'] + digest = hashlib.sha1() + with file(bundle_path, 'rb') as f: + while True: + chunk = f.read(toolkit.BUFFER_SIZE) + if not chunk: + break + digest.update(chunk) + data['digest'] = digest.hexdigest() + yield impl existing, __ = impls.find( context=context, version=impl['version'], not_layer='deleted') + if 'url' not in data: + data['blob'] = bundle_path impl['guid'] = \ request.call(method='POST', path=['implementation'], content=impl) for i in existing: layer = i['layer'] + ['deleted'] impls.update(i.guid, {'layer': layer}) - patch = contexts.patch(context, context_meta) - if patch and 'origin' in impls.get(impl['guid']).layer: - request.call(method='PUT', path=['context', context], content=patch) + if 'origin' in impls.get(impl['guid']).layer: + diff = contexts.patch(context, context_meta) + if diff: + request.call(method='PUT', path=['context', context], content=diff) def _load_context_metadata(bundle, spec): @@ -491,8 +503,18 @@ def _load_context_metadata(bundle, spec): result[prop] = spec[prop] try: - with bundle.extractfile(join(bundle.rootdir, spec['icon'])) as svg: - result.update(Context.image_props(svg)) + icon_file = bundle.extractfile(join(bundle.rootdir, spec['icon'])) + icon = StringIO(icon_file.read()) + icon_file.close() + result.update({ + 'artifact_icon': { + 'blob': icon, + 'mime_type': 'image/svg+xml', + 'digest': hashlib.sha1(icon.getvalue()).hexdigest(), + }, + 'preview': _svg_to_png(icon.getvalue(), 160, 120), + 'icon': _svg_to_png(icon.getvalue(), 55, 55), + }) except Exception: exception(_logger, 'Failed to load icon') @@ -518,10 +540,35 @@ def _load_context_metadata(bundle, spec): i18n = gettext.translation(spec['context'], join(tmpdir, *mo_path[:2]), [lang]) for prop, value in msgids.items(): - msgstr = i18n.gettext(value) - if msgstr != value or lang == 'en': + msgstr = i18n.gettext(value).decode('utf8') + if lang == 'en' or msgstr != value: result[prop][lang] = msgstr except Exception: exception(_logger, 'Gettext failed to read %r', mo_path[-1]) return result + + +def _svg_to_png(data, w, h): + import rsvg + import cairo + + svg = rsvg.Handle(data=data) + surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) + context = cairo.Context(surface) + + scale = min(float(w) / svg.props.width, float(h) / svg.props.height) + context.translate( + int(w - svg.props.width * scale) / 2, + int(h - svg.props.height * scale) / 2) + context.scale(scale, scale) + svg.render_cairo(context) + + result = StringIO() + surface.write_to_png(result) + result.seek(0) + + return {'blob': result, + 'mime_type': 'image/png', + 'digest': hashlib.sha1(result.getvalue()).hexdigest(), + } |