def _check_next_update(self): if self._cancelling or len(self._bundles_to_check) == 0: self._completion_cb(self._updates) return total = self._total_bundles_to_check current = total - len(self._bundles_to_check) progress = current / float(total) self._bundle_update = self._bundles_to_check.pop() _logger.debug("Check %s", self._bundle_update.bundle_id) # There is no need for a special name lookup for an automatic update. # The name lookup is only for UI purposes, but we are running in the # background. if self._bundle_update.name is None and self._auto: self._bundle_update.name = self._bundle_update.bundle_id if self._bundle_update.name is not None: # if we know the name, we just perform an asynchronous size check _logger.debug("Performing async size lookup") size_check = Downloader(self._bundle_update.link) size_check.connect('complete', self._size_lookup_cb) size_check.get_size() self._progress_cb(self._bundle_update.name, progress) else: # if we don't know the name, we run a metadata lookup and get # the size and name that way _logger.debug("Performing metadata lookup") namelookup = MetadataLookup(self._bundle_update.link) namelookup.connect('complete', self._name_lookup_complete) namelookup.run() self._progress_cb(self._bundle_update.bundle_id, progress)
def test_get_size(self): downloader = Downloader("http://0.0.0.0:%d/data/test.txt" % self._port) self._complete = False downloader.connect('complete', self.download_complete_cb) downloader.get_size() while not self._complete: Gtk.main_iteration() self.assertEqual(6, self._result)
def _do_download(self, method, **kwargs): # set up Downloader, call method on it with given kwargs, wait for # response self._complete = False downloader = Downloader(self._url) downloader.connect('complete', self._downloader_complete_cb) getattr(downloader, method)(**kwargs) while not self._complete: Gtk.main_iteration() if isinstance(self._result, Exception): raise self._result
def check(self, bundle): # ASLO knows only about stable SP releases major, minor = config.version.split('.')[0:2] sp_version = '%s.%s' % (major, int(minor) + int(minor) % 2) url = '%s?id=%s&appVersion=%s' % \ (_UPDATE_PATH, bundle.get_bundle_id(), sp_version) self._bundle = bundle _logger.debug('Fetch %s', url) self._downloader = Downloader(url) self._downloader.connect('complete', self.__downloader_complete_cb) self._downloader.download()
def fetch_update_info(self, installed_bundles, auto, progress_cb, completion_cb, error_cb): self._completion_cb = completion_cb self._progress_cb = progress_cb self._error_cb = error_cb self._bundles = installed_bundles self._progress_cb('', 0) # Set the status to 'Looking for updates' settings = Gio.Settings('org.sugarlabs.update') data_json_url = settings.get_string('new-aslo-url') self._downloader = Downloader(data_json_url) self._downloader.connect('complete', self.__data_json_download_complete_cb) self._downloader.download()
def check(self, bundle): # ASLO knows only about stable SP releases major, minor = config.version.split(".")[0:2] sp_version = "%s.%s" % (major, int(minor) + int(minor) % 2) url = "%s?id=%s&appVersion=%s" % (_UPDATE_PATH, bundle.get_bundle_id(), sp_version) self._bundle = bundle _logger.debug("Fetch %s", url) self._downloader = Downloader(url) self._downloader.connect("complete", self.__downloader_complete_cb) self._downloader.download()
def _download_next_update(self): if self._cancelling: self._finished(True) return if len(self._bundles_to_update) == 0: self._finished() return self._state = STATE_DOWNLOADING self._bundle_update = self._bundles_to_update.pop() _logger.debug("Downloading update for %s", self._bundle_update.bundle_id) total = self._total_bundles_to_update * 2 current = total - len(self._bundles_to_update) * 2 - 2 progress = current / float(total) self.emit('progress', self._state, self._bundle_update.name, progress) self._downloader = Downloader(self._bundle_update.link) self._downloader.connect('progress', self.__downloader_progress_cb) self._downloader.connect('complete', self.__downloader_complete_cb) self._downloader.download_to_temp()
def test_download_to_temp(self): downloader = Downloader("http://0.0.0.0:%d/data/test.txt" % self._port) self._complete = False downloader.connect('complete', self.download_complete_cb) downloader.download_to_temp() while not self._complete: Gtk.main_iteration() self.assertIsNone(self._result) path = downloader.get_local_file_path() text = open(path, "r").read() self.assertEqual("hello\n", text)
def _query(self): self.clean() settings = Gio.Settings.new(_MICROFORMAT_URL_PATH) url = settings.get_string(_MICROFORMAT_URL_KEY) _logger.debug("Query %s %r", url, url) if url == "": self._completion_cb([]) return self._parser = _UpdateHTMLParser(url) # wiki.laptop.org have agresive cache, we set max-age=600 # to be sure the page is no older than 10 minutes request_headers = {'Cache-Control': 'max-age=600'} downloader = Downloader(url, request_headers=request_headers) downloader.connect('got-chunk', self._got_chunk_cb) downloader.connect('complete', self._complete_cb) downloader.download_chunked() self._progress_cb(None, 0)
def _query(self): self.clean() settings = Gio.Settings(_MICROFORMAT_URL_PATH) url = settings.get_string(_MICROFORMAT_URL_KEY) _logger.debug("Query %s %r", url, url) if url == "": self._completion_cb([]) return self._parser = _UpdateHTMLParser(url) # wiki.laptop.org have agresive cache, we set max-age=600 # to be sure the page is no older than 10 minutes request_headers = {'Cache-Control': 'max-age=600'} downloader = Downloader(url, request_headers=request_headers) downloader.connect('got-chunk', self._got_chunk_cb) downloader.connect('complete', self._complete_cb) downloader.download_chunked() self._progress_cb(None, 0)
class NewAsloUpdater(object): """ Checks for updates using the new ASLO's update.json file """ def __init__(self): self._completion_cb = None self._progress_cb = None self._error_cb = None self._bundles = [] self._downloader = None self._canceled = False def fetch_update_info(self, installed_bundles, auto, progress_cb, completion_cb, error_cb): self._completion_cb = completion_cb self._progress_cb = progress_cb self._error_cb = error_cb self._bundles = installed_bundles self._progress_cb('', 0) # Set the status to 'Looking for updates' settings = Gio.Settings('org.sugarlabs.update') data_json_url = settings.get_string('new-aslo-url') self._downloader = Downloader(data_json_url) self._downloader.connect('complete', self.__data_json_download_complete_cb) self._downloader.download() def __data_json_download_complete_cb(self, downloader, result): if self._canceled: return try: activities = json.loads(result.get_data())['activities'] except ValueError: self._error_cb('Can not parse loaded update.json') return updates = [] for i, bundle in enumerate(self._bundles): self._progress_cb(bundle.get_name(), i/len(self._bundles)) if bundle.get_bundle_id() not in activities: logging.debug('%s not in activities' % bundle.get_bundle_id()) continue activity = activities[bundle.get_bundle_id()] try: version = NormalizedVersion(str(activity['version'])) min_sugar = NormalizedVersion(str(activity['minSugarVersion'])) except KeyError: logging.debug('KeyError - %s' % bundle.get_bundle_id()) continue except InvalidVersionError: logging.debug('InvalidVersion - %s' % bundle.get_bundle_id()) continue if NormalizedVersion(bundle.get_activity_version()) >= version: logging.debug('%s is up to date' % bundle.get_bundle_id()) continue if NormalizedVersion(config.version) < min_sugar: logging.debug('Upgrade sugar for %s' % bundle.get_bundle_id()) continue logging.debug('Marked for update: %s' % bundle.get_bundle_id()) u = BundleUpdate(bundle.get_bundle_id(), bundle.get_name(), version, activity['xo_url'], activity.get('xo_size', 1024 * 2)) updates.append(u) self._completion_cb(updates) def cancel(self): self._canceled = True if self._downloader: self._downloader.cancel() self._completion_cb(None) def clean(self): self._canceled = False
class Updater(GObject.GObject): __gtype_name__ = 'SugarUpdater' __gsignals__ = { 'updates-available': (GObject.SignalFlags.RUN_FIRST, None, (object,)), 'progress': (GObject.SignalFlags.RUN_FIRST, None, (int, str, float)), 'finished': (GObject.SignalFlags.RUN_FIRST, None, (object, object, bool)) } def __init__(self): GObject.GObject.__init__(self) settings = Gio.Settings(_UPDATE_KEYS_PATH) backend = settings.get_string(_UPDATE_BACKEND_KEY) module_name, class_name = backend.rsplit('.', 1) _logger.debug("Use backend %s.%s", module_name, class_name) module = importlib.import_module("jarabe.model.update." + module_name) self._model = getattr(module, class_name)() self._updates = None self._bundles_to_update = None self._total_bundles_to_update = 0 self._bundle_update = None self._bundles_updated = None self._bundles_failed = None self._downloader = None self._cancelling = False self._state = STATE_IDLE self._auto = False def get_state(self): return self._state def trigger_automatic_update(self): if self._state == STATE_IDLE: _logger.debug("Starting automatic activity update") self.check_updates(True) def check_updates(self, auto=False): if self._state not in (STATE_IDLE, STATE_CHECKED): raise UpdaterStateException() self._auto = auto self._updates = [] self._bundles_updated = [] self._bundles_failed = [] self._state = STATE_CHECKING bundles = list(bundleregistry.get_registry()) self._model.fetch_update_info(bundles, auto, self._backend_progress_cb, self._backend_finished_cb) def _backend_progress_cb(self, bundle_name, progress): self.emit('progress', self._state, bundle_name, progress) def _backend_finished_cb(self, updates): _logger.debug("_backend_finished_cb") if self._cancelling: self._finished(True) return self._updates = updates self._state = STATE_CHECKED if self._auto: self.update(None) else: self.emit('updates-available', self._updates) def update(self, bundle_ids): if self._state != STATE_CHECKED: raise UpdaterStateException() if bundle_ids is None: self._bundles_to_update = self._updates else: self._bundles_to_update = [] for bundle_update in self._updates: if bundle_update.bundle_id in bundle_ids: self._bundles_to_update.append(bundle_update) self._total_bundles_to_update = len(self._bundles_to_update) _logger.debug("Starting update of %d activities", self._total_bundles_to_update) self._download_next_update() def _download_next_update(self): if self._cancelling: self._finished(True) return if len(self._bundles_to_update) == 0: self._finished() return self._state = STATE_DOWNLOADING self._bundle_update = self._bundles_to_update.pop() _logger.debug("Downloading update for %s", self._bundle_update.bundle_id) total = self._total_bundles_to_update * 2 current = total - len(self._bundles_to_update) * 2 - 2 progress = current / float(total) self.emit('progress', self._state, self._bundle_update.name, progress) self._downloader = Downloader(self._bundle_update.link) self._downloader.connect('progress', self.__downloader_progress_cb) self._downloader.connect('complete', self.__downloader_complete_cb) self._downloader.download_to_temp() def __downloader_complete_cb(self, downloader, result): if self._cancelling: self._cleanup_downloader() self._finished(True) return if isinstance(result, Exception): _logger.error('Error downloading update: %s', result) self._cleanup_downloader() self._bundles_failed.append(self._bundle_update) self._download_next_update() else: self._install_update(self._bundle_update, self._downloader.get_local_file_path()) self._downloader = None def __downloader_progress_cb(self, downloader, progress): total = self._total_bundles_to_update * 2 current = total - len(self._bundles_to_update) * 2 - 2 + progress progress = current / float(total) self.emit('progress', self._state, self._bundle_update.name, progress) def _install_update(self, bundle_update, local_file_path): self._state = STATE_UPDATING total = self._total_bundles_to_update current = total - len(self._bundles_to_update) - 0.5 progress = current / float(total) _logger.debug("Installing update for %s", bundle_update.bundle_id) self.emit('progress', self._state, bundle_update.name, progress) current += 0.5 bundle = bundle_from_archive(local_file_path) registry = bundleregistry.get_registry() registry.install_async(bundle, self._bundle_installed_cb, current) def _bundle_installed_cb(self, bundle, result, progress): _logger.debug("%s installed: %r", bundle.get_bundle_id(), result) progress = progress / float(self._total_bundles_to_update) self.emit('progress', self._state, bundle.get_name(), progress) # Remove downloaded bundle archive try: os.unlink(bundle.get_path()) except OSError: pass if result is True: self._bundles_updated.append(bundle) else: self._bundles_failed.append(bundle) # do it in idle so the UI has a chance to refresh GLib.idle_add(self._download_next_update) def _finished(self, cancelled=False): self._state = STATE_IDLE self._cancelling = False _logger.debug("Update finished") self.emit('finished', self._bundles_updated, self._bundles_failed, cancelled) if not cancelled and len(self._bundles_failed) == 0: settings = Gio.Settings(_UPDATE_KEYS_PATH) settings.set_int(_LAST_UPDATE_KEY, time.time()) try: os.unlink(_URGENT_TRIGGER_FILE) except OSError: pass def cancel(self): # From STATE_CHECKED we can cancel immediately. if self._state == STATE_CHECKED: self._state = STATE_IDLE return self._cancelling = True self._model.cancel() if self._downloader: self._downloader.cancel() def _cleanup_downloader(self): if self._downloader is None: return file_path = self._downloader.get_local_file_path() if file_path is not None: try: os.unlink(file_path) except OSError: pass
class _UpdateChecker(GObject.GObject): __gsignals__ = { 'check-complete': (GObject.SignalFlags.RUN_FIRST, None, (object,)), } _CHUNK_SIZE = 10240 def __init__(self): GObject.GObject.__init__(self) self._bundle = None def check(self, bundle): # ASLO knows only about stable SP releases major, minor = config.version.split('.')[0:2] sp_version = '%s.%s' % (major, int(minor) + int(minor) % 2) url = '%s?id=%s&appVersion=%s' % \ (_UPDATE_PATH, bundle.get_bundle_id(), sp_version) self._bundle = bundle _logger.debug('Fetch %s', url) self._downloader = Downloader(url) self._downloader.connect('complete', self.__downloader_complete_cb) self._downloader.download() def __downloader_complete_cb(self, downloader, result): if isinstance(result, Exception): self.emit('check-complete', result) return if result is None: _logger.error('No XML update data returned from ASLO') return document = XML(result.get_data()) if document.find(_FIND_DESCRIPTION) is None: _logger.debug('Bundle %s not available in the server for the ' 'version %s', self._bundle.get_bundle_id(), config.version) version = None link = None size = None self.emit('check-complete', None) return try: version = NormalizedVersion(document.find(_FIND_VERSION).text) except InvalidVersionError: _logger.exception('Exception occurred while parsing version') self.emit('check-complete', None) return link = document.find(_FIND_LINK).text try: size = long(document.find(_FIND_SIZE).text) * 1024 except ValueError: _logger.exception('Exception occurred while parsing size') size = 0 if version > NormalizedVersion(self._bundle.get_activity_version()): result = BundleUpdate(self._bundle.get_bundle_id(), self._bundle.get_name(), version, link, size) else: result = None self.emit('check-complete', result)
class _UpdateChecker(GObject.GObject): __gsignals__ = { 'check-complete': (GObject.SignalFlags.RUN_FIRST, None, (object, )), } _CHUNK_SIZE = 10240 def __init__(self): GObject.GObject.__init__(self) self._bundle = None def check(self, bundle): # ASLO knows only about stable SP releases major, minor = config.version.split('.')[0:2] sp_version = '%s.%s' % (major, int(minor) + int(minor) % 2) url = '%s?id=%s&appVersion=%s' % \ (_UPDATE_PATH, bundle.get_bundle_id(), sp_version) self._bundle = bundle _logger.debug('Fetch %s', url) self._downloader = Downloader(url) self._downloader.connect('complete', self.__downloader_complete_cb) self._downloader.download() def __downloader_complete_cb(self, downloader, result): if isinstance(result, Exception): self.emit('check-complete', result) return if result is None: _logger.error('No XML update data returned from ASLO') return document = XML(result.get_data()) if document.find(_FIND_DESCRIPTION) is None: _logger.debug( 'Bundle %s not available in the server for the ' 'version %s', self._bundle.get_bundle_id(), config.version) version = None link = None size = None self.emit('check-complete', None) return try: version = NormalizedVersion(document.find(_FIND_VERSION).text) except InvalidVersionError: _logger.exception('Exception occurred while parsing version') self.emit('check-complete', None) return link = document.find(_FIND_LINK).text try: size = long(document.find(_FIND_SIZE).text) * 1024 except ValueError: _logger.exception('Exception occurred while parsing size') size = 0 if version > NormalizedVersion(self._bundle.get_activity_version()): result = BundleUpdate(self._bundle.get_bundle_id(), self._bundle.get_name(), version, link, size) else: result = None self.emit('check-complete', result)
class Updater(GObject.GObject): __gtype_name__ = 'SugarUpdater' __gsignals__ = { 'updates-available': (GObject.SignalFlags.RUN_FIRST, None, (object, )), 'progress': (GObject.SignalFlags.RUN_FIRST, None, (int, str, float)), 'finished': (GObject.SignalFlags.RUN_FIRST, None, (object, object, bool)) } def __init__(self): GObject.GObject.__init__(self) client = GConf.Client.get_default() backend = client.get_string(_UPDATE_BACKEND_KEY) module_name, class_name = backend.rsplit('.', 1) _logger.debug("Use backend %s.%s", module_name, class_name) module = importlib.import_module("jarabe.model.update." + module_name) self._model = getattr(module, class_name)() self._updates = None self._bundles_to_update = None self._total_bundles_to_update = 0 self._bundle_update = None self._bundles_updated = None self._bundles_failed = None self._downloader = None self._cancelling = False self._state = STATE_IDLE self._auto = False def get_state(self): return self._state def trigger_automatic_update(self): if self._state == STATE_IDLE: _logger.debug("Starting automatic activity update") self.check_updates(True) def check_updates(self, auto=False): if self._state not in (STATE_IDLE, STATE_CHECKED): raise UpdaterStateException() self._auto = auto self._updates = [] self._bundles_updated = [] self._bundles_failed = [] self._state = STATE_CHECKING bundles = list(bundleregistry.get_registry()) self._model.fetch_update_info(bundles, auto, self._backend_progress_cb, self._backend_finished_cb) def _backend_progress_cb(self, bundle_name, progress): self.emit('progress', self._state, bundle_name, progress) def _backend_finished_cb(self, updates): _logger.debug("_backend_finished_cb") if self._cancelling: self._finished(True) return self._updates = updates self._state = STATE_CHECKED if self._auto: self.update(None) else: self.emit('updates-available', self._updates) def update(self, bundle_ids): if self._state != STATE_CHECKED: raise UpdaterStateException() if bundle_ids is None: self._bundles_to_update = self._updates else: self._bundles_to_update = [] for bundle_update in self._updates: if bundle_update.bundle_id in bundle_ids: self._bundles_to_update.append(bundle_update) self._total_bundles_to_update = len(self._bundles_to_update) _logger.debug("Starting update of %d activities", self._total_bundles_to_update) self._download_next_update() def _download_next_update(self): if self._cancelling: self._finished(True) return if len(self._bundles_to_update) == 0: self._finished() return self._state = STATE_DOWNLOADING self._bundle_update = self._bundles_to_update.pop() _logger.debug("Downloading update for %s", self._bundle_update.bundle_id) total = self._total_bundles_to_update * 2 current = total - len(self._bundles_to_update) * 2 - 2 progress = current / float(total) self.emit('progress', self._state, self._bundle_update.name, progress) self._downloader = Downloader(self._bundle_update.link) self._downloader.connect('progress', self.__downloader_progress_cb) self._downloader.connect('complete', self.__downloader_complete_cb) self._downloader.download_to_temp() def __downloader_complete_cb(self, downloader, result): if self._cancelling: self._cleanup_downloader() self._finished(True) return if isinstance(result, Exception): _logger.error('Error downloading update: %s', result) self._cleanup_downloader() self._bundles_failed.append(self._bundle_update) self._download_next_update() else: self._install_update(self._bundle_update, self._downloader.get_local_file_path()) self._downloader = None def __downloader_progress_cb(self, downloader, progress): total = self._total_bundles_to_update * 2 current = total - len(self._bundles_to_update) * 2 - 2 + progress progress = current / float(total) self.emit('progress', self._state, self._bundle_update.name, progress) def _install_update(self, bundle_update, local_file_path): self._state = STATE_UPDATING total = self._total_bundles_to_update current = total - len(self._bundles_to_update) - 0.5 progress = current / float(total) _logger.debug("Installing update for %s", bundle_update.bundle_id) self.emit('progress', self._state, bundle_update.name, progress) current += 0.5 bundle = bundle_from_archive(local_file_path) registry = bundleregistry.get_registry() registry.install_async(bundle, self._bundle_installed_cb, current) def _bundle_installed_cb(self, bundle, result, progress): _logger.debug("%s installed: %r", bundle.get_bundle_id(), result) progress = progress / float(self._total_bundles_to_update) self.emit('progress', self._state, bundle.get_name(), progress) # Remove downloaded bundle archive try: os.unlink(bundle.get_path()) except OSError: pass if result is True: self._bundles_updated.append(bundle) else: self._bundles_failed.append(bundle) # do it in idle so the UI has a chance to refresh GLib.idle_add(self._download_next_update) def _finished(self, cancelled=False): self._state = STATE_IDLE self._cancelling = False _logger.debug("Update finished") self.emit('finished', self._bundles_updated, self._bundles_failed, cancelled) if not cancelled and len(self._bundles_failed) == 0: client = GConf.Client.get_default() client.set_int(_LAST_UPDATE_KEY, time.time()) try: os.unlink(_URGENT_TRIGGER_FILE) except OSError: pass def cancel(self): # From STATE_CHECKED we can cancel immediately. if self._state == STATE_CHECKED: self._state = STATE_IDLE return self._cancelling = True self._model.cancel() if self._downloader: self._downloader.cancel() def _cleanup_downloader(self): if self._downloader is None: return file_path = self._downloader.get_local_file_path() if file_path is not None: try: os.unlink(file_path) except OSError: pass