Example #1
0
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
Example #2
0
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
Example #3
0
    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)
Example #4
0
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
Example #5
0
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()
Example #6
0
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()
Example #7
0
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
Example #8
0
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
Example #9
0
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()
Example #10
0
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
Example #11
0
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
Example #12
0
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
Example #13
0
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
Example #14
0
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
Example #15
0
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
Example #16
0
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
Example #17
0
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
Example #18
0
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
Example #19
0
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
Example #20
0
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
Example #21
0
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
Example #22
0
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
Example #23
0
 def _do_later(self, *_):
     status = UpdaterStatus.get_instance()
     status.is_scheduled = True
     Gtk.main_quit()
Example #24
0
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