def clean(dry_run=False): status = UpdaterStatus.get_instance() old_status = status.state msg = "The status of the updater at boot was: {}".format(status.state) logger.info(msg) if status.state == UpdaterStatus.DOWNLOADING_UPDATES: # The download was interrupted, go back one state status.state = UpdaterStatus.UPDATES_AVAILABLE elif status.state == UpdaterStatus.UPDATES_INSTALLED: # Show a dialog and change the state back to no updates status.state = UpdaterStatus.NO_UPDATES status.is_urgent = False if status.state != old_status: msg = "The status was changed to: {}".format(status.state) logger.info(msg) status.notifications_muted = False if not dry_run: status.save() return old_status
def clean(dry_run=False): status = UpdaterStatus.get_instance() old_status = status.state msg = "The status of the updater at boot was: {}".format(status.state) logger.debug(msg) if status.state == UpdaterStatus.DOWNLOADING_UPDATES: # The download was interrupted, go back one state status.state = UpdaterStatus.UPDATES_AVAILABLE elif status.state == UpdaterStatus.INSTALLING_UPDATES: # The installation was interrupted, go back one state status.state = UpdaterStatus.UPDATES_DOWNLOADED elif status.state == UpdaterStatus.INSTALLING_INDEPENDENT: # The installation was interrupted, go back one state status.state = UpdaterStatus.NO_UPDATES elif status.state == UpdaterStatus.UPDATES_INSTALLED: # Show a dialog and change the state back to no updates status.state = UpdaterStatus.NO_UPDATES status.is_urgent = False if status.state != old_status: msg = "The status was changed to: {}".format(status.state) logger.debug(msg) status.notifications_muted = False if not dry_run: status.save() return old_status
def __init__(self): Countdown.__init__(self) complete = Gtk.Label(_('Update complete!')) complete.get_style_context().add_class('H1') status = UpdaterStatus.get_instance() self._shutdown_scheduled = status.is_shutdown if self._shutdown_scheduled: finish_method = _("shutdown") else: finish_method = _("restart") info = Gtk.Label(_( "Your Kano is up to date and \n" "will automatically {} in 10 seconds" .format(finish_method)) ) info.set_justify(Gtk.Justification.CENTER) info.get_style_context().add_class('H2') instructions = Gtk.Label(_("Press ENTER to {} now".format(finish_method))) instructions.get_style_context().add_class('H3') instructions.set_margin_top(50) self._main_grid.attach(complete, 0, 1, 1, 1) self._main_grid.attach(info, 0, 2, 1, 1) self._main_grid.attach(instructions, 0, 3, 1, 1) self.connect('show', self._on_show)
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 launch_shutdown_gui(): from gi.repository import GObject, Gtk from kano_updater.ui.available_window import UpdateNowShutdownWindow from kano_updater.ui.install_window import InstallWindow status = UpdaterStatus.get_instance() if status.is_scheduled: GObject.threads_init() win = InstallWindow() if status.is_urgent else UpdateNowShutdownWindow() win.show() Gtk.main()
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 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 launch_boot_gui(): # FIXME: This window uses Gtk2 which requires the other Gtk imports to be # loaded in the scope of the functions that require them. old_status = clean(dry_run=True) status = UpdaterStatus.get_instance() if old_status == UpdaterStatus.INSTALLING_UPDATES: from kano.gtk3.kano_dialog import KanoDialog d = KanoDialog( 'Continue updating', 'The update you started didn\'t finish. Would you like to ' 'continue?', [{"label": "YES", "return_value": True, "color": "green"}], orange_info={'name': 'SKIP', 'return_value': False}, ) rv = d.run() del d if rv: status.notifications_muted = True status.state = UpdaterStatus.NO_UPDATES status.save() remove_pid_file() cmd_args = ['kano-updater', 'install', '--gui', '--no-confirm'] os.execvp('kano-updater', cmd_args) elif old_status == UpdaterStatus.UPDATES_INSTALLED: try: from kano_profile.badges import \ increment_app_state_variable_with_dialog increment_app_state_variable_with_dialog( 'kano-updater', 'updated', 1) except Exception: pass from kano_updater.ui.changes_dialog import ChangesDialog win = ChangesDialog() win.run() status.save()
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 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 check_for_updates(progress=None, priority=Priority.NONE, is_gui=False): status = UpdaterStatus.get_instance() if not progress: progress = DummyProgress() countdown = status.first_boot_countdown - int(time.time()) # block update checks when: # 1) three days have NOT passed since the first boot # 2) and not checking for URGENT updates # 3) and the check is triggered from background hooks (not by user) if (countdown > 0) and (priority is not Priority.URGENT) and (not is_gui): return False if status.state not in [UpdaterStatus.NO_UPDATES, UpdaterStatus.UPDATES_DOWNLOADED]: msg = "No need to check for updates" logger.info(msg) # This was a successful check, so we need to update the timestamp. status.last_check = int(time.time()) status.save() # Return True in all cases except when the state is UPDATES_INSTALLED # In that case, we've just updated and don't want to check for updates # again. return status.state != UpdaterStatus.UPDATES_INSTALLED if not is_internet(): err_msg = N_("Must have internet to check for updates") logger.error(err_msg) progress.fail(_(err_msg)) RCState.get_instance().rc = RC.NO_NETWORK # Not updating the timestamp. The check failed. 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 # Not updating the timestamp. The check failed. return False update_type = _do_check(progress, priority=priority) if update_type == Priority.NONE: # 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.NO_UPDATES logger.info("No updates available") RCState.get_instance().rc = RC.NO_UPDATES_AVAILABLE rv = False else: if update_type == Priority.URGENT: status.notifications_muted = True status.is_urgent = True if not status.is_recovery_needed(): status.state = UpdaterStatus.UPDATES_AVAILABLE logger.info("Updates available") logger.info("Found update of priority: {}".format(priority.priority)) rv = True if priority <= Priority.STANDARD: status.last_check = 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.last_check_urgent = int(time.time()) status.save() return rv
def check_for_updates(progress=None, priority=Priority.NONE, is_gui=False): status = UpdaterStatus.get_instance() # FIXME: FOR DEBUGGING ONLY #status.state = UpdaterStatus.UPDATES_AVAILABLE #status.last_check = int(time.time()) #status.save() #return True if not progress: progress = DummyProgress() countdown = status.first_boot_countdown - int(time.time()) # block update checks when: # 1) three days have NOT passed since the first boot # 2) and not checking for URGENT updates # 3) and the check is triggered from background hooks (not by user) if (countdown > 0) and (priority is not Priority.URGENT) and (not is_gui): return False if status.state != UpdaterStatus.NO_UPDATES: msg = "No need to check for updates" logger.info(msg) # This was a successful check, so we need to update the timestamp. status.last_check = int(time.time()) status.save() # Return True in all cases except when the state is UPDATES_INSTALLED # In that case, we've just updated and don't want to check for updates # again. return status.state != UpdaterStatus.UPDATES_INSTALLED if not is_internet(): err_msg = N_("Must have internet to check for updates") logger.error(err_msg) progress.fail(_(err_msg)) # Not updating the timestamp. The check failed. 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)) # Not updating the timestamp. The check failed. return False update_type = _do_check(progress, priority=priority) if update_type == Priority.NONE: status.state = UpdaterStatus.NO_UPDATES logger.debug("No updates available") rv = False else: if update_type == Priority.URGENT: status.notifications_muted = True status.is_urgent = True status.state = UpdaterStatus.UPDATES_AVAILABLE logger.debug("Updates available") logger.debug("Found update of priority: {}".format(priority.priority)) rv = True if priority <= Priority.STANDARD: status.last_check = 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.last_check_urgent = int(time.time()) status.save() return rv
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.info("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.info("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.info("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 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 < 1024: err_msg = _("Only {}MB free, at least 1GB is needed.".format(mb_free)) logger.warn(err_msg) answer = progress.prompt( 'Feeling full!', 'My brain is feeling a bit full, but I can make some more ' 'room if you\'d like?', ['OK', 'CANCEL'] ) if answer.lower() == 'ok': run_cmd('sudo expand-rootfs') status.state = UpdaterStatus.INSTALLING_UPDATES status.save() os.system('sudo reboot') else: logger.error(err_msg) progress.fail(err_msg) return False 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') 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 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: 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 # 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
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 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 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 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
def check_for_updates(progress=None, priority=Priority.NONE, is_gui=False): status = UpdaterStatus.get_instance() # FIXME: FOR DEBUGGING ONLY #status.state = UpdaterStatus.UPDATES_AVAILABLE #status.last_check = int(time.time()) #status.save() #return True if not progress: progress = DummyProgress() countdown = status.first_boot_countdown - int(time.time()) # block update checks when: # 1) three days have NOT passed since the first boot # 2) and not checking for URGENT updates # 3) and the check is triggered from background hooks (not by user) if (countdown > 0) and (priority is not Priority.URGENT) and (not is_gui): return False if status.state != UpdaterStatus.NO_UPDATES: msg = _('No need to check for updates') logger.info(msg) # This was a successful check, so we need to update the timestamp. status.last_check = int(time.time()) status.save() # Return True in all cases except when the state is UPDATES_INSTALLED # In that case, we've just updated and don't want to check for updates # again. return status.state != UpdaterStatus.UPDATES_INSTALLED if not is_internet(): err_msg = _('Must have internet to check for updates') logger.error(err_msg) progress.fail(err_msg) # Not updating the timestamp. The check failed. return False if not is_server_available(): err_msg = _('Could not connect to the download server') logger.error(err_msg) progress.fail(err_msg) # Not updating the timestamp. The check failed. return False update_type = _do_check(progress, priority=priority) if update_type == Priority.NONE: status.state = UpdaterStatus.NO_UPDATES logger.debug('No updates available') rv = False else: if update_type == Priority.URGENT: status.notifications_muted = True status.is_urgent = True status.state = UpdaterStatus.UPDATES_AVAILABLE logger.debug('Updates available') logger.debug('Found update of priority: {}'.format(priority.priority)) rv = True if priority <= Priority.STANDARD: status.last_check = int(time.time()) status.last_check_urgent = int(time.time()) status.save() return rv
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 priority = Priority.NONE if status.is_urgent: priority = Priority.URGENT 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 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 # 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 _do_later(self, *_): status = UpdaterStatus.get_instance() status.is_scheduled = True Gtk.main_quit()
def check_for_updates(min_time_between_checks=0, progress=None): status = UpdaterStatus.get_instance() # FIXME: FOR DEBUGGING ONLY #status.state = UpdaterStatus.UPDATES_AVAILABLE #status.last_check = int(time.time()) #status.save() #return True if not progress: progress = DummyProgress() if status.state != UpdaterStatus.NO_UPDATES: msg = _('No need to check for updates') logger.info(msg) progress.abort(msg) # Return True in all cases except when the state is UPDATES_INSTALLED # In that case, we've just updated and don't want to check for updates # again. return status.state != UpdaterStatus.UPDATES_INSTALLED if min_time_between_checks: target_delta = float(min_time_between_checks) * 60 * 60 time_now = time.time() delta = time_now - status.last_check if delta > target_delta: logger.info(_('Time check passed, doing update check!')) else: msg = _('Not enough time passed for a new update check!') logger.info(msg) progress.abort(msg) return False if not is_internet(): err_msg = _('Must have internet to check for 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 if _do_check(progress): status.state = UpdaterStatus.UPDATES_AVAILABLE logger.debug('Updates available') rv = True else: status.state = UpdaterStatus.NO_UPDATES logger.debug('No updates available') rv = False status.last_check = int(time.time()) status.save() return rv