Beispiel #1
0
    def _map_to_model(self,
                      app_json: dict,
                      installed: bool,
                      disk_loader: DiskCacheLoader,
                      internet: bool = True) -> FlatpakApplication:

        app = FlatpakApplication(**app_json, i18n=self.i18n)
        app.installed = installed
        api_data = self.api_cache.get(app_json['id'])

        expired_data = api_data and api_data.get(
            'expires_at') and api_data['expires_at'] <= datetime.utcnow()

        if not api_data or expired_data:
            if not app.runtime:
                if disk_loader:
                    disk_loader.fill(app)  # preloading cached disk data

                if internet:
                    FlatpakAsyncDataLoader(
                        app=app,
                        api_cache=self.api_cache,
                        manager=self,
                        context=self.context,
                        category_cache=self.category_cache).start()

        else:
            app.fill_cached_data(api_data)

        return app
Beispiel #2
0
    def install(self, pkg: FlatpakApplication, root_password: str, watcher: ProcessWatcher) -> bool:

        config = read_config()

        install_level = config['installation_level']

        if install_level is not None:
            self.logger.info("Default Flaptak installation level defined: {}".format(install_level))

            if install_level not in ('user', 'system'):
                watcher.show_message(title=self.i18n['error'].capitalize(),
                                     body=self.i18n['flatpak.install.bad_install_level.body'].format(field=bold('installation_level'),
                                                                                                     file=bold(CONFIG_FILE)),
                                     type_=MessageType.ERROR)
                return False

            pkg.installation = install_level
        else:
            user_level = watcher.request_confirmation(title=self.i18n['flatpak.install.install_level.title'],
                                                      body=self.i18n['flatpak.install.install_level.body'].format(bold(pkg.name)),
                                                      confirmation_label=self.i18n['no'].capitalize(),
                                                      deny_label=self.i18n['yes'].capitalize())
            pkg.installation = 'user' if user_level else 'system'

        remotes = flatpak.list_remotes()

        handler = ProcessHandler(watcher)

        if pkg.installation == 'user' and not remotes['user']:
            handler.handle_simple(flatpak.set_default_remotes('user'))
        elif pkg.installation == 'system' and not remotes['system']:
            if user.is_root():
                handler.handle_simple(flatpak.set_default_remotes('system'))
            else:
                user_password, valid = watcher.request_root_password()
                if not valid:
                    watcher.print('Operation aborted')
                    return False
                else:
                    if not handler.handle_simple(flatpak.set_default_remotes('system', user_password)):
                        watcher.show_message(title=self.i18n['error'].capitalize(),
                                             body=self.i18n['flatpak.remotes.system_flathub.error'],
                                             type_=MessageType.ERROR)
                        watcher.print("Operation cancelled")
                        return False

        res = handler.handle(SystemProcess(subproc=flatpak.install(str(pkg.id), pkg.origin, pkg.installation), wrong_error_phrase='Warning'))

        if res:
            try:
                fields = flatpak.get_fields(str(pkg.id), pkg.branch, ['Ref', 'Branch'])

                if fields:
                    pkg.ref = fields[0]
                    pkg.branch = fields[1]
            except:
                traceback.print_exc()

        return res
Beispiel #3
0
    def ignore_update(self, pkg: FlatpakApplication):
        ignored_keys = self._read_ignored_updates()

        pkg_key = pkg.get_update_ignore_key()

        if pkg_key not in ignored_keys:
            ignored_keys.add(pkg_key)
            self._write_ignored_updates(ignored_keys)

        pkg.updates_ignored = True
Beispiel #4
0
    def revert_ignored_update(self, pkg: FlatpakApplication):
        ignored_keys = self._read_ignored_updates()

        if ignored_keys:
            pkg_key = pkg.get_update_ignore_key()

            if pkg_key in ignored_keys:
                ignored_keys.remove(pkg_key)
                self._write_ignored_updates(ignored_keys)

        pkg.updates_ignored = False
Beispiel #5
0
    def install(self, pkg: FlatpakApplication, root_password: str, watcher: ProcessWatcher) -> bool:
        res = ProcessHandler(watcher).handle(SystemProcess(subproc=flatpak.install(pkg.id, pkg.origin), wrong_error_phrase='Warning'))

        if res:
            try:
                fields = flatpak.get_fields(pkg.id, pkg.branch, ['Ref', 'Branch'])

                if fields:
                    pkg.ref = fields[0]
                    pkg.branch = fields[1]
            except:
                traceback.print_exc()

        return res
Beispiel #6
0
    def downgrade(self, pkg: FlatpakApplication, root_password: str,
                  watcher: ProcessWatcher) -> bool:
        handler = ProcessHandler(watcher)
        pkg.commit = flatpak.get_commit(pkg.id, pkg.branch, pkg.installation)

        watcher.change_progress(10)
        watcher.change_substatus(self.i18n['flatpak.downgrade.commits'])
        commits = flatpak.get_app_commits(pkg.ref, pkg.origin,
                                          pkg.installation, handler)

        if commits is None:
            return False

        commit_idx = commits.index(pkg.commit)

        # downgrade is not possible if the app current commit in the first one:
        if commit_idx == len(commits) - 1:
            watcher.show_message(
                self.i18n['flatpak.downgrade.impossible.title'],
                self.i18n['flatpak.downgrade.impossible.body'],
                MessageType.WARNING)
            return False

        commit = commits[commit_idx + 1]
        watcher.change_substatus(self.i18n['flatpak.downgrade.reverting'])
        watcher.change_progress(50)
        success = handler.handle(
            SystemProcess(
                subproc=flatpak.downgrade(pkg.ref, commit, pkg.installation,
                                          root_password),
                success_phrases=['Changes complete.', 'Updates complete.'],
                wrong_error_phrase='Warning'))
        watcher.change_progress(100)
        return success
Beispiel #7
0
    def test__sort_deps__one_app_one_runtime(self):
        pkgs = [
            FlatpakApplication(id="org.gnome.gedit",
                               name='Gedit',
                               runtime=False),
            FlatpakApplication(id="org.gnome.Platform",
                               name='org.gnome.Platform',
                               runtime=True),
        ]

        sorted_list = self.manager.sort_update_order(pkgs)
        self.assertIsInstance(sorted_list, list)
        self.assertEqual(len(pkgs), len(sorted_list))

        self.assertEqual(pkgs[1], sorted_list[0])
        self.assertEqual(pkgs[0], sorted_list[1])
Beispiel #8
0
    def test__sort_deps__only_apps(self):
        pkgs = [
            FlatpakApplication(id="org.gnome.gedit",
                               name='Gedit',
                               runtime=False),
            FlatpakApplication(id="com.spotify.Client",
                               name='com.spotify.Client',
                               runtime=False),
        ]

        sorted_list = self.manager.sort_update_order(pkgs)
        self.assertIsInstance(sorted_list, list)
        self.assertEqual(len(pkgs), len(sorted_list))

        for pkg in sorted_list:
            self.assertIn(pkg, pkgs)
Beispiel #9
0
    def get_history(self, pkg: FlatpakApplication, full_commit_str: bool = False) -> PackageHistory:
        pkg.commit = flatpak.get_commit(pkg.id, pkg.branch, pkg.installation)
        pkg_commit = pkg.commit if pkg.commit else None

        if pkg_commit and not full_commit_str:
            pkg_commit = pkg_commit[0:8]

        commits = flatpak.get_app_commits_data(pkg.ref, pkg.origin, pkg.installation, full_str=full_commit_str)

        status_idx = 0
        commit_found = False

        if pkg_commit is None and len(commits) > 1 and commits[0]['commit'] == '(null)':
            del commits[0]
            pkg_commit = commits[0]
            commit_found = True

        if not commit_found:
            for idx, data in enumerate(commits):
                if data['commit'] == pkg_commit:
                    status_idx = idx
                    commit_found = True
                    break

        if not commit_found and pkg_commit and commits[0]['commit'] == '(null)':
            commits[0]['commit'] = pkg_commit

        return PackageHistory(pkg=pkg, history=commits, pkg_status_idx=status_idx)
Beispiel #10
0
    def test_sort_deps_two_apps_two_runtimes_one_partial(self):
        gnome_platform = FlatpakApplication(id="org.gnome.Platform",
                                            name='Platform',
                                            runtime=True)
        gnome_locale = FlatpakApplication(id="org.gnome.Platform.Locale",
                                          name="Locale",
                                          runtime=True,
                                          partial=True)
        gnome_locale.base_id = gnome_platform.id

        pkgs = [
            FlatpakApplication(id="org.gnome.gedit",
                               name='Gedit',
                               runtime=False), gnome_platform,
            FlatpakApplication(id="com.spotify.Client",
                               name='Spotify',
                               runtime=False),
            FlatpakApplication(id="org.freedesktop.Platform.GL.default",
                               name='default',
                               runtime=True), gnome_locale
        ]

        sorted_list = self.manager.sort_update_order(pkgs)
        self.assertIsInstance(sorted_list, list)
        self.assertEqual(len(pkgs), len(sorted_list))

        self.assertEqual(pkgs[4], sorted_list[0])
        self.assertEqual(pkgs[1], sorted_list[1])
        self.assertEqual(pkgs[3], sorted_list[2])
        self.assertEqual(pkgs[0], sorted_list[3])
        self.assertEqual(pkgs[2], sorted_list[4])
Beispiel #11
0
    def _map_to_model(self, app_json: dict, installed: bool, disk_loader: Optional[DiskCacheLoader], internet: bool = True) -> Tuple[FlatpakApplication, Optional[FlatpakAsyncDataLoader]]:

        app = FlatpakApplication(**app_json, i18n=self.i18n)
        app.installed = installed
        api_data = self.api_cache.get(app_json['id'])

        if app.runtime and app.latest_version is None:
            app.latest_version = app.version

        expired_data = api_data and api_data.get('expires_at') and api_data['expires_at'] <= datetime.utcnow()

        data_loader: Optional[FlatpakAsyncDataLoader] = None

        if not api_data or expired_data:
            if not app.runtime:
                if disk_loader:
                    disk_loader.fill(app)  # preloading cached disk data

                if internet:
                    data_loader = FlatpakAsyncDataLoader(app=app, api_cache=self.api_cache, manager=self,
                                                         context=self.context, category_cache=self.category_cache)
                    data_loader.start()

        else:
            app.fill_cached_data(api_data)
            app.status = PackageStatus.READY

        return app, data_loader
Beispiel #12
0
    def get_history(self, pkg: FlatpakApplication) -> PackageHistory:
        pkg.commit = flatpak.get_commit(pkg.id, pkg.branch)
        commits = flatpak.get_app_commits_data(pkg.ref, pkg.origin)
        status_idx = 0

        for idx, data in enumerate(commits):
            if data['commit'] == pkg.commit:
                status_idx = idx
                break

        return PackageHistory(pkg=pkg, history=commits, pkg_status_idx=status_idx)
Beispiel #13
0
    def test_sort_deps_two_apps_two_runtimes_two_partials(self):
        gnome_platform = FlatpakApplication(id="org.gnome.Platform",
                                            name='Platform',
                                            runtime=True)
        gnome_locale = FlatpakApplication(id="org.gnome.Platform.Locale",
                                          name="Locale",
                                          runtime=True,
                                          partial=True)
        gnome_locale.base_id = gnome_platform.id

        platform_default = FlatpakApplication(
            id="org.freedesktop.Platform.GL.default",
            name='Default',
            runtime=True)
        platform_locale = FlatpakApplication(
            id="org.freedesktop.Platform.GL.Locale",
            name='Locale',
            runtime=True,
            partial=True)
        platform_locale.base_id = platform_default.id

        pkgs = [
            platform_locale,
            FlatpakApplication(id="org.gnome.gedit",
                               name='Gedit',
                               runtime=False), gnome_platform,
            FlatpakApplication(id="com.spotify.Client",
                               name='Spotify',
                               runtime=False), platform_default, gnome_locale
        ]

        sorted_list = self.manager.sort_update_order(pkgs)
        self.assertIsInstance(sorted_list, list)
        self.assertEqual(len(pkgs), len(sorted_list))

        self.assertEqual(platform_default.id, sorted_list[0].id)
        self.assertEqual(platform_locale.id, sorted_list[1].id)
        self.assertEqual(gnome_locale.id, sorted_list[2].id)
        self.assertEqual(gnome_platform.id, sorted_list[3].id)
        self.assertEqual('org.gnome.gedit', sorted_list[4].id)
        self.assertEqual('com.spotify.Client', sorted_list[5].id)
Beispiel #14
0
    def test_sort_deps_two_apps_two_runtimes(self):
        pkgs = [
            FlatpakApplication(id="org.gnome.gedit",
                               name='Gedit',
                               runtime=False),
            FlatpakApplication(id="org.gnome.Platform",
                               name='Platform',
                               runtime=True),
            FlatpakApplication(id="com.spotify.Client",
                               name='Spotify',
                               runtime=False),
            FlatpakApplication(id="org.freedesktop.Platform.GL.default",
                               name='default',
                               runtime=True)
        ]

        sorted_list = self.manager.sort_update_order(pkgs)
        self.assertIsInstance(sorted_list, list)
        self.assertEqual(len(pkgs), len(sorted_list))

        self.assertEqual(pkgs[1], sorted_list[0])
        self.assertEqual(pkgs[3], sorted_list[1])
        self.assertEqual(pkgs[0], sorted_list[2])
        self.assertEqual(pkgs[2], sorted_list[3])
Beispiel #15
0
    def install(self, pkg: FlatpakApplication, root_password: str,
                disk_loader: DiskCacheLoader,
                watcher: ProcessWatcher) -> TransactionResult:
        flatpak_config = self.configman.get_config()

        install_level = flatpak_config['installation_level']

        if install_level is not None:
            self.logger.info(
                "Default Flaptak installation level defined: {}".format(
                    install_level))

            if install_level not in ('user', 'system'):
                watcher.show_message(
                    title=self.i18n['error'].capitalize(),
                    body=self.i18n['flatpak.install.bad_install_level.body'].
                    format(field=bold('installation_level'),
                           file=bold(CONFIG_FILE)),
                    type_=MessageType.ERROR)
                return TransactionResult(success=False,
                                         installed=[],
                                         removed=[])

            pkg.installation = install_level
        else:
            user_level = watcher.request_confirmation(
                title=self.i18n['flatpak.install.install_level.title'],
                body=self.i18n['flatpak.install.install_level.body'].format(
                    bold(pkg.name)),
                confirmation_label=self.i18n['no'].capitalize(),
                deny_label=self.i18n['yes'].capitalize())
            pkg.installation = 'user' if user_level else 'system'

        remotes = flatpak.list_remotes()

        handler = ProcessHandler(watcher)

        if pkg.installation == 'user' and not remotes['user']:
            handler.handle_simple(flatpak.set_default_remotes('user'))
        elif pkg.installation == 'system' and not remotes['system']:
            if user.is_root():
                handler.handle_simple(flatpak.set_default_remotes('system'))
            else:
                valid, user_password = watcher.request_root_password()
                if not valid:
                    watcher.print('Operation aborted')
                    return TransactionResult(success=False,
                                             installed=[],
                                             removed=[])
                else:
                    if not handler.handle_simple(
                            flatpak.set_default_remotes(
                                'system', user_password))[0]:
                        watcher.show_message(
                            title=self.i18n['error'].capitalize(),
                            body=self.
                            i18n['flatpak.remotes.system_flathub.error'],
                            type_=MessageType.ERROR)
                        watcher.print("Operation cancelled")
                        return TransactionResult(success=False,
                                                 installed=[],
                                                 removed=[])

        # retrieving all installed so it will be possible to know the additional installed runtimes after the operation succeeds
        flatpak_version = flatpak.get_version()
        installed = flatpak.list_installed(flatpak_version)
        installed_by_level = {
            '{}:{}:{}'.format(p['id'], p['name'], p['branch'])
            for p in installed if p['installation'] == pkg.installation
        } if installed else None

        if not self._make_exports_dir(handler.watcher):
            return TransactionResult(success=False, installed=[], removed=[])

        installed, output = handler.handle_simple(
            flatpak.install(str(pkg.id), pkg.origin, pkg.installation))

        if not installed and 'error: No ref chosen to resolve matches' in output:
            ref_opts = RE_INSTALL_REFS.findall(output)

            if ref_opts and len(ref_opts) > 1:
                view_opts = [
                    InputOption(label=o, value=o.strip()) for o in ref_opts
                    if o
                ]
                ref_select = SingleSelectComponent(type_=SelectViewType.RADIO,
                                                   options=view_opts,
                                                   default_option=view_opts[0],
                                                   label='')
                if watcher.request_confirmation(
                        title=self.i18n['flatpak.install.ref_choose.title'],
                        body=self.i18n['flatpak.install.ref_choose.body'].
                        format(bold(pkg.name)),
                        components=[ref_select],
                        confirmation_label=self.i18n['proceed'].capitalize(),
                        deny_label=self.i18n['cancel'].capitalize()):
                    ref = ref_select.get_selected()
                    installed, output = handler.handle_simple(
                        flatpak.install(ref, pkg.origin, pkg.installation))
                    pkg.ref = ref
                    pkg.runtime = 'runtime' in ref
                else:
                    watcher.print('Aborted by the user')
                    return TransactionResult.fail()
            else:
                return TransactionResult.fail()

        if installed:
            try:
                fields = flatpak.get_fields(str(pkg.id), pkg.branch,
                                            ['Ref', 'Branch'])

                if fields:
                    pkg.ref = fields[0]
                    pkg.branch = fields[1]
            except:
                traceback.print_exc()

        if installed:
            new_installed = [pkg]
            current_installed = flatpak.list_installed(flatpak_version)
            current_installed_by_level = [
                p for p in current_installed
                if p['installation'] == pkg.installation
            ] if current_installed else None

            if current_installed_by_level and (not installed_by_level or
                                               len(current_installed_by_level)
                                               > len(installed_by_level) + 1):
                pkg_key = '{}:{}:{}'.format(pkg.id, pkg.name, pkg.branch)
                net_available = self.context.is_internet_available()
                for p in current_installed_by_level:
                    current_key = '{}:{}:{}'.format(p['id'], p['name'],
                                                    p['branch'])
                    if current_key != pkg_key and (not installed_by_level
                                                   or current_key
                                                   not in installed_by_level):
                        new_installed.append(
                            self._map_to_model(app_json=p,
                                               installed=True,
                                               disk_loader=disk_loader,
                                               internet=net_available))

            return TransactionResult(success=installed,
                                     installed=new_installed,
                                     removed=[])
        else:
            return TransactionResult.fail()
Beispiel #16
0
    def read_installed(self, disk_loader: Optional[DiskCacheLoader], limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None,
                       internet_available: bool = None, wait_async_data: bool = False) -> SearchResult:
        version = flatpak.get_version()

        updates, required_runtimes = list(), dict()

        thread_updates, thread_runtimes = None, None
        if internet_available:
            thread_updates = Thread(target=self._add_updates, args=(version, updates))
            thread_updates.start()

            if version >= VERSION_1_12:
                thread_runtimes = Thread(target=self._fill_required_runtime_updates, args=(required_runtimes,))
                thread_runtimes.start()

        installed = flatpak.list_installed(version)

        update_map = None
        if thread_updates:
            thread_updates.join()
            update_map = updates[0]

        models = {}
        data_loaders: Optional[List[FlatpakAsyncDataLoader]] = [] if wait_async_data else None

        if installed:
            for app_json in installed:
                model, loader = self._map_to_model(app_json=app_json, installed=True,
                                                   disk_loader=disk_loader, internet=internet_available)
                model.update = False
                models[model.get_update_id(version)] = model

                if loader and data_loaders is not None:
                    data_loaders.append(loader)

        if update_map:
            for update_id in update_map['full']:
                model_with_update = models.get(update_id)
                if model_with_update:
                    model_with_update.update = True
                else:
                    # it is a new component that must be installed
                    update_id_split = update_id.split('/')
                    new_app = FlatpakApplication(id=update_id_split[0],
                                                 branch=update_id_split[1],
                                                 installation=update_id_split[2],
                                                 name=update_id_split[0].split('.')[-1].strip(),
                                                 version=update_id_split[1],
                                                 arch='x86_64' if self.context.is_system_x86_64() else 'x86',
                                                 origin=update_id_split[3] if len(update_id_split) == 4 else None)
                    new_app.update_component = True  # mark as "update component"
                    new_app.installed = True  # faking the "installed" status to be displayed as an update
                    new_app.update = True
                    new_app.update_ref()
                    models[update_id] = new_app

            if version >= VERSION_1_2:
                for partial_update_id in update_map['partial']:
                    partial_data = partial_update_id.split('/')

                    for model in models.values():
                        if model.installation == partial_data[2] and model.branch == partial_data[1]:
                            if model.id == partial_data[0]:
                                model.update = True
                                break
                            elif model.id in partial_data[0]:
                                partial_model = model.gen_partial(partial_data[0])
                                partial_model.update = True
                                models[partial_update_id] = partial_model
                                break

        if thread_runtimes:
            thread_runtimes.join()

        if required_runtimes:
            for installation in ('system', 'user'):
                installation_runtimes = required_runtimes.get(installation)

                if installation_runtimes:
                    for ref, origin in installation_runtimes:
                        ref_split = ref.split('/')
                        models[f'{installation}.'] = FlatpakApplication(id=ref_split[1],
                                                                        ref=ref,
                                                                        origin=origin,
                                                                        name=ref_split[1],
                                                                        version=ref_split[-1],
                                                                        latest_version=ref_split[-1],
                                                                        runtime=True,
                                                                        installation=installation,
                                                                        installed=False,
                                                                        update_component=True,
                                                                        update=True)

        if models:
            ignored = self._read_ignored_updates()

            if ignored:
                for model in models.values():
                    if model.get_update_ignore_key() in ignored:
                        model.updates_ignored = True

        if data_loaders:
            for loader in data_loaders:
                loader.join()

        return SearchResult([*models.values()], None, len(models))