コード例 #1
0
    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)
コード例 #2
0
ファイル: download.py プロジェクト: fantomid/kano-updater
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
コード例 #3
0
    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()
コード例 #4
0
ファイル: apt_wrapper.py プロジェクト: 3GA/kano-updater
    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)
コード例 #5
0
    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()
コード例 #6
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
コード例 #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
コード例 #8
0
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()
コード例 #9
0
ファイル: apt_wrapper.py プロジェクト: 3GA/kano-updater
    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()
コード例 #10
0
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
コード例 #11
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
コード例 #12
0
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()
コード例 #13
0
    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)
コード例 #14
0
ファイル: install.py プロジェクト: fantomid/kano-updater
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
コード例 #15
0
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
コード例 #16
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
コード例 #17
0
ファイル: install.py プロジェクト: fantomid/kano-updater
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
コード例 #18
0
    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()
コード例 #19
0
ファイル: download.py プロジェクト: 3GA/kano-updater
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
コード例 #20
0
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)
コード例 #21
0
ファイル: download.py プロジェクト: fantomid/kano-updater
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