def update(self, progress, sources_list=None): src_list = aptsources.sourceslist.SourcesList() src_count = 0 for src in src_list.list: if not src.disabled and not src.invalid: src_count += len(src.comps) + 1 updating_sources = "{}-updating-apt-sources".format( progress.get_current_phase().name) cache_init = "{}-apt-cache-init".format( progress.get_current_phase().name) progress.split( Phase(updating_sources, _("Updating apt sources")), Phase(cache_init, _("Initialising apt cache")) ) progress.start(updating_sources) self._update_cache(progress, src_count, sources_list) progress.start(cache_init) ops = [("reading-package-lists", _("Reading package lists")), ("building-dependency-tree", _("Building dependency tree")), ("reading-state-information", _("Reading state information")), ("building-data-structures", _("Building data structures"))] op_progress = AptOpProgress(progress, ops) self._cache.open(op_progress)
def do_download(progress, status, priority=Priority.NONE, dialog_proc=None): progress.split( Phase( 'downloading-pip-pkgs', _("Downloading Python packages"), 10, is_main=True ), Phase( 'updating-sources', _("Updating apt sources"), 40, is_main=True ), Phase( 'downloading-apt-packages', _("Downloading apt packages"), 50, is_main=True ) ) _cache_pip_packages(progress, priority=priority) _cache_deb_packages(progress, priority=priority) progress.finish(_("Done downloading")) # kill the dialog if it is still on if dialog_proc: dialog_proc.terminate() # TODO: Figure out if it has actually worked return True
def upgrade(self, packages, progress=None, priority=Priority.NONE): if not isinstance(packages, list): packages = [packages] for pkg_name in packages: if pkg_name in self._cache: pkg = self._cache[pkg_name] if self._is_package_upgradable(pkg, priority=priority): pkg.mark_upgrade() phase_name = progress.get_current_phase().name download = "{}-downloading".format(phase_name) install = "{}-installing".format(phase_name) progress.split( Phase(download, _("Downloading packages")), Phase(install, _("Installing packages")) ) progress.start(download) self._fetch_archives(progress) progress.start(install) inst_progress = AptInstallProgress(progress) self._cache.commit(install_progress=inst_progress) self._cache.open() self._cache.clear()
def update(self, progress, sources_list=None): src_list = aptsources.sourceslist.SourcesList() src_count = 0 for src in src_list.list: if not src.disabled and not src.invalid: src_count += len(src.comps) + 1 updating_sources = "{}-updating-apt-sources".format( progress.get_current_phase().name) cache_init = "{}-apt-cache-init".format( progress.get_current_phase().name) progress.split(Phase(updating_sources, _("Updating apt sources")), Phase(cache_init, _("Initialising apt cache"))) progress.start(updating_sources) apt_progress = AptDownloadProgress(progress, src_count) try: self._cache.update(fetch_progress=apt_progress, sources_list=sources_list) except apt.cache.FetchFailedException: err_msg = N_("Failed to update sources") logger.error(err_msg) progress.fail(_(err_msg)) progress.start(cache_init) ops = [("reading-package-lists", _("Reading package lists")), ("building-dependency-tree", _("Building dependency tree")), ("reading-state-information", _("Reading state information")), ("building-data-structures", _("Building data structures"))] op_progress = AptOpProgress(progress, ops) self._cache.open(op_progress)
def fix_broken(self, progress): progress.split( Phase('dpkg-clean', _("Cleaning dpkg journal")), Phase('fix-broken', _("Fixing broken packages")) ) if self._cache.dpkg_journal_dirty: progress.start('dpkg-clean') logger.info("Cleaning dpkg journal") run_cmd_log("dpkg --configure -a") self._cache.clear() self._cache.open() progress.start('fix-broken') # Naughty but don't want to re-initialise if self._cache._depcache.broken_count: try: self._cache._depcache.fix_broken() except SystemError as e: logger.error('Error attempting to fix broken pkgs', exception=e) self._cache.clear() self._cache.open()
def install_ind_package(progress, package): status = UpdaterStatus.get_instance() # install an independent package. previous_state = status.state # Allow installing only if the updater is in certain safe states. if status.state not in [ UpdaterStatus.NO_UPDATES, UpdaterStatus.UPDATES_AVAILABLE, UpdaterStatus.UPDATES_INSTALLED ]: msg = "The install is already running" logger.warn(msg) progress.abort(msg) return False if package not in status.updatable_independent_packages: msg = "tried to install non-independent package {} using update_ind_pkg".format( package) logger.warn(msg) progress.abort(msg) return False status.state = UpdaterStatus.INSTALLING_INDEPENDENT status.save() update_sources_phase = 'updating-sources' installing_idp_phase = 'installing-idp-package' progress.split( Phase(update_sources_phase, _("Updating apt sources"), 10), Phase(installing_idp_phase, _("Installing independent package"), 90)) apt_handle = AptWrapper.get_instance() progress.start(update_sources_phase) apt_handle.update(progress) progress.start(installing_idp_phase) apt_handle.upgrade(package, progress) status.state = previous_state status.last_update = int(time.time()) # always check independent packages as NONE as urgent updates to # these packages are dealt with by the main updater status.updatable_independent_packages = get_ind_packages(Priority.NONE) status.is_scheduled = False status.save() progress.finish(_("Update completed")) return True
def install(progress=None, gui=True): progress.split( Phase('checks', _('Checking system'), 1, is_main=True), Phase('download', _("Downloading updates"), 39, is_main=True), Phase('install', _("Installing updates"), 60, is_main=True), ) progress.start('checks') status = UpdaterStatus.get_instance() logger.debug("Installing update (updater state = {})".format(status.state)) if not progress: progress = DummyProgress() priority = Priority.NONE if status.is_urgent: priority = Priority.URGENT run_cmd('sudo kano-empty-trash') enough_space, space_msg = check_disk_space(priority) if not enough_space: logger.error(space_msg) progress.abort(_(space_msg)) RCState.get_instance().rc = RC.NOT_ENOUGH_SPACE return False logger.debug("Downloading any new updates that might be available.") progress.start('download') if not download(progress): logger.error("Downloading updates failed, cannot update.") return False progress.start('install') logger.debug("Installing with priority {}".format(priority.priority)) try: return do_install(progress, status, priority=priority) except Relaunch as err: raise except Exception as err: # Reset the state back to the previous one, so the updater # doesn't get stuck in 'installing' forever. status.state = UpdaterStatus.UPDATES_DOWNLOADED status.save() logger.error(err.message) progress.fail(err.message) RCState.get_instance().rc = RC.UNEXPECTED_ERROR return False
def run_aux_tasks(progress): progress.split( Phase('updating-home-folders', _('Updating home folders from template')), Phase('refreshing-kdesk', _('Refreshing the desktop')), Phase('expanding-rootfs', _('Expanding filesystem partitions'))) progress.start('updating-home-folders') # TODO: We might want to keep this in install() update_home_folders_from_skel() progress.start('refreshing-kdesk') _refresh_kdesk() progress.start('expanding-rootfs') _expand_rootfs()
def upgrade_all(self, progress=None, priority=Priority.NONE): if priority != Priority.URGENT: self._cache.upgrade(dist_upgrade=True) phase_name = progress.get_current_phase().name download = "{}-downloading".format(phase_name) install = "{}-installing".format(phase_name) progress.split(Phase(download, _("Downloading packages")), Phase(install, _("Installing packages"))) progress.start(download) self.cache_updates(progress, priority=priority) progress.start(install) inst_progress = AptInstallProgress(progress) self._cache.commit(install_progress=inst_progress) self._cache.open() self._cache.clear()
def do_download(progress, status): progress.split( Phase('downloading-pip-pkgs', 'Downloading Python packages', 10, is_main=True), Phase('updating-sources', 'Updating apt sources', 40, is_main=True), Phase('downloading-apt-packages', 'Downloading apt packages', 50, is_main=True)) _cache_pip_packages(progress) _cache_deb_packages(progress) progress.finish('Done downloading') # TODO: Figure out if it has actually worked return True
def install(progress=None): status = UpdaterStatus.get_instance() logger.debug("Installing update (updater state = {})".format(status.state)) if not progress: progress = DummyProgress() if status.state == UpdaterStatus.INSTALLING_UPDATES: msg = 'The install is already running' logger.warn(msg) progress.abort(_(msg)) return False elif status.state != UpdaterStatus.UPDATES_DOWNLOADED: logger.debug('Updates weren\'t downloaded, running download first.') progress.split( Phase('download', _('Downloading updates'), 40, is_main=True), Phase('install', _('Installing updates'), 60, is_main=True), ) progress.start('download') if not download(progress): logger.error('Downloading updates failed, cannot update.') return False progress.start('install') try: return do_install(progress, status) except Relaunch as err: raise except Exception as err: # Reset the state back to the previous one, so the updater # doesn't get stuck in 'installing' forever. status.state = UpdaterStatus.UPDATES_DOWNLOADED status.save() logger.error(err.message) progress.fail(err.message) return False
def run_aux_tasks(progress): progress.split( Phase('updating-home-folders', _("Updating home folders from template")), Phase('checking-for-app-updates', _("Refreshing Kano Apps")), Phase('refreshing-kdesk', _("Refreshing the desktop")), Phase('expanding-rootfs', _("Expanding filesystem partitions")), Phase('prune-kano-content', _("Removing unnecessary kano-content entries")), Phase('syncing', _("Syncing"))) progress.start('updating-home-folders') try: update_home_folders_from_skel() except Exception: logger.error("Updating home folders failed. See the traceback bellow:") _type, _value, tb = sys.exc_info() for tb_line in traceback.format_tb(tb): logger.error(tb_line) progress.start('checking-for-app-updates') _check_for_app_updates() progress.start('refreshing-kdesk') _refresh_kdesk() progress.start('expanding-rootfs') _expand_rootfs() progress.start('prune-kano-content') _kano_content_prune() progress.start('syncing') _sync()
def __init__(self, updater_progress, ops=[]): super(AptOpProgress, self).__init__() self._updater_progress = updater_progress self._phase_name = updater_progress.get_current_phase().name self.ops = [(self._get_op_key(op[0]), op[1]) for op in ops] phases = [Phase(op[0], op[1]) for op in self.ops] self._updater_progress.split(*phases) for op in self.ops: self._updater_progress.init_steps(op[0], 100)
def install_urgent(progress, status): progress.split( Phase('installing-urgent', _("Installing Hotfix"), 100, is_main=True)) logger.debug("Installing urgent hotfix") packages_to_update = apt_handle.packages_to_be_upgraded() progress.start('installing-urgent') install_deb_packages(progress, priority=Priority.URGENT) status.is_urgent = False try: from kano_profile.tracker import track_data track_data('updated_hotfix', {'packages': packages_to_update}) logger.debug("Tracking Data: '{}'".format(packages_to_update)) except ImportError as imp_exc: logger.error("Couldn't track hotfix installation, failed to import " \ "tracking module: [{}]".format(imp_exc)) except Exception: pass
def do_install(progress, status): status.state = UpdaterStatus.INSTALLING_UPDATES status.save() progress.split( Phase('init', _('Starting Update'), 10, is_main=True), Phase('updating-itself', _('Updating Itself'), 10, is_main=True), Phase('preupdate', _('Running The Preupdate Scripts'), 10, is_main=True), Phase('updating-pip-packages', _('Updating Pip Packages'), 15, is_main=True), Phase('updating-deb-packages', _('Updating Deb Packages'), 15, is_main=True), Phase('postupdate', _('Running The Postupdate Scripts'), 10, is_main=True), Phase('aux-tasks', 'Performing auxiliary tasks', 10, is_main=True)) progress.start('init') apt_handle.clear_cache() apt_handle.fix_broken(progress) # determine the versions (from and to) system_version = OSVersion.from_version_file(SYSTEM_VERSION_FILE) msg = "Upgrading from {} to {}".format(system_version, TARGET_VERSION) logger.info(msg) # set up the scenarios and check whether they cover updating # from this version preup = PreUpdate(system_version) postup = PostUpdate(system_version) if not (preup.covers_update() and postup.covers_update()): title = _('Unfortunately, your version of Kano OS is too old ' 'to be updated through the updater.') description = _('You will need to download the image of the ' 'OS and reflash your SD card.') msg = "{}: {}".format(title, description) logger.error("Updating from a version that is no longer supported" + \ "()".format(system_version)) progress.error(msg) raise InstallError(msg) old_updater = apt_handle.get_package('kano-updater').installed.version progress.start('updating-itself') apt_handle.upgrade('kano-updater', progress) # relaunch if the updater has changed new_updater = apt_handle.get_package('kano-updater') if old_updater != new_updater.installed.version: # Remove the installation in progress status so it doesn't # block the start of the new instance. status.state = UpdaterStatus.UPDATES_DOWNLOADED status.save() logger.info(_('The updater has been updated, relaunching.')) progress.relaunch() return False progress.start('preupdate') try: preup.run() except Exception as e: logger.error('The pre-update scenarios failed.') logger.error(str(e)) progress.abort(_('The pre-update tasks failed.')) raise logger.debug('Updating pip packages') progress.start('updating-pip-packages') install_pip_packages(progress) logger.debug('Updating deb packages') progress.start('updating-deb-packages') install_deb_packages(progress) progress.start('postupdate') try: postup.run() except Exception as e: logger.error('The post-update scenarios failed.') logger.error(str(e)) progress.abort(_('The post-update tasks failed.')) raise bump_system_version() # We don't care too much when these fail progress.start('aux-tasks') run_aux_tasks(progress) status.state = UpdaterStatus.UPDATES_INSTALLED status.last_update = int(time.time()) status.save() progress.finish('Update completed') return True
def download(progress=None): status = UpdaterStatus.get_instance() if not progress: progress = DummyProgress() if status.state == UpdaterStatus.NO_UPDATES: progress.split( Phase('checking', _('Checking for updates'), 10, is_main=True), Phase('downloading', _('Downloading updates'), 90, is_main=True)) progress.start('checking') check_for_updates(progress=progress) if status.state == UpdaterStatus.NO_UPDATES: progress.finish(_('No updates to download')) return False progress.start('downloading') elif status.state == UpdaterStatus.UPDATES_DOWNLOADED: err_msg = _('Updates have been downloaded already') logger.error(err_msg) progress.abort(err_msg) return True elif status.state == UpdaterStatus.DOWNLOADING_UPDATES: err_msg = _('The download is already running') logger.error(err_msg) progress.abort(err_msg) return False elif status.state == UpdaterStatus.INSTALLING_UPDATES: err_msg = _('Updates are already being installed') logger.error(err_msg) progress.abort(err_msg) return False if not is_internet(): err_msg = _('Must have internet to download the updates') logger.error(err_msg) progress.fail(err_msg) return False if not is_server_available(): err_msg = _('Could not connect to the download server') logger.error(err_msg) progress.fail(err_msg) return False status.state = UpdaterStatus.DOWNLOADING_UPDATES status.save() try: success = do_download(progress, status) except Exception as err: progress.fail(err.message) logger.error(err.message) status.state = UpdaterStatus.UPDATES_AVAILABLE status.save() return False status.state = UpdaterStatus.UPDATES_DOWNLOADED status.save() return success
def install(progress=None, gui=True): status = UpdaterStatus.get_instance() logger.debug("Installing update (updater state = {})".format(status.state)) if not progress: progress = DummyProgress() # run_cmd('sudo kano-empty-trash') # Check for available disk space before updating # We require at least 1GB of space for the update to proceed # TODO: Take this value from apt mb_free = get_free_space() if mb_free < 1536: err_msg = N_( "Only {}MB free, at least 1.5GB is needed.".format(mb_free)) logger.warn(err_msg) answer = progress.prompt(_("Not enough space to update!"), _("But I can make more room if you'd like?"), [_("OK"), _("CANCEL")]) if answer == _("OK"): run_cmd('sudo expand-rootfs') status.state = UpdaterStatus.INSTALLING_UPDATES status.save() os.system('sudo systemctl reboot') else: logger.error(err_msg) progress.fail(_(err_msg)) return False if (status.state == UpdaterStatus.INSTALLING_UPDATES or status.state == UpdaterStatus.INSTALLING_INDEPENDENT): msg = "The install is already running" logger.warn(msg) progress.abort(msg) return False elif status.state != UpdaterStatus.UPDATES_DOWNLOADED: logger.debug("Updates weren't downloaded, running download first.") progress.split( Phase('download', _("Downloading updates"), 40, is_main=True), Phase('install', _("Installing updates"), 60, is_main=True), ) progress.start('download') if not download(progress): logger.error("Downloading updates failed, cannot update.") return False progress.start('install') priority = Priority.NONE if status.is_urgent: priority = Priority.URGENT logger.debug("Installing with priority {}".format(priority.priority)) try: return do_install(progress, status, priority=priority) except Relaunch as err: raise except Exception as err: # Reset the state back to the previous one, so the updater # doesn't get stuck in 'installing' forever. status.state = UpdaterStatus.UPDATES_DOWNLOADED status.save() logger.error(err.message) progress.fail(err.message) return False
def beta_370_to_beta_380(self, progress): # linux kernel 4.4.21 shipped with Kano 3.8.0 emits systemd boot messages. # fix by telling the kernel to enable an empty splash screen. command = "sed -i 's/\\bsystemd.show_status=0\\b/splash/' {}".format( '/boot/cmdline.txt') run_cmd_log(command) self._bootconfig_set_value_helper("gpu_mem", "256") try: # Install 3rd party apps from Kano World using the App Store. # Before, the disk space requirement was part of the update itself. # Moved away from that model to install apps separately of the update # to minimise the requirement (divide and conquer). # However, the App Store does not check for disk space before # installing an app so account for this here naively. # Requirements (disk_req) in MB were made with apt on a clean system. from kano.utils.disk import get_free_space new_apps = [ { 'kw_app': 'tux-paint', 'disk_req': 413 }, { 'kw_app': 'numpty-physics', 'disk_req': 2 }, { 'kw_app': 'gmail', 'disk_req': 1 }, { 'kw_app': 'google-drive', 'disk_req': 1 }, { 'kw_app': 'google-maps', 'disk_req': 1 }, { 'kw_app': 'wikipedia', 'disk_req': 1 }, { 'kw_app': 'whatsapp', 'disk_req': 1 }, { 'kw_app': 'adventure', 'disk_req': 5 }, { 'kw_app': 'openttd', 'disk_req': 21 }, { 'kw_app': 'tux-typing', 'disk_req': 26 }, { 'kw_app': 'libreoffice', 'disk_req': 385 }, ] phases = [ Phase( app['kw_app'], _("Installing {} from the App Store").format( app['kw_app']), app['disk_req']) for app in new_apps ] # TODO: Because the Pre/PostUpdate scenarios don't split the # progress, this last phase essentially is used to preserve the # phase from install. phases.append( Phase('continue-postupdate', _("Running The Postupdate Scripts"))) progress.split(*phases) run_cmd_log('apt-get autoremove -y') for app in new_apps: run_cmd_log('apt-get clean') mb_free = get_free_space() mb_required = app['disk_req'] + 250 # MB buffer if mb_free > mb_required: progress.start(app['kw_app']) run_cmd_log('kano-apps install --no-gui {app}'.format( app=app['kw_app'])) else: logger.warn( "Cannot install {app} as it requires {mb_required} but" " only has {mb_free}".format(app=app['kw_app'], mb_required=mb_required, mb_free=mb_free)) except Exception as e: logger.error("Failed to install 3rd party apps", exception=e) send_crash_report( "PostUpdate 3.7 to 3.8 app install", "Failed with unexpected exception\n{}".format( traceback.format_exc())) finally: run_cmd_log('apt-get clean') progress.start('continue-postupdate') # Tell kano-init to put the automatic logins up-to-date reconfigure_autostart_policy()
def download(progress=None, gui=True): status = UpdaterStatus.get_instance() dialog_proc = None if not progress: progress = DummyProgress() if status.state in [ UpdaterStatus.NO_UPDATES, UpdaterStatus.UPDATES_DOWNLOADED ]: progress.split( Phase('checking', _("Checking for updates"), 10, is_main=True), Phase('downloading', _("Downloading updates"), 90, is_main=True)) pre_check_state = status.state progress.start('checking') check_for_updates(progress=progress) if status.state == UpdaterStatus.NO_UPDATES: if pre_check_state == UpdaterStatus.NO_UPDATES: msg = N_("No updates to download") logger.info(msg) progress.finish(_(msg)) return False elif pre_check_state == UpdaterStatus.UPDATES_DOWNLOADED: err_msg = N_("Latest updates have been downloaded already") logger.info(err_msg) progress.abort(_(err_msg)) return True progress.start('downloading') elif status.state == UpdaterStatus.DOWNLOADING_UPDATES: err_msg = N_("The download is already running") logger.error(err_msg) progress.abort(_(err_msg)) return False if not is_internet(): err_msg = N_("Must have internet to download the updates") logger.error(err_msg) progress.fail(_(err_msg)) RCState.get_instance().rc = RC.NO_NETWORK return False if not is_server_available(): err_msg = N_("Could not connect to the download server") logger.error(err_msg) progress.fail(_(err_msg)) RCState.get_instance().rc = RC.CANNOT_REACH_KANO return False # show a dialog informing the user of an automatic urgent download if status.is_urgent and not gui: # TODO: mute notifications? title = _("Updater") description = _( "Kano HQ has just released a critical update that will repair" " some important things on your system! We'll download these" " automatically, and ask you to schedule the install when they finish." ) buttons = _("OK:green:1") dialog_proc = show_kano_dialog(title, description, buttons, blocking=False) # If the Updater is running in recovery mode, do not update the state # out of the installing ones, otherwise the recovery flow will quit. if not status.is_recovery_needed(): status.state = UpdaterStatus.DOWNLOADING_UPDATES status.save() priority = Priority.NONE if status.is_urgent: priority = Priority.URGENT logger.info("Urgent update detected, bumping to normal priority") make_normal_prio() logger.debug("Downloading with priority {}".format(priority.priority)) try: success = do_download(progress, status, priority=priority, dialog_proc=dialog_proc) except Exception as err: progress.fail(err.message) logger.error(err.message) RCState.get_instance().rc = RC.UNEXPECTED_ERROR status.state = UpdaterStatus.UPDATES_AVAILABLE status.save() return False if not status.is_recovery_needed(): status.state = UpdaterStatus.UPDATES_DOWNLOADED status.save() return success
def install_standard(progress, status): progress.split( Phase('init', _("Starting Update"), 10, is_main=True), Phase('updating-itself', _("Updating Itself"), 10, is_main=True), Phase('preupdate', _("Running The Preupdate Scripts"), 10, is_main=True), Phase('updating-deb-packages', _("Updating Deb Packages"), 30, is_main=True), Phase('postupdate', _("Running The Postupdate Scripts"), 10, is_main=True), Phase('aux-tasks', _("Performing auxiliary tasks"), 10, is_main=True)) progress.start('init') apt_handle = AptWrapper.get_instance() apt_handle.clear_cache() apt_handle.fix_broken(progress) # determine the versions (from and to) system_version = get_system_version() target_version = get_target_version() msg = "Upgrading from {} to {}".format(system_version, target_version) logger.info(msg) # set up the scenarios and check whether they cover updating # from this version preup = PreUpdate(system_version) postup = PostUpdate(system_version) if not (preup.covers_update() and postup.covers_update()): title = _("Unfortunately, your version of Kano OS is too old " \ "to be updated through the updater.") description = _("You will need to download the image of the " \ "OS and reflash your SD card.") msg = "{}: {}".format(title, description) logger.error( "Updating from a version that is no longer supported ({})".format( system_version)) progress.fail(msg) raise InstallError(msg) old_updater = apt_handle.get_package('kano-updater').installed.version progress.start('updating-itself') apt_handle.upgrade('kano-updater', progress) # relaunch if the updater has changed new_updater = apt_handle.get_package('kano-updater') if old_updater != new_updater.installed.version: # Remove the installation in progress status so it doesn't # block the start of the new instance. status.state = UpdaterStatus.UPDATES_DOWNLOADED status.save() logger.info("The updater has been updated, relaunching.") progress.relaunch() return False progress.start('preupdate') try: preup.run() except Exception as err: logger.error("The pre-update scenarios failed.") logger.error(err.encode('utf-8')) progress.abort("The pre-update tasks failed.") raise logger.debug("Updating deb packages") progress.start('updating-deb-packages') install_deb_packages(progress) progress.start('postupdate') try: postup.run() except Exception as err: logger.error("The post-update scenarios failed.") logger.error(err.encode('utf-8')) progress.abort("The post-update tasks failed.") raise bump_system_version() # We don't care too much when these fail progress.start('aux-tasks') run_aux_tasks(progress)
def download(progress=None, gui=True): status = UpdaterStatus.get_instance() dialog_proc = None if not progress: progress = DummyProgress() if status.state == UpdaterStatus.NO_UPDATES: progress.split( Phase( 'checking', _("Checking for updates"), 10, is_main=True ), Phase( 'downloading', _("Downloading updates"), 90, is_main=True ) ) progress.start('checking') check_for_updates(progress=progress) if status.state == UpdaterStatus.NO_UPDATES: logger.info("No updates to download") progress.finish(_("No updates to download")) return False progress.start('downloading') elif status.state == UpdaterStatus.UPDATES_DOWNLOADED: err_msg = N_("Updates have been downloaded already") logger.error(err_msg) progress.abort(_(err_msg)) return True elif status.state == UpdaterStatus.DOWNLOADING_UPDATES: err_msg = N_("The download is already running") logger.error(err_msg) progress.abort(_(err_msg)) return False elif status.state == UpdaterStatus.INSTALLING_UPDATES: err_msg = N_("Updates are already being installed") logger.error(err_msg) progress.abort(_(err_msg)) return False if not is_internet(): err_msg = N_("Must have internet to download the updates") logger.error(err_msg) progress.fail(_(err_msg)) return False if not is_server_available(): err_msg = N_("Could not connect to the download server") logger.error(err_msg) progress.fail(_(err_msg)) return False # show a dialog informing the user of an automatic urgent download if status.is_urgent and not gui: # TODO: mute notifications? title = _("Updater") description = _("Kano HQ has just released a critical update that will repair" \ " some important things on your system! We'll download these automatically," \ " and ask you to schedule the install when they finish.") buttons = _("OK:green:1") dialog_proc = show_kano_dialog(title, description, buttons, blocking=False) status.state = UpdaterStatus.DOWNLOADING_UPDATES status.save() priority = Priority.NONE if status.is_urgent: priority = Priority.URGENT logger.info("Urgent update detected, bumping to normal priority") make_normal_prio() logger.debug("Downloading with priority {}".format(priority.priority)) try: success = do_download(progress, status, priority=priority, dialog_proc=dialog_proc) except Exception as err: progress.fail(err.message) logger.error(err.message) status.state = UpdaterStatus.UPDATES_AVAILABLE status.save() return False status.state = UpdaterStatus.UPDATES_DOWNLOADED status.save() return success