Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/extensions/cpsection/updater/backends/microformat.py
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/cpsection/updater/backends/microformat.py')
-rw-r--r--extensions/cpsection/updater/backends/microformat.py203
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)