diff options
author | Aleksey Lim <alsroot@sugarlabs.org> | 2012-03-26 18:42:46 (GMT) |
---|---|---|
committer | Aleksey Lim <alsroot@sugarlabs.org> | 2012-03-26 18:42:46 (GMT) |
commit | da6f0b92e2e58b5d8ad7c4f0dc901a4e07c932de (patch) | |
tree | f9a0d9b62ff180299a0bb3c8981ac177356b925a | |
parent | f1dcc4e647e4f06127e3c4f41d2f7aaa40f46022 (diff) |
Keep feed for entire context to avoid needless queries
-rw-r--r-- | doc/objects.dia | 107 | ||||
-rwxr-xr-x | misc/aslo_sync.py | 55 | ||||
-rw-r--r-- | sugar_network_server/resources/context.py | 100 | ||||
-rw-r--r-- | sugar_network_server/resources/implementation.py | 76 | ||||
-rw-r--r-- | sugar_network_server/resources/resource.py | 2 |
5 files changed, 193 insertions, 147 deletions
diff --git a/doc/objects.dia b/doc/objects.dia index 4579ae3..b3e7ce2 100644 --- a/doc/objects.dia +++ b/doc/objects.dia @@ -87,19 +87,19 @@ <dia:layer name="Background" visible="true" active="true"> <dia:object type="UML - Class" version="0" id="O0"> <dia:attribute name="obj_pos"> - <dia:point val="30,25"/> + <dia:point val="30,21"/> </dia:attribute> <dia:attribute name="obj_bb"> - <dia:rectangle val="29.985,24.985;48.6675,51.015"/> + <dia:rectangle val="29.985,20.985;48.6675,51.815"/> </dia:attribute> <dia:attribute name="elem_corner"> - <dia:point val="30,25"/> + <dia:point val="30,21"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="18.6525"/> </dia:attribute> <dia:attribute name="elem_height"> - <dia:real val="26"/> + <dia:real val="30.800000000000001"/> </dia:attribute> <dia:attribute name="name"> <dia:string>#Context#</dia:string> @@ -197,7 +197,7 @@ <dia:string>#type#</dia:string> </dia:attribute> <dia:attribute name="type"> - <dia:string>#enum [R WN S]#</dia:string> + <dia:string>#[enum] [R WN S]#</dia:string> </dia:attribute> <dia:attribute name="value"> <dia:string>##</dia:string> @@ -355,6 +355,29 @@ </dia:composite> <dia:composite type="umlattribute"> <dia:attribute name="name"> + <dia:string>#mime_types#</dia:string> + </dia:attribute> + <dia:attribute name="type"> + <dia:string>#[str] [R WA]#</dia:string> + </dia:attribute> + <dia:attribute name="value"> + <dia:string>#[]#</dia:string> + </dia:attribute> + <dia:attribute name="comment"> + <dia:string>#List of MIME types that supported for Artifacts created within the Context#</dia:string> + </dia:attribute> + <dia:attribute name="visibility"> + <dia:enum val="0"/> + </dia:attribute> + <dia:attribute name="abstract"> + <dia:boolean val="false"/> + </dia:attribute> + <dia:attribute name="class_scope"> + <dia:boolean val="false"/> + </dia:attribute> + </dia:composite> + <dia:composite type="umlattribute"> + <dia:attribute name="name"> <dia:string>#icon#</dia:string> </dia:attribute> <dia:attribute name="type"> @@ -401,6 +424,29 @@ </dia:composite> <dia:composite type="umlattribute"> <dia:attribute name="name"> + <dia:string>#feed#</dia:string> + </dia:attribute> + <dia:attribute name="type"> + <dia:string>#blob [R]#</dia:string> + </dia:attribute> + <dia:attribute name="value"> + <dia:string>##</dia:string> + </dia:attribute> + <dia:attribute name="comment"> + <dia:string>#Zero Instrall feed informaiton#</dia:string> + </dia:attribute> + <dia:attribute name="visibility"> + <dia:enum val="0"/> + </dia:attribute> + <dia:attribute name="abstract"> + <dia:boolean val="false"/> + </dia:attribute> + <dia:attribute name="class_scope"> + <dia:boolean val="false"/> + </dia:attribute> + </dia:composite> + <dia:composite type="umlattribute"> + <dia:attribute name="name"> <dia:string>#rating#</dia:string> </dia:attribute> <dia:attribute name="type"> @@ -1050,17 +1096,17 @@ </dia:object> <dia:object type="UML - Association" version="2" id="O3"> <dia:attribute name="obj_pos"> - <dia:point val="48.6676,38"/> + <dia:point val="48.6676,36.4"/> </dia:attribute> <dia:attribute name="obj_bb"> - <dia:rectangle val="48.65,37.24;53.0176,54.84"/> + <dia:rectangle val="48.65,35.64;53.0176,54.84"/> </dia:attribute> <dia:attribute name="meta"> <dia:composite type="dict"/> </dia:attribute> <dia:attribute name="orth_points"> - <dia:point val="48.6676,38"/> - <dia:point val="51,38"/> + <dia:point val="48.6676,36.4"/> + <dia:point val="51,36.4"/> <dia:point val="51,54"/> <dia:point val="53,54"/> </dia:attribute> @@ -1124,7 +1170,7 @@ <dia:color val="#000000ff"/> </dia:attribute> <dia:connections> - <dia:connection handle="0" to="O0" connection="30"/> + <dia:connection handle="0" to="O0" connection="34"/> </dia:connections> </dia:object> <dia:object type="UML - Association" version="2" id="O4"> @@ -1209,17 +1255,17 @@ </dia:object> <dia:object type="UML - Association" version="2" id="O5"> <dia:attribute name="obj_pos"> - <dia:point val="39.3263,51"/> + <dia:point val="39.3263,51.8"/> </dia:attribute> <dia:attribute name="obj_bb"> - <dia:rectangle val="39.3087,50.24;40.1,54.84"/> + <dia:rectangle val="39.3086,51.04;40.1,54.84"/> </dia:attribute> <dia:attribute name="meta"> <dia:composite type="dict"/> </dia:attribute> <dia:attribute name="orth_points"> - <dia:point val="39.3263,51"/> - <dia:point val="40,51"/> + <dia:point val="39.3263,51.8"/> + <dia:point val="40,51.8"/> <dia:point val="40,54"/> <dia:point val="39.5,54"/> </dia:attribute> @@ -3651,7 +3697,7 @@ <dia:point val="54,38"/> </dia:attribute> <dia:attribute name="obj_bb"> - <dia:rectangle val="53.985,37.985;65.6275,64.415"/> + <dia:rectangle val="53.985,37.985;65.6275,61.615"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="54,38"/> @@ -3660,7 +3706,7 @@ <dia:real val="11.612500000000001"/> </dia:attribute> <dia:attribute name="elem_height"> - <dia:real val="26.400000000000006"/> + <dia:real val="23.600000000000005"/> </dia:attribute> <dia:attribute name="name"> <dia:string>#Implementation#</dia:string> @@ -3893,29 +3939,6 @@ </dia:composite> <dia:composite type="umlattribute"> <dia:attribute name="name"> - <dia:string>#feed#</dia:string> - </dia:attribute> - <dia:attribute name="type"> - <dia:string>#dict [R WN]#</dia:string> - </dia:attribute> - <dia:attribute name="value"> - <dia:string>##</dia:string> - </dia:attribute> - <dia:attribute name="comment"> - <dia:string>#Zero Install Implementation parameters to add to feed#</dia:string> - </dia:attribute> - <dia:attribute name="visibility"> - <dia:enum val="0"/> - </dia:attribute> - <dia:attribute name="abstract"> - <dia:boolean val="false"/> - </dia:attribute> - <dia:attribute name="class_scope"> - <dia:boolean val="false"/> - </dia:attribute> - </dia:composite> - <dia:composite type="umlattribute"> - <dia:attribute name="name"> <dia:string>#bundle#</dia:string> </dia:attribute> <dia:attribute name="type"> @@ -4175,16 +4198,16 @@ </dia:object> <dia:object type="UML - Association" version="2" id="O24"> <dia:attribute name="obj_pos"> - <dia:point val="59.8062,64.4"/> + <dia:point val="59.8062,61.6"/> </dia:attribute> <dia:attribute name="obj_bb"> - <dia:rectangle val="59.7886,64.3824;68.0176,73.14"/> + <dia:rectangle val="59.7886,61.5824;68.0176,73.14"/> </dia:attribute> <dia:attribute name="meta"> <dia:composite type="dict"/> </dia:attribute> <dia:attribute name="orth_points"> - <dia:point val="59.8062,64.4"/> + <dia:point val="59.8062,61.6"/> <dia:point val="59.8062,72.3"/> <dia:point val="68,72.3"/> </dia:attribute> diff --git a/misc/aslo_sync.py b/misc/aslo_sync.py index fde4b6a..68e31e8 100755 --- a/misc/aslo_sync.py +++ b/misc/aslo_sync.py @@ -7,6 +7,8 @@ import getpass import MySQLdb as mdb +from sweets_recipe import GOOD_LICENSES + import restful_document import sugar_network as client import sugar_network_server as server @@ -79,25 +81,20 @@ def import_versions(): (select max(localized_string) from translations where id=licenses.text), versions.created, - versions.version, (select max(localized_string) from translations where id=versions.releasenotes), - files.filename, - (select version from appversions where - id=applications_versions.min), - (select version from appversions where - id=applications_versions.max) + files.filename FROM addons INNER JOIN versions ON versions.addon_id=addons.id INNER JOIN licenses ON licenses.id=versions.license_id INNER JOIN files ON files.version_id=versions.id INNER JOIN applications_versions ON applications_versions.version_id=versions.id - WHERE addons.status=4 + WHERE addons.status=4 and addons.id = 4037 """) for row in rows: - addon_id, bundle_id, license_id, alicense, release_date, version, \ - releasenotes, filename, sugar_min, sugar_max = row + addon_id, bundle_id, license_id, alicense, release_date, \ + releasenotes, filename = row if [i for i in EXCLUDE_BUNDLE_IDS if i in bundle_id]: continue @@ -116,7 +113,7 @@ def import_versions(): elif license_id == 6: alicense = 'BSD' else: - for good in server.GOOD_LICENSES: + for good in GOOD_LICENSES: if not alicense or good in ['ec']: continue if good in alicense: @@ -136,27 +133,17 @@ def import_versions(): for i in client.Context.find(implement=[bundle_id]): if i['implement'] == [bundle_id]: - context_guid = i['guid'] + context = i break else: - context_guid = context_new(addon_id, bundle_id) - - impl = client.Implementation() - impl['context'] = context_guid - impl['license'] = [alicense] - impl['version'] = version - impl['date'] = int(time.mktime(release_date.timetuple())) - impl['stability'] = 'stable' - impl['notes'] = releasenotes or '' - impl['feed'] = { - 'requires': { - sugar_guid: {'constraints': sugar_max}, - }, - } - impl.post() - impl.set_blob_with_url('bundle', - 'http://download.sugarlabs.org/activities/%s/%s' % \ - (addon_id, filename)) + context = context_new(addon_id, bundle_id) + + context.call('release-from-aslo', 'POST', + url='http://download.sugarlabs.org/activities/%s/%s' % \ + (addon_id, filename), + notes=releasenotes or 'Mirror activity from ASLO', + date=int(time.mktime(release_date.timetuple())), + licenses=alicense) def context_new(addon_id, bundle_id): @@ -210,7 +197,7 @@ def context_new(addon_id, bundle_id): context.post() if icondata: - context.set_blob('icon', icondata) + context.blobs['icon'] = icondata for row in sqlexec(""" SELECT @@ -232,11 +219,11 @@ def context_new(addon_id, bundle_id): artifact.post() if thumb: - artifact.set_blob('preview', thumb) + artifact.blobs['preview'] = thumb if data: - artifact.set_blob('data', data) + artifact.blobs['data'] = data - return context['guid'] + return context def sqlexec(text): @@ -255,7 +242,7 @@ if __name__ == '__main__': server.index_flush_timeout.value = 0 server.trust_users.value = True - server_pid = restful_document.fork(server.resources()) + server_pid = restful_document.fork(server.resources) client.api_url.value = \ 'http://%s:%s' % (server.host.value, server.port.value) diff --git a/sugar_network_server/resources/context.py b/sugar_network_server/resources/context.py index 1777146..0cfa534 100644 --- a/sugar_network_server/resources/context.py +++ b/sugar_network_server/resources/context.py @@ -15,21 +15,32 @@ # pylint: disable-msg=E1101,E0102 +import os +import json +from cStringIO import StringIO +from os.path import exists, join +from gettext import gettext as _ + import active_document as ad +import restful_document as rd +from sweets_recipe import Bundle +enforce = ad.util.enforce from sugar_network_server import env from sugar_network_server.resources.resource import Resource, Vote +_ASLO_DOWNLOAD_URL = 'http://download.sugarlabs.org/activities' +_ASLO_ACTIVITIES_PATH = '/upload/activities' + + class Context(Resource): - @ad.active_property(slot=1, prefix='T', - permissions=ad.ACCESS_CREATE | ad.ACCESS_READ, - typecast=env.CONTEXT_TYPES) + @ad.active_property(prefix='T', typecast=[env.CONTEXT_TYPES]) def type(self, value): return value - @ad.active_property(slot=2, prefix='N', full_text=True, + @ad.active_property(slot=1, prefix='N', full_text=True, permissions=ad.ACCESS_READ, default='') def name(self, value): return value @@ -43,7 +54,7 @@ class Context(Resource): def implement(self, value): return value - @ad.active_property(slot=3, prefix='S', full_text=True) + @ad.active_property(slot=2, prefix='S', full_text=True) def title(self, value): return value @@ -51,7 +62,7 @@ class Context(Resource): def title(self, value): return value - @ad.active_property(slot=4, prefix='R', full_text=True) + @ad.active_property(slot=3, prefix='R', full_text=True) def summary(self, value): return value @@ -67,7 +78,7 @@ class Context(Resource): def description(self, value): return value - @ad.active_property(slot=5, prefix='H', default='', full_text=True) + @ad.active_property(slot=4, prefix='H', default='', full_text=True) def homepage(self, value): return value @@ -75,11 +86,24 @@ class Context(Resource): def homepage(self, value): return value + @ad.active_property(prefix='Y', default=[], typecast=[]) + def mime_types(self, value): + return value + @ad.active_property(ad.BlobProperty) def icon(self, value): return value - @ad.active_property(ad.CounterProperty, slot=6) + @ad.active_property(ad.BlobProperty) + def artifact_icon(self, value): + return value + + @ad.active_property(ad.BlobProperty, + permissions=ad.ACCESS_READ, mime_type='application/json') + def feed(self, value): + return value + + @ad.active_property(ad.CounterProperty, slot=5) def rating(self, value): return value @@ -90,3 +114,63 @@ class Context(Resource): @vote.setter def vote(self, value): return value + + @rd.restful_method(method='POST', cmd='release-from-aslo') + def _release_from_aslo(self, url, date, notes, licenses): + from sugar_network_server import resources + + enforce(rd.principal.user in self.author, rd.Forbidden, + _('Operation is permitted only for authors')) + enforce(url.startswith(_ASLO_DOWNLOAD_URL)) + + path = url[len(_ASLO_DOWNLOAD_URL):].strip('/').split('/') + enforce(len(path) == 2 and path[-1].endswith('.xo'), + _('Incorrect activities.sugarlabs.org path')) + path = join(_ASLO_ACTIVITIES_PATH, *path) + enforce(exists(path), _('Cannot find ASLO bundle at %s'), path) + + bundle = Bundle(path) + spec = bundle.get_spec() + # TODO + #spec.lint() + + feed_data = self.get_blob('feed') + if feed_data is None: + feed = {} + else: + feed = json.load(feed_data) + + impl = resources.Implementation( + author=[rd.principal.user], + context=self.guid, + license=licenses, + version=spec.version, + date=date, + stability=spec.stability, + notes=notes) + impl.post() + + if not feed or spec.version >= max(feed.keys()): + self['type'] = spec.types + self['title'] = spec.name + self['summary'] = spec.summary + self['description'] = spec.description + self['homepage'] = spec.homepage + self['tags'] = spec.tags + self['mime_types'] = spec.mime_types + self.post() + + icon_path = join(bundle.extract, spec.icon) + self.set_blob('artifact_icon', bundle.extractfile(icon_path)) + + feed.setdefault(spec.version, {}) + feed[spec.version]['*-*'] = { + 'guid': impl.guid, + 'stability': spec.stability, + 'commands': spec.commands, + 'requires': spec.requires, + 'url': url, + 'extract': bundle.extract, + 'size': os.stat(path).st_size, + } + self.set_blob('feed', StringIO(json.dumps(feed)), raw=True) diff --git a/sugar_network_server/resources/implementation.py b/sugar_network_server/resources/implementation.py index 8b2f5ad..a766375 100644 --- a/sugar_network_server/resources/implementation.py +++ b/sugar_network_server/resources/implementation.py @@ -15,26 +15,16 @@ # pylint: disable-msg=E1101,E0102,E0202 -import os -import zipfile -from cStringIO import StringIO -from ConfigParser import ConfigParser -from os.path import exists, join -from gettext import gettext as _ +import json import active_document as ad import restful_document as rd -enforce = ad.util.enforce +from sweets_recipe import GOOD_LICENSES from sugar_network_server import env -from sugar_network_server.licenses import GOOD_LICENSES from sugar_network_server.resources.resource import Resource -_ASLO_DOWNLOAD_URL = 'http://download.sugarlabs.org/activities' -_ASLO_ACTIVITIES_PATH = '/upload/activities' - - class Implementation(Resource): @ad.active_property(prefix='C', @@ -63,16 +53,6 @@ class Implementation(Resource): def stability(self, value): return value - @ad.active_property(ad.StoredProperty, typecast=dict, default={}) - def feed(self, value): - return value - - @feed.setter - def feed(self, value): - value.setdefault('implementations', {}) - value['implementations'].setdefault('*-*', {}) - return value - @ad.active_property(full_text=True, permissions=ad.ACCESS_CREATE | ad.ACCESS_READ) def notes(self, value): @@ -82,45 +62,17 @@ class Implementation(Resource): def bundle(self, value): return value - def recv_blob(self, prop, url): - if not url.startswith(_ASLO_DOWNLOAD_URL): - return Resource.recv_blob(self, prop, url) - - path = url[len(_ASLO_DOWNLOAD_URL):].strip('/').split('/') - enforce(len(path) == 2 and path[-1].endswith('.xo'), - _('Incorrect activities.sugarlabs.org path')) - - feed = self.feed - feed['implementations']['*-*']['url'] = url - - path = join(_ASLO_ACTIVITIES_PATH, *path) - if exists(path): - try: - zp = zipfile.ZipFile(path) - extract = zp.namelist()[0].split(os.sep)[0] - - activity_info_data = StringIO( - zp.read(join(extract, 'activity', 'activity.info'))) - activity_info = ConfigParser() - activity_info.readfp(activity_info_data) - - if activity_info.has_option('Activity', 'exec'): - exec_cmd = activity_info.get('Activity', 'exec') - else: - exec_cmd = 'sugar-activity %s' % \ - activity_info.get('Activity', 'class') - feed['commands'] = { - 'activity': exec_cmd, - } - except Exception, error: - ad.util.exception() - raise RuntimeError(_('Cannot read bundle: %s') % error) - - self.feed = feed - self.post() - def send_blob(self, prop): - url = self.feed['implementations']['*-*'].get('url') - if url: - raise rd.SeeOther(url) + from sugar_network_server import resources + + context = resources.Context(self['context']) + feed_data = context.get_blob('feed') + + if feed_data is not None: + feed = json.load(feed_data) + if self['version'] in feed: + url = feed[self['version']]['*-*'].get('url') + if url: + raise rd.SeeOther(url) + return Resource.send_blob(self, prop) diff --git a/sugar_network_server/resources/resource.py b/sugar_network_server/resources/resource.py index 2e2e3d4..204a3bd 100644 --- a/sugar_network_server/resources/resource.py +++ b/sugar_network_server/resources/resource.py @@ -33,7 +33,7 @@ class Resource(rd.Document): def author(self, value): return value - @ad.active_property(prefix='OT', full_text=True, default=[], typecast=[]) + @ad.active_property(prefix='OT', default=[], typecast=[]) def tags(self, value): return value |