diff options
Diffstat (limited to 'extensions/cpsection/updater/backends/microformat.py')
-rw-r--r-- | extensions/cpsection/updater/backends/microformat.py | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/extensions/cpsection/updater/backends/microformat.py b/extensions/cpsection/updater/backends/microformat.py new file mode 100644 index 0000000..97499aa --- /dev/null +++ b/extensions/cpsection/updater/backends/microformat.py @@ -0,0 +1,203 @@ +#!/usr/bin/python +# +# Copyright (C) 2011, Anish Mangal <anish@sugarlabs.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import logging +from HTMLParser import HTMLParser +import urllib +import re + +import gio +import gobject +import gconf + +from jarabe import config + +client = gconf.client_get_default() +_UPDATE_PATH = client.get_string('/desktop/sugar/updater_url') +_ACTIVITIES_LIST = {} +ACTION_CHECKING = 0 +ACTION_UPDATING = 1 +ACTION_DOWNLOADING = 2 + +class MicroformatParser(HTMLParser): + + def __init__(self, data, completion_cb): + HTMLParser.__init__(self) + self.reset() + self._data_to_parse = data + self._activity_id = '' + self._activity_url = '' + self._activity_version = '' + self._activity_size = 1 + self._activity_name = '' + self._inside_activity_block = False + self._inside_activity_version = False + self._inside_activity_id = False + self._inside_activity_url = False + self._inside_activity_size = False + self._inside_activity_name = False + self._activity_block_tag = '' + self._completion_cb = completion_cb + + def parse(self): + self.feed(self._data_to_parse) + + def handle_endtag(self, tag): + if tag == self._activity_block_tag and self._inside_activity_block: + self._inside_activity_block = False + + _ACTIVITIES_LIST[self._activity_id] = \ + {'version':self._activity_version, + 'url':self._activity_url, + 'size':self._activity_size, + 'name':self._activity_name} + + elif tag == 'a': + if self._inside_activity_url: + self._inside_activity_url = False + + elif tag == 'body': + num_bundles = len(_ACTIVITIES_LIST) + progress = num_bundles + for bundle, info in _ACTIVITIES_LIST.items(): + progress = progress + 1 + if _ACTIVITIES_LIST[bundle]['size'] == 1: + try: + _ACTIVITIES_LIST[bundle]['size'] = \ + gio.File(_ACTIVITIES_LIST[bundle]['url']).\ + query_info('*').get_size() + + except Exception, e: + logging.exception(e) + + if _ACTIVITIES_LIST[bundle]['size'] == 0: + logging.error('Size of activity %s reported as ' + '0 bytes. Excluding from update list' % bundle) + del _ACTIVITIES_LIST[bundle] + + elif _ACTIVITIES_LIST[bundle]['name'] == '': + # Do some regex magic to get the 'probable' + # activity name. + activity_name = re.split('\.', + bundle)[-1] + activity_name = re.sub('^[\s|\t]*', '', + activity_name) + activity_name = re.sub('[\s|\t]*$', '', + activity_name) + activity_name = re.sub('[A|a]ctivity$', '', + activity_name) + _ACTIVITIES_LIST[bundle]['name'] = \ + activity_name + + self._completion_cb(_ACTIVITIES_LIST, None) + + def handle_starttag(self, tag, attrs): + for attribute, value in attrs: + if value == 'olpc-activity-info': + self._inside_activity_block = True + self._activity_block_tag = tag + + if tag == 'span': + for attribute, value in attrs: + if value == 'olpc-activity-id': + self._inside_activity_id = True + elif value == 'olpc-activity-version': + self._inside_activity_version = True + elif value == 'olpc-activity-name': + self._inside_activity_name = True + elif value == 'olpc-activity-size': + self._inside_activity_size = True + elif value == 'olpc-activity-url': + self._inside_activity_url = True + + elif tag == 'a': + if self._inside_activity_url: + for attribute, value in attrs: + if attribute == 'href': + self._activity_url = value + + def handle_data(self, data): + if self._inside_activity_version: + self._activity_version = int(data) + self._inside_activity_version = False + + elif self._inside_activity_id: + self._activity_id = data + self._inside_activity_id = False + + elif self._inside_activity_name: + self._activity_name = data + self._inside_activity_name = False + + elif self._inside_activity_size: + self._activity_size = int(data) + self._inside_activity_size = False + +class _UpdateFetcher(gobject.GObject): + + __gsignals__ = { + 'progress': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, + ([int, str, float, int])), + } + + def __init__(self, completion_cb): + gobject.GObject.__init__(self) + # ASLO knows only about stable SP releases + major, minor = config.version.split('.')[0:2] + sp_version = '%s.%s' % (major, int(minor) + int(minor) % 2) + self._data = '' + self._completion_cb = completion_cb + + def download_bundle_updates(self): + self.emit('progress', ACTION_CHECKING, 'Fetching update ' + 'information', 1, 3) + self._url = _UPDATE_PATH + self._file = gio.File(self._url) + logging.debug('Fetch %s', self._url) + self._file.read_async(self.__read_async_cb) + + def __read_async_cb(self, gfile, result): + try: + stream = gfile.read_finish(result) + except gio.Error, e: + self.stop() + logging.exception('Error while fetching content from %s' % + self._url) + return + stream.read_async(4096, self.__stream_read_cb) + + def __stream_read_cb(self, stream, result): + data = stream.read_finish(result) + if not data: + self._data_finished() + return + self._data_read(data) + stream.read_async(4096, self.__stream_read_cb) + + def _data_read(self, data): + self._data += data + + def read_finish(self): + pass + + def _data_finished(self): + self.emit('progress', ACTION_CHECKING, 'Fetching update ' + 'information', 2, 3) + parser = MicroformatParser(self._data, self._completion_cb) + gobject.idle_add(parser.parse) |