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)
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
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