예제 #1
0
    def _gen_installation_response(self, success: bool, pkg: SnapApplication,
                                   installed: Set[str],
                                   disk_loader: DiskCacheLoader):
        if success:
            new_installed = [pkg]

            if installed:
                try:
                    current_installed = self.read_installed(
                        disk_loader=disk_loader,
                        internet_available=internet.is_available()).installed
                except:
                    current_installed = None

                if current_installed and (
                        not installed
                        or len(current_installed) > len(installed) + 1):
                    for p in current_installed:
                        if p.name != pkg.name and (not installed
                                                   or p.name not in installed):
                            new_installed.append(p)

            return TransactionResult(success=success,
                                     installed=new_installed,
                                     removed=[])
        else:
            return TransactionResult.fail()
예제 #2
0
    def uninstall(self, pkg: AppImage, root_password: Optional[str], watcher: ProcessWatcher, disk_loader: DiskCacheLoader = None) -> TransactionResult:
        if os.path.exists(pkg.get_disk_cache_path()):
            handler = ProcessHandler(watcher)

            if not handler.handle(SystemProcess(new_subprocess(['rm', '-rf', pkg.get_disk_cache_path()]))):
                watcher.show_message(title=self.i18n['error'], body=self.i18n['appimage.uninstall.error.remove_folder'].format(bold(pkg.get_disk_cache_path())))
                return TransactionResult.fail()

            de_path = self._gen_desktop_entry_path(pkg)
            if os.path.exists(de_path):
                os.remove(de_path)

            self.revert_ignored_update(pkg)

        if pkg.symlink and os.path.islink(pkg.symlink):
            self.logger.info(f"Removing symlink '{pkg.symlink}'")

            try:
                os.remove(pkg.symlink)
                self.logger.info(f"symlink '{pkg.symlink}' successfully removed")
            except:
                msg = f"could not remove symlink '{pkg.symlink}'"
                self.logger.error(msg)

                if watcher:
                    watcher.print(f"[error] {msg}")

        self._add_self_latest_version(pkg)  # only for self installation
        return TransactionResult(success=True, installed=None, removed=[pkg])
예제 #3
0
파일: controller.py 프로젝트: vinifmor/bauh
    def _gen_installation_response(self, success: bool, pkg: SnapApplication,
                                   installed: Set[str],
                                   disk_loader: DiskCacheLoader):
        if success:
            new_installed = []
            try:
                net_available = self.context.internet_checker.is_available()
                current_installed = self.read_installed(
                    disk_loader=disk_loader,
                    internet_available=net_available).installed
            except:
                new_installed = [pkg]
                traceback.print_exc()
                current_installed = None

            if current_installed:
                for p in current_installed:
                    if p.name == pkg.name or (not installed
                                              or p.name not in installed):
                        new_installed.append(p)

            return TransactionResult(success=success,
                                     installed=new_installed,
                                     removed=[])
        else:
            return TransactionResult.fail()
예제 #4
0
    def uninstall(self, pkg: FlatpakApplication, root_password: str, watcher: ProcessWatcher, disk_loader: DiskCacheLoader) -> TransactionResult:

        if not self._make_exports_dir(watcher):
            return TransactionResult.fail()

        uninstalled, _ = ProcessHandler(watcher).handle_simple(flatpak.uninstall(pkg.ref, pkg.installation))

        if uninstalled:
            if self.suggestions_cache:
                self.suggestions_cache.delete(pkg.id)

            self.revert_ignored_update(pkg)
            return TransactionResult(success=True, installed=None, removed=[pkg])

        return TransactionResult.fail()
예제 #5
0
    def install(self, app: SoftwarePackage, root_password: str,
                disk_loader: DiskCacheLoader,
                handler: ProcessWatcher) -> TransactionResult:
        man = self._get_manager_for(app)

        if man:
            ti = time.time()
            disk_loader = self.disk_loader_factory.new()
            disk_loader.start()
            try:
                self.logger.info('Installing {}'.format(app))
                res = man.install(app, root_password, disk_loader, handler)
                disk_loader.stop_working()
                disk_loader.join()
                self._update_post_transaction_status(res)
                return res
            except:
                traceback.print_exc()
                return TransactionResult(success=False,
                                         installed=[],
                                         removed=[])
            finally:
                tf = time.time()
                self.logger.info('Installation of {}'.format(app) +
                                 'took {0:.2f} minutes'.format((tf - ti) / 60))
예제 #6
0
    def uninstall(self,
                  pkg: SoftwarePackage,
                  root_password: Optional[str],
                  handler: ProcessWatcher,
                  disk_loader: DiskCacheLoader = None) -> TransactionResult:
        man = self._get_manager_for(pkg)

        if man:
            ti = time.time()
            disk_loader = self.disk_loader_factory.new()
            disk_loader.start()
            self.logger.info(f"Uninstalling {pkg.name}")
            try:
                res = man.uninstall(pkg, root_password, handler, disk_loader)
                disk_loader.stop_working()
                disk_loader.join()
                self._update_post_transaction_status(res)
                return res
            except:
                traceback.print_exc()
                return TransactionResult(success=False,
                                         installed=[],
                                         removed=[])
            finally:
                tf = time.time()
                self.logger.info(
                    f'Uninstallation of {pkg} took {(tf - ti) / 60:.2f} minutes'
                )
예제 #7
0
    def uninstall(self, pkg: SnapApplication, root_password: str,
                  watcher: ProcessWatcher,
                  disk_loader: DiskCacheLoader) -> TransactionResult:
        uninstalled = ProcessHandler(watcher).handle(
            SystemProcess(
                subproc=snap.uninstall_and_stream(pkg.name, root_password)))

        if uninstalled:
            if self.suggestions_cache:
                self.suggestions_cache.delete(pkg.name)

            return TransactionResult(success=True,
                                     installed=None,
                                     removed=[pkg])

        return TransactionResult.fail()
예제 #8
0
    def uninstall(self, pkg: SnapApplication, root_password: str,
                  watcher: ProcessWatcher,
                  disk_loader: DiskCacheLoader) -> TransactionResult:
        if snap.is_installed() and snapd.is_running():
            uninstalled = ProcessHandler(watcher).handle_simple(
                snap.uninstall_and_stream(pkg.name, root_password))[0]

            if uninstalled:
                if self.suggestions_cache:
                    self.suggestions_cache.delete(pkg.name)

                return TransactionResult(success=True,
                                         installed=None,
                                         removed=[pkg])

        return TransactionResult.fail()
예제 #9
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()
예제 #10
0
파일: controller.py 프로젝트: vinifmor/bauh
    def install(self, pkg: SoftwarePackage, root_password: str, disk_loader: Optional[DiskCacheLoader],
                watcher: ProcessWatcher) -> TransactionResult:

        watcher.change_substatus(self._i18n['debian.simulate_operation'])
        transaction = self.aptitude.simulate_installation((pkg.name, ))

        if transaction is None or not transaction.to_install:
            return TransactionResult.fail()

        if transaction.to_remove or (transaction.to_install and len(transaction.to_install) > 1):
            watcher.change_substatus(self._i18n['debian.transaction.get_data'])

            deps = tuple(p for p in transaction.to_install or () if p.name != pkg.name)
            removal = tuple(p for p in transaction.to_remove or ())
            all_pkgs = [*deps, *removal]

            pkgs_data = self.aptitude.show(pkgs=(f'{d.name}={d.version}' for d in all_pkgs),
                                           attrs=self.install_show_attrs)

            if pkgs_data:
                for p in all_pkgs:
                    fill_show_data(p, pkgs_data.get(p.name))

            if not self.view.confirm_transaction(to_install=deps, removal=removal, watcher=watcher):
                return TransactionResult.fail()

        watcher.change_substatus(self._i18n['debian.installing_pkgs'])
        handler = ProcessHandler(watcher)

        targets = (p.name for p in transaction.to_install)
        with self.output_handler.start(watcher=watcher, targets=targets, action=AptitudeAction.INSTALL) as handle:
            installed, _ = handler.handle_simple(self.aptitude.install(packages=(pkg.name,),
                                                                       root_password=root_password),
                                                 output_handler=handle)

        if installed:
            self._refresh_apps_index(watcher)

            watcher.change_substatus(self._i18n['debian.install.validating'])

            currently_installed = set(self.aptitude.read_installed_names())

            installed_instances = []
            if currently_installed:
                for p in transaction.to_install:
                    instance = p if p != pkg else pkg
                    if instance.name in currently_installed:
                        instance.installed = True
                        instance.bind_app(self.apps_index.get(instance.name))
                        installed_instances.append(instance)

            removed = None

            if transaction.to_remove:
                removed = [p for p in transaction.to_remove if p.name not in currently_installed]

                not_removed = set(transaction.to_remove).difference(removed)

                if not_removed:
                    not_removed_str = ' '.join(p.name for p in not_removed)
                    self._log.warning(f"The following packages were not removed: {not_removed_str}")

            return TransactionResult(installed=installed_instances, removed=removed,
                                     success=bool(installed_instances and pkg in installed_instances))
        else:
            watcher.change_substatus('')
            return TransactionResult.fail()
예제 #11
0
파일: controller.py 프로젝트: vinifmor/bauh
    def uninstall(self, pkg: DebianPackage, root_password: str, watcher: ProcessWatcher,
                  disk_loader: Optional[DiskCacheLoader], purge: bool = False) -> TransactionResult:

        config_ = self.configman.get_config()
        purge_ = purge or config_.get('remove.purge', False)

        watcher.change_substatus(self._i18n['debian.simulate_operation'])

        transaction = self.aptitude.simulate_removal((pkg.name,), purge=purge_)

        if not transaction or not transaction.to_remove:
            return TransactionResult.fail()

        if pkg not in transaction.to_remove:
            watcher.show_message(title=self._i18n['popup.title.error'],
                                 body=self._i18n['debian.remove.impossible'].format(pkg=bold(pkg.name)),
                                 type_=MessageType.ERROR)
            return TransactionResult.fail()

        watcher.change_substatus('')

        deps = tuple(p for p in transaction.to_remove if p.name != pkg.name)

        if deps:
            # updates are required to be filled in case the dependencies are currently displayed on the view
            updates = dict()
            fill_updates = Thread(target=self._fill_updates, args=(updates,))
            fill_updates.start()

            deps_data = self.aptitude.show((p.name for p in deps), attrs=('description', 'maintainer', 'section'))

            if deps_data:
                for p in deps:
                    fill_show_data(p, deps_data.get(p.name))

            if not self.view.confirm_removal(source_pkg=pkg.name, dependencies=deps, watcher=watcher):
                return TransactionResult.fail()

            fill_updates.join()

            if updates:
                for p in deps:
                    latest_version = updates.get(p.name)

                    if latest_version is not None and p.version != latest_version:
                        p.latest_version = latest_version
                        p.update = True

        watcher.change_substatus(self._i18n['debian.uninstall.removing'])

        handler = ProcessHandler(watcher)
        to_remove = tuple(p.name for p in transaction.to_remove)
        with self.output_handler.start(watcher=watcher, targets=to_remove, action=AptitudeAction.REMOVE) as handle:
            removed, _ = handler.handle_simple(self.aptitude.remove(packages=to_remove, root_password=root_password,
                                                                    purge=purge_),
                                               output_handler=handle)

        if not removed:
            return TransactionResult.fail()

        watcher.change_substatus(self._i18n['debian.uninstall.validating'])

        current_installed_names = set(self.aptitude.read_installed_names())

        watcher.change_substatus('')

        all_removed, apps_removed, not_removed_names = [], set(), set()

        for p in transaction.to_remove:
            if p.name not in current_installed_names:
                instance = p if p != pkg else pkg

                all_removed.append(instance)

                if instance.app:
                    apps_removed.add(instance.app)

                instance.installed = False
                instance.version = instance.latest_version
                instance.update = False
                instance.bind_app(None)
            else:
                not_removed_names.add(p.name)

        if apps_removed:  # updating apps index
            watcher.print(self._i18n['debian.app_index.updating'] + ' ...')
            watcher.change_substatus(self._i18n['debian.app_index.updating'])
            indexed_apps = set(self.app_indexer.read_index())

            if indexed_apps:
                new_index = indexed_apps.difference(apps_removed)
                try:
                    self.app_indexer.update_index(new_index, update_timestamp=False)
                    self._update_apps_index(new_index)
                    self._log.info(f"Debian applications removed from the index: "
                                   f"{', '.join((a.name for a in apps_removed))}")
                except ApplicationIndexError:
                    pass

        watcher.change_substatus('')

        success = True
        if not_removed_names:
            success = pkg.name not in not_removed_names
            not_removed_str = ', '.join((bold(p) for p in sorted(not_removed_names)))
            watcher.show_message(title=self._i18n[f"popup.title.{'warning' if success else 'error'}"],
                                 body=self._i18n['debian.uninstall.failed_to_remove'].format(no=len(not_removed_names),
                                                                                             pkgs=not_removed_str),
                                 type_=MessageType.WARNING if success else MessageType.ERROR)

        return TransactionResult(success=success, installed=None, removed=all_removed)
예제 #12
0
    def _install(self, pkg: AppImage, watcher: ProcessWatcher, pre_downloaded_file: Optional[Tuple[str, str]] = None) \
            -> TransactionResult:

        handler = ProcessHandler(watcher)
        out_dir = f'{INSTALLATION_DIR}/{pkg.get_clean_name()}'
        counter = 0
        while True:
            if os.path.exists(out_dir):
                self.logger.info(f"Installation dir '{out_dir}' already exists. Generating a different one")
                out_dir += f'-{counter}'
                counter += 1
            else:
                break

        Path(out_dir).mkdir(parents=True, exist_ok=True)
        pkg.install_dir = out_dir

        if pkg.imported:

            downloaded, file_name = True, pkg.local_file_path.split('/')[-1]

            install_file_path = out_dir + '/' + file_name

            try:
                moved, output = handler.handle_simple(SimpleProcess(['mv', pkg.local_file_path, install_file_path]))
            except:
                output = ''
                self.logger.error(f"Could not rename file '{pkg.local_file_path}' as '{install_file_path}'")
                moved = False

            if not moved:
                watcher.show_message(title=self.i18n['error'].capitalize(),
                                     body=self.i18n['appimage.install.imported.rename_error'].format(bold(pkg.local_file_path.split('/')[-1]),
                                                                                                     bold(output)),
                                     type_=MessageType.ERROR)

                return TransactionResult.fail()

        else:
            download_data = pre_downloaded_file if pre_downloaded_file else self._download(pkg, watcher)

            if not download_data:
                return TransactionResult.fail()

            file_name, download_path = download_data[0], download_data[1]

            install_file_path = f'{out_dir}/{file_name}'

            try:
                shutil.move(download_path, install_file_path)
            except OSError:
                watcher.show_message(title=self.i18n['error'],
                                     body=self.i18n['error.mvfile'].formmat(src=bold(download_path),
                                                                            dest=bold(install_file_path)))
                return TransactionResult.fail()

        watcher.change_substatus(self.i18n['appimage.install.permission'].format(bold(file_name)))
        permission_given = handler.handle(SystemProcess(new_subprocess(['chmod', 'a+x', install_file_path])))

        if permission_given:

            watcher.change_substatus(self.i18n['appimage.install.extract'].format(bold(file_name)))

            try:
                res, output = handler.handle_simple(
                    SimpleProcess([install_file_path, '--appimage-extract'], cwd=out_dir))

                if 'Error: Failed to register AppImage in AppImageLauncherFS' in output:
                    watcher.show_message(title=self.i18n['error'],
                                         body=self.i18n['appimage.install.appimagelauncher.error'].format(
                                             appimgl=bold('AppImageLauncher'), app=bold(pkg.name)),
                                         type_=MessageType.ERROR)
                    handler.handle(SystemProcess(new_subprocess(['rm', '-rf', out_dir])))
                    return TransactionResult.fail()
            except:
                watcher.show_message(title=self.i18n['error'],
                                     body=traceback.format_exc(),
                                     type_=MessageType.ERROR)
                traceback.print_exc()
                handler.handle(SystemProcess(new_subprocess(['rm', '-rf', out_dir])))
                return TransactionResult.fail()

            watcher.change_substatus(self.i18n['appimage.install.desktop_entry'])
            extracted_folder = f'{out_dir}/squashfs-root'

            if os.path.exists(extracted_folder):
                desktop_entry = self._find_desktop_file(extracted_folder)

                with open(f'{extracted_folder}/{desktop_entry}') as f:
                    de_content = f.read()

                if de_content:
                    de_content = replace_desktop_entry_exec_command(desktop_entry=de_content,
                                                                    appname=pkg.name,
                                                                    file_path=install_file_path)
                extracted_icon = self._find_icon_file(extracted_folder)

                if extracted_icon:
                    icon_path = out_dir + '/logo.' + extracted_icon.split('/')[-1].split('.')[-1]
                    shutil.copy(extracted_icon, icon_path)

                    if de_content:
                        de_content = RE_DESKTOP_ICON.sub(f'Icon={icon_path}\n', de_content)

                    pkg.icon_path = icon_path

                if not de_content:
                    de_content = pkg.to_desktop_entry()

                Path(DESKTOP_ENTRIES_DIR).mkdir(parents=True, exist_ok=True)

                with open(self._gen_desktop_entry_path(pkg), 'w+') as f:
                    f.write(de_content)

                try:
                    shutil.rmtree(extracted_folder)
                except:
                    traceback.print_exc()

                SymlinksVerifier.create_symlink(app=pkg, file_path=install_file_path, logger=self.logger,
                                                watcher=watcher)
                return TransactionResult(success=True, installed=[pkg], removed=[])
            else:
                watcher.show_message(title=self.i18n['error'],
                                     body=f'Could extract content from {bold(file_name)}',
                                     type_=MessageType.ERROR)

        handler.handle(SystemProcess(new_subprocess(['rm', '-rf', out_dir])))
        return TransactionResult.fail()
예제 #13
0
    def install(self, pkg: AppImage, root_password: str,
                disk_loader: Optional[DiskCacheLoader],
                watcher: ProcessWatcher) -> TransactionResult:
        handler = ProcessHandler(watcher)

        out_dir = INSTALLATION_PATH + pkg.get_clean_name()
        counter = 0
        while True:
            if os.path.exists(out_dir):
                self.logger.info(
                    "Installation dir '{}' already exists. Generating a different one"
                    .format(out_dir))
                out_dir += '-{}'.format(counter)
                counter += 1
            else:
                break

        Path(out_dir).mkdir(parents=True, exist_ok=True)
        pkg.install_dir = out_dir

        if pkg.imported:

            downloaded, file_name = True, pkg.local_file_path.split('/')[-1]

            file_path = out_dir + '/' + file_name

            try:
                moved, output = handler.handle_simple(
                    SimpleProcess(['mv', pkg.local_file_path, file_path]))
            except:
                self.logger.error("Could not rename file '' as '{}'".format(
                    pkg.local_file_path, file_path))
                moved = False

            if not moved:
                watcher.show_message(
                    title=self.i18n['error'].capitalize(),
                    body=self.i18n['appimage.install.imported.rename_error'].
                    format(bold(pkg.local_file_path.split('/')[-1]),
                           bold(output)),
                    type_=MessageType.ERROR)

                return TransactionResult.fail()

        else:
            appimage_url = pkg.url_download_latest_version if pkg.update else pkg.url_download
            file_name = appimage_url.split('/')[-1]
            pkg.version = pkg.latest_version
            pkg.url_download = appimage_url

            file_path = out_dir + '/' + file_name
            downloaded = self.file_downloader.download(
                file_url=pkg.url_download,
                watcher=watcher,
                output_path=file_path,
                cwd=str(Path.home()))

        if downloaded:
            watcher.change_substatus(
                self.i18n['appimage.install.permission'].format(
                    bold(file_name)))
            permission_given = handler.handle(
                SystemProcess(new_subprocess(['chmod', 'a+x', file_path])))

            if permission_given:

                watcher.change_substatus(
                    self.i18n['appimage.install.extract'].format(
                        bold(file_name)))

                try:
                    res, output = handler.handle_simple(
                        SimpleProcess([file_path, '--appimage-extract'],
                                      cwd=out_dir))

                    if 'Error: Failed to register AppImage in AppImageLauncherFS' in output:
                        watcher.show_message(
                            title=self.i18n['error'],
                            body=self.
                            i18n['appimage.install.appimagelauncher.error'].
                            format(appimgl=bold('AppImageLauncher'),
                                   app=bold(pkg.name)),
                            type_=MessageType.ERROR)
                        handler.handle(
                            SystemProcess(
                                new_subprocess(['rm', '-rf', out_dir])))
                        return TransactionResult.fail()
                except:
                    watcher.show_message(title=self.i18n['error'],
                                         body=traceback.format_exc(),
                                         type_=MessageType.ERROR)
                    traceback.print_exc()
                    handler.handle(
                        SystemProcess(new_subprocess(['rm', '-rf', out_dir])))
                    return TransactionResult.fail()

                watcher.change_substatus(
                    self.i18n['appimage.install.desktop_entry'])
                extracted_folder = '{}/{}'.format(out_dir, 'squashfs-root')

                if os.path.exists(extracted_folder):
                    desktop_entry = self._find_desktop_file(extracted_folder)

                    with open('{}/{}'.format(extracted_folder,
                                             desktop_entry)) as f:
                        de_content = f.read()

                    de_content = replace_desktop_entry_exec_command(
                        desktop_entry=de_content,
                        appname=pkg.name,
                        file_path=file_path)

                    extracted_icon = self._find_icon_file(extracted_folder)

                    if extracted_icon:
                        icon_path = out_dir + '/logo.' + extracted_icon.split(
                            '/')[-1].split('.')[-1]
                        shutil.copy(extracted_icon, icon_path)
                        de_content = RE_DESKTOP_ICON.sub(
                            'Icon={}\n'.format(icon_path), de_content)
                        pkg.icon_path = icon_path

                    Path(DESKTOP_ENTRIES_PATH).mkdir(parents=True,
                                                     exist_ok=True)

                    with open(self._gen_desktop_entry_path(pkg), 'w+') as f:
                        f.write(de_content)

                    try:
                        shutil.rmtree(extracted_folder)
                    except:
                        traceback.print_exc()

                    SymlinksVerifier.create_symlink(app=pkg,
                                                    file_path=file_path,
                                                    logger=self.logger,
                                                    watcher=watcher)
                    return TransactionResult(success=True,
                                             installed=[pkg],
                                             removed=[])
                else:
                    watcher.show_message(
                        title=self.i18n['error'],
                        body='Could extract content from {}'.format(
                            bold(file_name)),
                        type_=MessageType.ERROR)
        else:
            watcher.show_message(
                title=self.i18n['error'],
                body=self.i18n['appimage.install.download.error'].format(
                    bold(pkg.url_download)),
                type_=MessageType.ERROR)

        handler.handle(SystemProcess(new_subprocess(['rm', '-rf', out_dir])))
        return TransactionResult.fail()
예제 #14
0
    def install(self, pkg: SnapApplication, root_password: str,
                disk_loader: DiskCacheLoader,
                watcher: ProcessWatcher) -> TransactionResult:
        # retrieving all installed so it will be possible to know the additional installed runtimes after the operation succeeds
        if not snap.is_installed():
            watcher.print("'snap' seems not to be installed")
            return TransactionResult.fail()

        if not snapd.is_running():
            watcher.print("'snapd' seems not to be running")
            return TransactionResult.fail()

        installed_names = {
            s['name']
            for s in SnapdClient(self.logger).list_all_snaps()
        }

        client = SnapdClient(self.logger)
        snap_config = read_config()

        try:
            channel = self._request_channel_installation(
                pkg=pkg,
                snap_config=snap_config,
                snapd_client=client,
                watcher=watcher)
            pkg.channel = channel
        except:
            watcher.print('Aborted by user')
            return TransactionResult.fail()

        res, output = ProcessHandler(watcher).handle_simple(
            snap.install_and_stream(app_name=pkg.name,
                                    confinement=pkg.confinement,
                                    root_password=root_password,
                                    channel=channel))

        if 'error:' in output:
            res = False
            if 'not available on stable' in output:
                channels = RE_AVAILABLE_CHANNELS.findall(output)

                if channels:
                    opts = [
                        InputOption(label=c[0], value=c[1]) for c in channels
                    ]
                    channel_select = SingleSelectComponent(
                        type_=SelectViewType.RADIO,
                        label='',
                        options=opts,
                        default_option=opts[0])
                    body = '<p>{}.</p>'.format(
                        self.i18n['snap.install.available_channels.message'].
                        format(bold(self.i18n['stable']), bold(pkg.name)))
                    body += '<p>{}:</p>'.format(
                        self.i18n['snap.install.available_channels.help'])

                    if watcher.request_confirmation(
                            title=self.
                            i18n['snap.install.available_channels.title'],
                            body=body,
                            components=[channel_select],
                            confirmation_label=self.i18n['continue'],
                            deny_label=self.i18n['cancel']):
                        self.logger.info(
                            "Installing '{}' with the custom command '{}'".
                            format(pkg.name, channel_select.value))
                        res = ProcessHandler(watcher).handle(
                            SystemProcess(
                                new_root_subprocess(
                                    channel_select.value.value.split(' '),
                                    root_password=root_password)))
                        return self._gen_installation_response(
                            success=res,
                            pkg=pkg,
                            installed=installed_names,
                            disk_loader=disk_loader)
                else:
                    self.logger.error(
                        "Could not find available channels in the installation output: {}"
                        .format(output))

        return self._gen_installation_response(success=res,
                                               pkg=pkg,
                                               installed=installed_names,
                                               disk_loader=disk_loader)