Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@sugarlabs.org>2013-05-26 07:38:23 (GMT)
committer Aleksey Lim <alsroot@sugarlabs.org>2013-05-26 07:38:56 (GMT)
commitbcbacf88eb0847085538029452ae0b8e80a77e36 (patch)
tree18593fbd2213ae0be1735594da5db9cbdad3514d
parente12c1b54791a8526ccab3aca9aca60912fc769d6 (diff)
Update Context strings from .xo bundles
-rwxr-xr-xmisc/aslo-sync208
1 files changed, 127 insertions, 81 deletions
diff --git a/misc/aslo-sync b/misc/aslo-sync
index 5ff1f12..e94c89a 100755
--- a/misc/aslo-sync
+++ b/misc/aslo-sync
@@ -18,9 +18,8 @@
import os
import time
import getpass
-import tempfile
-import subprocess
-from os.path import join, exists
+from ConfigParser import ConfigParser
+from os.path import join
import MySQLdb as mdb
@@ -122,6 +121,12 @@ LICENSES_MAP = {
'au.net.acid.Jam2Jam1': ['GPLv2+'],
}
+ACTIVITY_I18N_PROPS = [
+ ('title', 'name'),
+ ('summary', 'summary'),
+ ('description', 'description'),
+ ]
+
class Application(application.Application):
@@ -208,6 +213,45 @@ class Application(application.Application):
self.sync_activities()
@application.command(
+ 'pull activities metadata from activities.sugarlabs.org')
+ def pull_metadata(self):
+ sql = """
+ SELECT
+ id,
+ guid
+ FROM
+ addons
+ WHERE
+ status > 0 AND status < 5
+ """
+ for addon_id in self.args:
+ sql += ' AND id = %s' % addon_id
+
+ for addon_id, bundle_id in self.sqlexec(sql):
+ impls, __ = self.volume['implementation'].find(
+ context=bundle_id, order_by='-version', limit=1)
+ for impl in impls:
+ version = impl['version']
+ break
+ else:
+ continue
+ rows = self.sqlexec("""
+ SELECT
+ files.filename
+ FROM versions
+ INNER JOIN files ON files.version_id = versions.id
+ WHERE
+ versions.addon_id = %s AND versions.version = '%s'
+ ORDER BY
+ versions.id DESC
+ LIMIT
+ 1
+ """ % (addon_id, version))
+ if not rows:
+ continue
+ self.sync_context_metadata(bundle_id, addon_id, rows[0][0])
+
+ @application.command(
'submit pulled activities.sugarlabs.org content to '
'Sugar Network server')
def push(self):
@@ -294,10 +338,12 @@ class Application(application.Application):
applications_versions.version_id=versions.id
WHERE
addons.status > 0 AND addons.status < 5 AND addons.id = %s
+ ORDER BY
+ versions.id DESC
""" % addon_id
recent_version = None
- recent_impl = None
+ recent_filename = None
for version_id, version, status, license_id, alicense, release_date, \
releasenotes, filename, sugar_min, sugar_max \
@@ -305,6 +351,10 @@ class Application(application.Application):
if version_id in IGNORE_VERSIONS:
continue
+ if filename.endswith('.xol'):
+ print '-- Ignore library bundles for %r' % bundle_id
+ continue
+
try:
parsed_version = util.parse_version(version)
except Exception, error:
@@ -312,10 +362,6 @@ class Application(application.Application):
(version, bundle_id, error)
continue
- if self.volume['implementation'].find(
- context=bundle_id, version=version)[1] > 0:
- continue
-
if license_id is None:
pass
elif license_id == 0:
@@ -343,40 +389,67 @@ class Application(application.Application):
(alicense, filename, addon_id)
continue
- try:
- impl = self.sync_implementaiton(bundle_id,
- 'http://download.sugarlabs.org/activities/%s/%s' %
- (addon_id, filename),
- sugar_min, sugar_max,
- stability='stable' if status == 4 else 'developer',
- date=int(time.mktime(release_date.timetuple())),
- notes=self.get_i18n_field(releasenotes),
- license=alicense if alicense else [],
- )
- except Exception, error:
- print '-- Failed to sync %s for %s: %s' % \
- (version, bundle_id, error)
- continue
+ if self.volume['implementation'].find(
+ context=bundle_id, version=version)[1] == 0:
+ try:
+ self.sync_implementaiton(bundle_id, addon_id, filename,
+ sugar_min, sugar_max,
+ stability='stable' if status == 4 else 'developer',
+ date=int(time.mktime(release_date.timetuple())),
+ notes=self.get_i18n_field(releasenotes),
+ license=alicense if alicense else [],
+ )
+ except Exception, error:
+ print '-- Failed to sync %s for %s: %s' % \
+ (version, bundle_id, error)
+ continue
- if impl and parsed_version > recent_version:
+ if parsed_version > recent_version:
recent_version = parsed_version
- recent_impl = impl
+ recent_filename = filename
if recent_version:
- icon = recent_impl.pop('artifact_icon')
- self.volume['context'].update(bundle_id, **recent_impl)
- self.volume['context'].set_blob(bundle_id, 'artifact_icon', icon)
-
- with tempfile.NamedTemporaryFile() as f:
- f.write(icon)
- f.flush()
- self.svg_to_png(f.name, 'context', bundle_id, 'icon', [
- '-adaptive-resize', '55x55',
- ])
- self.svg_to_png(f.name, 'context', bundle_id, 'preview', [
- '-density', '400',
- '-adaptive-resize', '160x120',
- ])
+ self.sync_context_metadata(bundle_id, addon_id, recent_filename)
+
+ def sync_context_metadata(self, bundle_id, addon_id, filename):
+ bundle = Bundle(join(ACTIVITIES_PATH, str(addon_id), filename))
+ spec = bundle.get_spec()
+
+ props = {}
+ for prop in ('homepage', 'mime_types'):
+ if spec[prop]:
+ props[prop] = spec[prop]
+
+ try:
+ svg = bundle.extractfile(join(bundle.extract, spec['icon']))
+ icon = props['artifact_icon'] = svg.read()
+ png = svg_to_png(icon, '--width=55', '--height=55')
+ if png:
+ props['icon'] = png
+ png = svg_to_png(icon, '--width=160', '--height=120')
+ if png:
+ props['preview'] = png
+ except Exception, error:
+ print '-- Cannot find activity icon: %s' % error
+
+ for prop, confname in ACTIVITY_I18N_PROPS:
+ if spec[confname]:
+ props[prop] = {'en': spec[confname]}
+ for path in bundle.get_names():
+ locale_path = path.split(os.sep)
+ if len(locale_path) < 3 or locale_path[-3] != 'locale' or \
+ locale_path[-1] != 'activity.linfo':
+ continue
+ config = ConfigParser()
+ config.readfp(bundle.extractfile(path))
+ lang = locale_path[-2].replace('_', '-').lower()
+ for prop, confname in ACTIVITY_I18N_PROPS:
+ if config.has_option('Activity', confname):
+ value = config.get('Activity', confname)
+ props.setdefault(prop, {})[lang] = value
+
+ print '-- Update %r metadata from %r' % (bundle_id, filename)
+ self.volume['context'].update(bundle_id, **props)
def sync_context(self, addon_id, bundle_id):
if not self.volume['context'].exists(bundle_id):
@@ -444,26 +517,12 @@ class Application(application.Application):
ctime=created,
mtime=modified)
- def sync_implementaiton(self, context, url, sugar_min, sugar_max,
- **impl_props):
- path = url[len(DOWNLOAD_URL):].strip('/').split('/')
- path = join(ACTIVITIES_PATH, *path)
- if path.endswith('.xol'):
- return None
- if not exists(path):
- print '-- Cannot find ASLO bundle at %s' % path
- return None
-
- try:
- bundle = Bundle(path)
- except Exception, error:
- print '-- Cannor read %s bundle: %s' % (path, error)
- return None
-
+ def sync_implementaiton(self, context, addon_id, filename,
+ sugar_min, sugar_max, **impl_props):
+ bundle = Bundle(join(ACTIVITIES_PATH, addon_id, filename))
spec = bundle.get_spec()
if spec is None:
- print '-- Bundle %s does not contain spec' % path
- return None
+ raise Exception('Bundle does not contain spec file')
if not impl_props['license']:
impl_props['license'] = self.parse_license(spec['license'])
@@ -471,9 +530,7 @@ class Application(application.Application):
if context in LICENSES_MAP:
impl_props['license'] = LICENSES_MAP[context]
else:
- print '-- Skip bad license %r from %s' % \
- (spec['license'], path)
- return None
+ raise Exception('Skip bad license %r' % spec['license'])
print '-- Add %r version to %r activity' % (spec['version'], context)
@@ -503,13 +560,8 @@ class Application(application.Application):
ctime=time.time(), mtime=time.time(),
author=self.authors(),
**impl_props)
- self.volume['implementation'].set_blob(impl, 'data', url=url)
-
- icon = bundle.extractfile(join(bundle.extract, spec['icon'])).read()
- return {'homepage': spec['homepage'] or '',
- 'mime_types': spec['mime_types'] or [],
- 'artifact_icon': icon,
- }
+ self.volume['implementation'].set_blob(impl, 'data',
+ url='/'.join([DOWNLOAD_URL, addon_id, filename]))
def parse_license(self, alicense):
for good in licenses.GOOD_LICENSES:
@@ -556,21 +608,6 @@ class Application(application.Application):
cursor.execute(text)
return cursor.fetchall()
- def svg_to_png(self, src, document, guid, prop, args):
- dst = src + '.png'
- try:
- subprocess.check_call(
- ['convert', '-background', 'none'] +
- args +
- [src, dst])
- with file(dst) as f:
- self.volume[document].set_blob(guid, prop, f)
- except Exception, error:
- print '-- Cannot convert SVG icon: %s' % error
- finally:
- if exists(dst):
- os.unlink(dst)
-
def authors(self, original=None):
result = {
ASLO_GUID: {
@@ -584,6 +621,15 @@ class Application(application.Application):
return result
+def svg_to_png(svg, *args):
+ try:
+ return util.assert_call(
+ ('rsvg-convert', '--keep-aspect-ratio') + args,
+ stdin=svg)
+ except Exception, error:
+ print '-- Cannot convert SVG icon: %s' % error
+
+
mysql_server = Option(
'MySQL server',
default='localhost', name='mysql_server')