Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/sugar_network
diff options
context:
space:
mode:
Diffstat (limited to 'sugar_network')
-rw-r--r--sugar_network/db/directory.py7
-rw-r--r--sugar_network/model/context.py39
-rw-r--r--sugar_network/node/routes.py69
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(),
+ }