Beispiel #1
0
    def run(self):
        self.taskman.register_task(self.task_id, self.i18n['arch.task.mirrors'], get_icon_path())
        self.logger.info("Refreshing mirrors")

        handler = ProcessHandler()
        try:
            self.taskman.update_progress(self.task_id, 10, '')
            success, output = handler.handle_simple(pacman.refresh_mirrors(self.root_password), output_handler=self._notify_output)

            if success:

                if self.sort_limit is not None and self.sort_limit >= 0:
                    self.taskman.update_progress(self.task_id, 50, self.i18n['arch.custom_action.refresh_mirrors.status.updating'])
                    try:
                        handler.handle_simple(pacman.sort_fastest_mirrors(self.root_password, self.sort_limit), output_handler=self._notify_output)
                    except:
                        self.logger.error("Could not sort mirrors by speed")
                        traceback.print_exc()

                mirrors.register_sync(self.logger)
            else:
                self.logger.error("It was not possible to refresh mirrors")
        except:
            self.logger.error("It was not possible to refresh mirrors")
            traceback.print_exc()

        self.taskman.update_progress(self.task_id, 100, None)
        self.taskman.finish_task(self.task_id)
        self.logger.info("Finished")
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 _generate_backup(self, app_config: dict, root_password: Optional[str]) -> bool:
        if app_config['backup']['mode'] not in ('only_one', 'incremental'):
            self.show_message(title=self.i18n['error'].capitalize(),
                              body='{}: {}'.format(self.i18n['action.backup.invalid_mode'],bold(app_config['backup']['mode'])),
                              type_=MessageType.ERROR)
            self.change_substatus('')
            return False

        handler = ProcessHandler(self)
        if app_config['backup']['mode'] == 'only_one':
            remove_method = app_config['backup']['remove_method']

            if remove_method not in BACKUP_REMOVE_METHODS:
                remove_method = BACKUP_DEFAULT_REMOVE_METHOD

            delete_failed = False

            if remove_method == 'self':
                previous_snapshots = tuple(timeshift.read_created_snapshots(root_password))

                if previous_snapshots:
                    substatus = f"[{self.i18n['core.config.tab.backup'].lower()}] {self.i18n['action.backup.substatus.delete']}"
                    self.change_substatus(substatus)

                    for snapshot in reversed(previous_snapshots):
                        deleted, _ = handler.handle_simple(timeshift.delete(snapshot, root_password))

                        if not deleted:
                            delete_failed = True
            else:
                deleted, _ = handler.handle_simple(timeshift.delete_all_snapshots(root_password))
                delete_failed = not deleted

            if delete_failed and not self.request_confirmation(title=self.i18n['core.config.tab.backup'],
                                                               body=f"{self.i18n['action.backup.error.delete']}. "
                                                                    f"{self.i18n['action.backup.error.proceed']}",
                                                               confirmation_label=self.i18n['yes'].capitalize(),
                                                               deny_label=self.i18n['no'].capitalize()):
                self.change_substatus('')
                return False

        self.change_substatus('[{}] {}'.format(self.i18n['core.config.tab.backup'].lower(), self.i18n['action.backup.substatus.create']))
        created, _ = handler.handle_simple(timeshift.create_snapshot(root_password, app_config['backup']['type']))

        if not created and not self.request_confirmation(title=self.i18n['core.config.tab.backup'],
                                                         body='{}. {}'.format(self.i18n['action.backup.error.create'],
                                                                              self.i18n['action.backup.error.proceed']),
                                                         confirmation_label=self.i18n['yes'].capitalize(),
                                                         deny_label=self.i18n['no'].capitalize()):
            self.change_substatus('')
            return False

        self.change_substatus('')
        return True
Beispiel #4
0
    def _generate_backup(self, app_config: dict, i18n: I18n,
                         root_password: str) -> bool:
        if timeshift.is_available():
            if app_config['backup']['mode'] not in ('only_one', 'incremental'):
                self.show_message(title=self.i18n['error'].capitalize(),
                                  body='{}: {}'.format(
                                      self.i18n['action.backup.invalid_mode'],
                                      bold(app_config['backup']['mode'])),
                                  type_=MessageType.ERROR)
                return False

            if not user.is_root() and not root_password:
                root_pwd, valid = self.request_root_password()
            else:
                root_pwd, valid = root_password, True

            if not valid:
                return False

            handler = ProcessHandler(self)
            if app_config['backup']['mode'] == 'only_one':
                self.change_substatus('[{}] {}'.format(
                    i18n['core.config.tab.backup'].lower(),
                    i18n['action.backup.substatus.delete']))
                deleted, _ = handler.handle_simple(
                    timeshift.delete_all_snapshots(root_pwd))

                if not deleted and not self.request_confirmation(
                        title=i18n['core.config.tab.backup'],
                        body='{}. {}'.format(
                            i18n['action.backup.error.delete'],
                            i18n['action.backup.error.proceed']),
                        confirmation_label=i18n['yes'].capitalize(),
                        deny_label=i18n['no'].capitalize()):
                    return False

            self.change_substatus('[{}] {}'.format(
                i18n['core.config.tab.backup'].lower(),
                i18n['action.backup.substatus.create']))
            created, _ = handler.handle_simple(
                timeshift.create_snapshot(root_pwd,
                                          app_config['backup']['type']))

            if not created and not self.request_confirmation(
                    title=i18n['core.config.tab.backup'],
                    body='{}. {}'.format(i18n['action.backup.error.create'],
                                         i18n['action.backup.error.proceed']),
                    confirmation_label=i18n['yes'].capitalize(),
                    deny_label=i18n['no'].capitalize()):
                return False

        return True
Beispiel #5
0
def check(project_dir: str, optimize: bool, missing_deps: bool, handler: ProcessHandler,
          custom_pkgbuild: Optional[str] = None, custom_user: Optional[str] = None) -> dict:
    res = {}

    cmd = ['makepkg', '-ALcfm', '--check', '--noarchive', '--nobuild', '--noprepare']

    if not missing_deps:
        cmd.append('--nodeps')

    if custom_pkgbuild:
        cmd.append('-p')
        cmd.append(custom_pkgbuild)

    if optimize:
        if os.path.exists(CUSTOM_MAKEPKG_FILE):
            handler.watcher.print(f'Using custom makepkg.conf -> {CUSTOM_MAKEPKG_FILE}')
            cmd.append(f'--config={CUSTOM_MAKEPKG_FILE}')
        else:
            handler.watcher.print(f'Custom optimized makepkg.conf ({CUSTOM_MAKEPKG_FILE}) not found')

    success, output = handler.handle_simple(SimpleProcess(cmd, cwd=project_dir, shell=True, custom_user=custom_user))

    if missing_deps and 'Missing dependencies' in output:
        res['missing_deps'] = RE_DEPS_PATTERN.findall(output)

    gpg_keys = RE_UNKNOWN_GPG_KEY.findall(output)

    if gpg_keys:
        res['gpg_key'] = gpg_keys[0]

    if 'One or more files did not pass the validity check' in output:
        res['validity_check'] = True

    return res
Beispiel #6
0
    def run(self) -> bool:
        ti = time.time()
        self._log.info("Begin: packages synchronization")
        self._taskman.update_progress(self._id, 1, None)

        handler = ProcessHandler(self._watcher)
        updated, _ = handler.handle_simple(self._aptitude.update(
            self._root_password),
                                           output_handler=self._notify_output)
        self._taskman.update_progress(self._id, 99, None)

        if updated:
            index_timestamp = datetime.utcnow().timestamp()
            finish_msg = None
            try:
                with open(PACKAGE_SYNC_TIMESTAMP_FILE, 'w+') as f:
                    f.write(str(index_timestamp))
            except OSError:
                finish_msg = self._i18n['error']
                self._log.error(
                    f"Could not write the packages synchronization timestamp to file "
                    f"'{PACKAGE_SYNC_TIMESTAMP_FILE}'")
        else:
            finish_msg = self._i18n['error']

        self._taskman.update_progress(self._id, 100, finish_msg)
        self._taskman.finish_task(self._id)

        tf = time.time()
        self._log.info(
            f"Finish: packages synchronization ({tf - ti:.4f} seconds)")
        return updated
Beispiel #7
0
def get_app_commits(app_ref: str, origin: str, installation: str, handler: ProcessHandler) -> List[str]:
    try:
        p = SimpleProcess(['flatpak', 'remote-info', '--log', origin, app_ref, '--{}'.format(installation)])
        success, output = handler.handle_simple(p)
        if output.startswith('error:'):
            return
        else:
            return re.findall(r'Commit+:\s(.+)', output)
    except:
        raise NoInternetException()
Beispiel #8
0
    def _rm_bad_file(self, file_name: str, output_path: str, cwd,
                     handler: ProcessHandler, root_password: Optional[str]):
        to_delete = output_path if output_path else f'{cwd}/{file_name}'

        if to_delete and os.path.exists(to_delete):
            self.logger.info(f'Removing downloaded file {to_delete}')
            success, _ = handler.handle_simple(
                SimpleProcess(['rm', '-rf', to_delete],
                              root_password=root_password))
            return success
Beispiel #9
0
    def _rm_bad_file(self, file_name: str, output_path: str, cwd,
                     handler: ProcessHandler, root_password: str):
        to_delete = output_path if output_path else '{}/{}'.format(
            cwd, file_name)

        if to_delete and os.path.exists(to_delete):
            self.logger.info('Removing downloaded file {}'.format(to_delete))
            success, _ = handler.handle_simple(
                SimpleProcess(['rm', '-rf', to_delete],
                              root_password=root_password))
            return success
Beispiel #10
0
    def upgrade(self, requirements: UpgradeRequirements, root_password: str, watcher: ProcessWatcher) -> bool:
        handler = ProcessHandler(watcher)

        targets = (r.pkg.name for r in (*requirements.to_upgrade, *(requirements.to_install or ())))

        with self.output_handler.start(watcher=watcher, targets=targets, action=AptitudeAction.UPGRADE) as handle:
            to_upgrade = (r.pkg.name for r in requirements.to_upgrade)
            success, _ = handler.handle_simple(self.aptitude.upgrade(packages=to_upgrade,
                                                                     root_password=root_password),
                                               output_handler=handle)
        return success
Beispiel #11
0
    def download(self, file_url: str, watcher: ProcessWatcher,
                 output_path: str, cwd: str) -> bool:
        self.logger.info('Downloading {}'.format(file_url))
        handler = ProcessHandler(watcher)
        file_name = file_url.split('/')[-1]

        final_cwd = cwd if cwd else '.'

        success = False
        ti = time.time()
        try:
            if output_path and os.path.exists(output_path):
                self.logger.info(
                    'Removing old file found before downloading: {}'.format(
                        output_path))
                os.remove(output_path)
                self.logger.info("Old file {} removed".format(output_path))

            if self.is_multithreaded():
                ti = time.time()
                process = self._get_aria2c_process(file_url, output_path,
                                                   final_cwd)
                downloader = 'aria2c'
            else:
                ti = time.time()
                process = self._get_wget_process(file_url, output_path,
                                                 final_cwd)
                downloader = 'wget'

            file_size = self.http_client.get_content_length(file_url)
            msg = bold('[{}] ').format(
                downloader) + self.i18n['downloading'] + ' ' + bold(
                    file_url.split('/')[-1]) + (' ( {} )'.format(file_size)
                                                if file_size else '')
            watcher.change_substatus(msg)

            if isinstance(process, SimpleProcess):
                success = handler.handle_simple(process)
            else:
                success = handler.handle(process)
        except:
            traceback.print_exc()
            self._rm_bad_file(file_name, output_path, final_cwd)

        tf = time.time()
        self.logger.info(file_name +
                         ' download took {0:.2f} minutes'.format((tf - ti) /
                                                                 60))

        if not success:
            self.logger.error("Could not download '{}'".format(file_name))
            self._rm_bad_file(file_name, output_path, final_cwd)

        return success
Beispiel #12
0
def make(pkgdir: str, optimize: bool,
         handler: ProcessHandler) -> Tuple[bool, str]:
    cmd = ['makepkg', '-ALcsmf', '--skipchecksums']

    if optimize:
        if os.path.exists(CUSTOM_MAKEPKG_FILE):
            handler.watcher.print(
                'Using custom makepkg.conf -> {}'.format(CUSTOM_MAKEPKG_FILE))
            cmd.append('--config={}'.format(CUSTOM_MAKEPKG_FILE))
        else:
            handler.watcher.print(
                'Custom optimized makepkg.conf ( {} ) not found'.format(
                    CUSTOM_MAKEPKG_FILE))

    return handler.handle_simple(SimpleProcess(cmd, cwd=pkgdir))
Beispiel #13
0
    def _install_node_lib(self, name: str, version: str, handler: ProcessHandler):
        lib_repr = '{}{}'.format(name, '@{}'.format(version) if version else '')
        self.logger.info("Installing {}".format(lib_repr))

        if handler and handler.watcher:
            handler.watcher.change_substatus(self.i18n['web.environment.install'].format(bold(lib_repr)))

        proc = SimpleProcess([NPM_BIN_PATH, 'install', lib_repr], cwd=ENV_PATH, extra_paths=NODE_PATHS)

        installed = handler.handle_simple(proc)[0]

        if installed:
            self.logger.info("{} successfully installed".format(lib_repr))

        return installed
Beispiel #14
0
def build(pkgdir: str, optimize: bool, handler: ProcessHandler, custom_pkgbuild: Optional[str] = None,
          custom_user: Optional[str] = None) -> Tuple[bool, str]:
    cmd = ['makepkg', '-ALcsmf', '--skipchecksums', '--nodeps']

    if custom_pkgbuild:
        cmd.append('-p')
        cmd.append(custom_pkgbuild)

    if optimize:
        if os.path.exists(CUSTOM_MAKEPKG_FILE):
            handler.watcher.print(f'Using custom makepkg.conf -> {CUSTOM_MAKEPKG_FILE}')
            cmd.append(f'--config={CUSTOM_MAKEPKG_FILE}')
        else:
            handler.watcher.print(f'Custom optimized makepkg.conf ({CUSTOM_MAKEPKG_FILE}) not found')

    return handler.handle_simple(SimpleProcess(cmd, cwd=pkgdir, shell=True, custom_user=custom_user))
Beispiel #15
0
def check(pkgdir: str, handler: ProcessHandler) -> dict:
    res = {}
    success, output = handler.handle_simple(
        SimpleProcess(
            ['makepkg', '-ALcf', '--check', '--noarchive', '--nobuild'],
            cwd=pkgdir))

    if 'Missing dependencies' in output:
        res['missing_deps'] = RE_DEPS_PATTERN.findall(output)

    gpg_keys = RE_UNKNOWN_GPG_KEY.findall(output)

    if gpg_keys:
        res['gpg_key'] = gpg_keys[0]

    return res
Beispiel #16
0
def check(pkgdir: str, optimize: bool, missing_deps: bool,
          handler: ProcessHandler) -> dict:
    res = {}

    cmd = [
        'makepkg', '-ALcf', '--check', '--noarchive', '--nobuild',
        '--noprepare'
    ]

    if not missing_deps:
        cmd.append('--nodeps')

    if optimize:
        if os.path.exists(CUSTOM_MAKEPKG_FILE):
            handler.watcher.print(
                'Using custom makepkg.conf -> {}'.format(CUSTOM_MAKEPKG_FILE))
            cmd.append('--config={}'.format(CUSTOM_MAKEPKG_FILE))
        else:
            handler.watcher.print(
                'Custom optimized makepkg.conf ( {} ) not found'.format(
                    CUSTOM_MAKEPKG_FILE))

    success, output = handler.handle_simple(SimpleProcess(cmd, cwd=pkgdir))

    if missing_deps and 'Missing dependencies' in output:
        res['missing_deps'] = RE_DEPS_PATTERN.findall(output)

    gpg_keys = RE_UNKNOWN_GPG_KEY.findall(output)

    if gpg_keys:
        res['gpg_key'] = gpg_keys[0]

    if 'One or more files did not pass the validity check' in output:
        res['validity_check'] = True

    return res
Beispiel #17
0
    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)
Beispiel #18
0
    def install(self, pkg: WebApplication, root_password: str,
                watcher: ProcessWatcher) -> bool:

        continue_install, install_options = self._ask_install_options(
            pkg, watcher)

        if not continue_install:
            watcher.print("Installation aborted by the user")
            return False

        watcher.change_substatus(self.i18n['web.env.checking'])
        handler = ProcessHandler(watcher)

        env_settings = self.env_updater.read_settings()
        local_config = read_config()

        if local_config['environment'][
                'system'] and not nativefier.is_available():
            watcher.show_message(
                title=self.i18n['error'].capitalize(),
                body=self.i18n['web.install.global_nativefier.unavailable'].
                format(n=bold('Nativefier'), app=bold(pkg.name)) + '.',
                type_=MessageType.ERROR)
            return False

        env_components = self.env_updater.check_environment(
            app=pkg,
            local_config=local_config,
            env=env_settings,
            is_x86_x64_arch=self.context.is_system_x86_64())

        comps_to_update = [c for c in env_components if c.update]

        if comps_to_update and not self._ask_update_permission(
                comps_to_update, watcher):
            return False

        if not self.env_updater.update(components=comps_to_update,
                                       handler=handler):
            watcher.show_message(title=self.i18n['error'],
                                 body=self.i18n['web.env.error'].format(
                                     bold(pkg.name)),
                                 type_=MessageType.ERROR)
            return False

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

        app_id, treated_name = self._gen_app_id(pkg.name)
        pkg.id = app_id
        app_dir = '{}/{}'.format(INSTALLED_PATH, app_id)

        watcher.change_substatus(
            self.i18n['web.install.substatus.checking_fixes'])
        fix = self._get_fix_for(
            url_no_protocol=self._strip_url_protocol(pkg.url))
        fix_path = '{}/fix.js'.format(app_dir)

        if fix:
            # just adding the fix as an installation option. The file will be written later
            self.logger.info('Fix found for {}'.format(pkg.url))
            watcher.print('Fix found for {}'.format(pkg.url))
            install_options.append('--inject={}'.format(fix_path))

        # if a custom icon is defined for an app suggestion:
        icon_path, icon_bytes = None, None
        if pkg.icon_url and pkg.save_icon and not {
                o
                for o in install_options if o.startswith('--icon')
        }:
            download = self._download_suggestion_icon(pkg, app_dir)

            if download and download[1]:
                icon_path, icon_bytes = download[0], download[1]
                pkg.custom_icon = icon_path

                # writting the icon in a temporary folder to be used by the nativefier process
                temp_icon_path = '{}/{}'.format(TEMP_PATH,
                                                pkg.icon_url.split('/')[-1])
                install_options.append('--icon={}'.format(temp_icon_path))

                self.logger.info("Writing a temp suggestion icon at {}".format(
                    temp_icon_path))
                with open(temp_icon_path, 'wb+') as f:
                    f.write(icon_bytes)

        watcher.change_substatus(
            self.i18n['web.install.substatus.call_nativefier'].format(
                bold('nativefier')))

        electron_version = str(
            next((c for c in env_components if c.id == 'electron')).version)
        installed = handler.handle_simple(
            nativefier.install(url=pkg.url,
                               name=app_id,
                               output_dir=app_dir,
                               electron_version=electron_version,
                               system=bool(
                                   local_config['environment']['system']),
                               cwd=INSTALLED_PATH,
                               extra_options=install_options))

        if not installed:
            msg = '{}.{}.'.format(
                self.i18n['wen.install.error'].format(bold(pkg.name)),
                self.i18n['web.install.nativefier.error.unknown'].format(
                    bold(self.i18n['details'].capitalize())))
            watcher.show_message(title=self.i18n['error'],
                                 body=msg,
                                 type_=MessageType.ERROR)
            return False

        inner_dir = os.listdir(app_dir)

        if not inner_dir:
            msg = '{}.{}.'.format(
                self.i18n['wen.install.error'].format(bold(pkg.name)),
                self.i18n['web.install.nativefier.error.inner_dir'].format(
                    bold(app_dir)))
            watcher.show_message(title=self.i18n['error'],
                                 body=msg,
                                 type_=MessageType.ERROR)
            return False

        # bringing the inner app folder to the 'installed' folder level:
        inner_dir = '{}/{}'.format(app_dir, inner_dir[0])
        temp_dir = '{}/tmp_{}'.format(INSTALLED_PATH, treated_name)
        os.rename(inner_dir, temp_dir)
        shutil.rmtree(app_dir)
        os.rename(temp_dir, app_dir)

        # injecting a fix
        if fix:
            self.logger.info('Writting JS fix at {}'.format(fix_path))
            with open(fix_path, 'w+') as f:
                f.write(fix)

        # persisting the custom suggestion icon in the defitive directory
        if icon_bytes:
            self.logger.info(
                "Writting the final custom suggestion icon at {}".format(
                    icon_path))
            with open(icon_path, 'wb+') as f:
                f.write(icon_bytes)

        pkg.installation_dir = app_dir

        version_path = '{}/version'.format(app_dir)

        if os.path.exists(version_path):
            with open(version_path, 'r') as f:
                pkg.version = f.read().strip()
                pkg.latest_version = pkg.version

        watcher.change_substatus(self.i18n['web.install.substatus.shortcut'])

        desktop_entry_path = self._gen_desktop_entry_path(app_id)

        entry_content = self._gen_desktop_entry_content(pkg)

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

        with open(desktop_entry_path, 'w+') as f:
            f.write(entry_content)

        pkg.desktop_entry = desktop_entry_path

        if '--tray=start-in-tray' in install_options:
            autostart_dir = '{}/.config/autostart'.format(Path.home())
            Path(autostart_dir).mkdir(parents=True, exist_ok=True)

            with open(pkg.get_autostart_path(), 'w+') as f:
                f.write(entry_content)

        if install_options:
            pkg.options_set = install_options

        return True
Beispiel #19
0
    def install(self, pkg: AppImage, root_password: str,
                watcher: ProcessWatcher) -> bool:
        handler = ProcessHandler(watcher)

        out_dir = INSTALLATION_PATH + pkg.name.lower()
        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 False

        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 False
                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 False

                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 = RE_DESKTOP_EXEC.sub(
                        'Exec={}\n'.format(file_path), de_content)

                    extracted_icon = self._find_icon_file(extracted_folder)

                    if extracted_icon:
                        icon_path = out_dir + '/logo.' + extracted_icon.split(
                            '.')[-1]
                        shutil.copy(
                            '{}/{}'.format(extracted_folder, 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)

                    shutil.rmtree(extracted_folder)
                    return True
                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 False
Beispiel #20
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 #21
0
    def _make_pkg(self,
                  pkgname: str,
                  maintainer: str,
                  root_password: str,
                  handler: ProcessHandler,
                  build_dir: str,
                  project_dir: str,
                  dependency: bool,
                  skip_optdeps: bool = False,
                  change_progress: bool = True) -> bool:

        self._pre_download_source(pkgname, project_dir, handler.watcher)

        self._update_progress(handler.watcher, 50, change_progress)
        if not self._install_missings_deps_and_keys(pkgname, root_password,
                                                    handler, project_dir):
            return False

        # building main package
        handler.watcher.change_substatus(
            self.i18n['arch.building.package'].format(bold(pkgname)))
        pkgbuilt, output = handler.handle_simple(
            SimpleProcess(['makepkg', '-ALcsmf'], cwd=project_dir))
        self._update_progress(handler.watcher, 65, change_progress)

        if pkgbuilt:
            gen_file = [
                fname for root, dirs, files in os.walk(build_dir)
                for fname in files
                if re.match(r'^{}-.+\.tar\.xz'.format(pkgname), fname)
            ]

            if not gen_file:
                handler.watcher.print(
                    'Could not find generated .tar.xz file. Aborting...')
                return False

            install_file = '{}/{}'.format(project_dir, gen_file[0])

            if self._install(pkgname=pkgname,
                             maintainer=maintainer,
                             root_password=root_password,
                             mirror='aur',
                             handler=handler,
                             install_file=install_file,
                             pkgdir=project_dir,
                             change_progress=change_progress):

                if dependency or skip_optdeps:
                    return True

                handler.watcher.change_substatus(
                    self.i18n['arch.optdeps.checking'].format(bold(pkgname)))

                if self._install_optdeps(pkgname,
                                         root_password,
                                         handler,
                                         project_dir,
                                         change_progress=change_progress):
                    return True

        return False
Beispiel #22
0
 def full_update(self, root_password: Optional[str], watcher: ProcessWatcher) -> bool:
     handler = ProcessHandler(watcher)
     return handler.handle_simple(flatpak.full_update(flatpak.get_version()))[0]
Beispiel #23
0
    def download_packages(self,
                          pkgs: List[str],
                          handler: ProcessHandler,
                          root_password: str,
                          sizes: Dict[str, int] = None) -> int:
        ti = time.time()
        watcher = handler.watcher
        mirrors = pacman.list_available_mirrors()

        if not mirrors:
            self.logger.warning('repository mirrors seem to be not reachable')
            watcher.print(
                '[warning] repository mirrors seem to be not reachable')
            watcher.print('[warning] multi-threaded download cancelled')
            return 0

        branch = pacman.get_mirrors_branch()

        if not branch:
            self.logger.warning('no default repository branch found')
            watcher.print('[warning] no default repository branch found')
            watcher.print('[warning] multi-threaded download cancelled')
            return 0

        cache_dir = pacman.get_cache_dir()

        if not os.path.exists(cache_dir):
            success, _ = handler.handle_simple(
                SimpleProcess(['mkdir', '-p', cache_dir],
                              root_password=root_password))

            if not success:
                msg = "could not create cache dir '{}'".format(cache_dir)
                self.logger.warning(msg)
                watcher.print("[warning] {}".format(cache_dir))
                watcher.show_message(
                    title=self.i18n['warning'].capitalize(),
                    body=self.i18n['arch.mthread_downloaded.error.cache_dir'].
                    format(bold(cache_dir)),
                    type_=MessageType.WARNING)
                raise CacheDirCreationException()

        downloader = MultiThreadedDownloader(
            file_downloader=self.file_downloader,
            mirrors_available=mirrors,
            mirrors_branch=branch,
            http_client=self.http_client,
            logger=self.logger,
            cache_dir=cache_dir)

        downloaded = 0
        pkgs_data = pacman.list_download_data(pkgs)

        if not pkgs_data:
            error_msg = "Could not retrieve download data of the following packages: {}".format(
                ', '.join(pkgs))
            watcher.print(error_msg)
            self.logger.error(error_msg)
            return 0

        for pkg in pkgs_data:
            self.logger.info('Preparing to download package: {} ({})'.format(
                pkg['n'], pkg['v']))
            try:
                perc = '({0:.2f}%)'.format(
                    (downloaded / (2 * len(pkgs))) * 100)
                status_prefix = '{} [{}/{}]'.format(perc, downloaded + 1,
                                                    len(pkgs))

                if downloader.download_package(
                        pkg=pkg,
                        root_password=root_password,
                        watcher=handler.watcher,
                        substatus_prefix=status_prefix,
                        size=sizes.get(pkg['n']) if sizes else None):
                    downloaded += 1
            except:
                traceback.print_exc()
                watcher.show_message(
                    title=self.i18n['error'].capitalize(),
                    body=self.i18n['arch.mthread_downloaded.error.cancelled'],
                    type_=MessageType.ERROR)
                raise ArchDownloadException()

        self.logger.info("Waiting for signature downloads to complete")
        downloader.wait_for_async_downloads()
        self.logger.info("Signature downloads finished")
        tf = time.time()
        self.logger.info("Download time: {0:.2f} seconds".format(tf - ti))
        return downloaded
Beispiel #24
0
    def download(self,
                 file_url: str,
                 watcher: ProcessWatcher,
                 output_path: str = None,
                 cwd: str = None,
                 root_password: str = None,
                 substatus_prefix: str = None,
                 display_file_size: bool = True,
                 max_threads: int = None,
                 known_size: int = None) -> bool:
        self.logger.info('Downloading {}'.format(file_url))
        handler = ProcessHandler(watcher)
        file_name = file_url.split('/')[-1]

        final_cwd = cwd if cwd else '.'

        success = False
        ti = time.time()
        try:
            if output_path and os.path.exists(output_path):
                self.logger.info(
                    'Removing old file found before downloading: {}'.format(
                        output_path))
                os.remove(output_path)
                self.logger.info("Old file {} removed".format(output_path))

            client = self.get_available_multithreaded_tool()
            if client:
                threads = self._get_appropriate_threads_number(
                    max_threads, known_size)

                if client == 'aria2':
                    ti = time.time()
                    process = self._get_aria2c_process(file_url, output_path,
                                                       final_cwd,
                                                       root_password, threads)
                    downloader = 'aria2'
                else:
                    ti = time.time()
                    process = self._get_axel_process(file_url, output_path,
                                                     final_cwd, root_password,
                                                     threads)
                    downloader = 'axel'
            else:
                ti = time.time()
                process = self._get_wget_process(file_url, output_path,
                                                 final_cwd, root_password)
                downloader = 'wget'

            name = file_url.split('/')[-1]

            if output_path and not RE_HAS_EXTENSION.match(
                    name) and RE_HAS_EXTENSION.match(output_path):
                name = output_path.split('/')[-1]

            if substatus_prefix:
                msg = substatus_prefix + ' '
            else:
                msg = ''

            msg += bold('[{}] ').format(
                downloader) + self.i18n['downloading'] + ' ' + bold(name)

            if watcher:
                watcher.change_substatus(msg)

                if display_file_size:
                    if known_size:
                        watcher.change_substatus(
                            msg +
                            ' ( {} )'.format(get_human_size_str(known_size)))
                    else:
                        Thread(target=self._display_file_size,
                               args=(file_url, msg, watcher)).start()

            success, _ = handler.handle_simple(process)
        except:
            traceback.print_exc()
            self._rm_bad_file(file_name, output_path, final_cwd, handler,
                              root_password)

        tf = time.time()
        self.logger.info(file_name +
                         ' download took {0:.2f} minutes'.format((tf - ti) /
                                                                 60))

        if not success:
            self.logger.error("Could not download '{}'".format(file_name))
            self._rm_bad_file(file_name, output_path, final_cwd, handler,
                              root_password)

        return success
Beispiel #25
0
    def download(self,
                 file_url: str,
                 watcher: ProcessWatcher,
                 output_path: str = None,
                 cwd: str = None,
                 root_password: Optional[str] = None,
                 substatus_prefix: str = None,
                 display_file_size: bool = True,
                 max_threads: int = None,
                 known_size: int = None) -> bool:
        self.logger.info(f'Downloading {file_url}')
        handler = ProcessHandler(watcher)
        file_name = file_url.split('/')[-1]

        final_cwd = cwd if cwd else '.'

        success = False
        ti = time.time()
        try:
            if output_path:
                if os.path.exists(output_path):
                    self.logger.info(
                        f'Removing old file found before downloading: {output_path}'
                    )
                    os.remove(output_path)
                    self.logger.info(f'Old file {output_path} removed')
                else:
                    output_dir = os.path.dirname(output_path)

                    try:
                        Path(output_dir).mkdir(exist_ok=True, parents=True)
                    except OSError:
                        self.logger.error(
                            f"Could not make download directory '{output_dir}'"
                        )
                        watcher.print(
                            self.i18n['error.mkdir'].format(dir=output_dir))
                        return False

            client = self.get_available_multithreaded_tool()
            if client:
                threads = self._get_appropriate_threads_number(
                    max_threads, known_size)

                if client == 'aria2':
                    ti = time.time()
                    process = self._get_aria2c_process(file_url, output_path,
                                                       final_cwd,
                                                       root_password, threads)
                    downloader = 'aria2'
                else:
                    ti = time.time()
                    process = self._get_axel_process(file_url, output_path,
                                                     final_cwd, root_password,
                                                     threads)
                    downloader = 'axel'
            else:
                ti = time.time()
                process = self._get_wget_process(file_url, output_path,
                                                 final_cwd, root_password)
                downloader = 'wget'

            name = file_url.split('/')[-1]

            if output_path and not RE_HAS_EXTENSION.match(
                    name) and RE_HAS_EXTENSION.match(output_path):
                name = output_path.split('/')[-1]

            if watcher:
                msg = StringIO()
                msg.write(f'{substatus_prefix} ' if substatus_prefix else '')
                msg.write(
                    f"{bold('[{}]'.format(downloader))} {self.i18n['downloading']} {bold(name)}"
                )

                if display_file_size:
                    if known_size:
                        msg.write(f' ( {get_human_size_str(known_size)} )')
                        watcher.change_substatus(msg.getvalue())
                    else:
                        Thread(target=self._concat_file_size,
                               args=(file_url, msg, watcher)).start()
                else:
                    msg.write(' ( ? Mb )')
                    watcher.change_substatus(msg.getvalue())

            success, _ = handler.handle_simple(process)
        except:
            traceback.print_exc()
            self._rm_bad_file(file_name, output_path, final_cwd, handler,
                              root_password)

        tf = time.time()
        self.logger.info(
            f'{file_name} download took {(tf - ti) / 60:.2f} minutes')

        if not success:
            self.logger.error(f"Could not download '{file_name}'")
            self._rm_bad_file(file_name, output_path, final_cwd, handler,
                              root_password)

        return success
Beispiel #26
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()
Beispiel #27
0
    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()
Beispiel #28
0
    def run(self):
        ti = time.time()
        self.taskman.update_progress(
            self.task_id, 0, self.i18n['task.waiting_task'].format(
                bold(self.create_config.task_name)))
        self.create_config.join()

        arch_config = self.create_config.config
        aur_supported = aur.is_supported(arch_config)

        self.taskman.update_progress(self.task_id, 1,
                                     self.i18n['arch.task.checking_settings'])

        if not self.is_enabled(arch_config, aur_supported):
            self.taskman.update_progress(self.task_id, 100,
                                         self.i18n['arch.task.disabled'])
            self.taskman.finish_task(self.task_id)
            return

        if not mirrors.should_sync(self.logger):
            self.taskman.update_progress(self.task_id, 100,
                                         self.i18n['arch.task.mirrors.cached'])
            self.taskman.finish_task(self.task_id)
            return

        sort_limit = arch_config['mirrors_sort_limit']
        self.logger.info("Refreshing mirrors")

        handler = ProcessHandler()
        try:
            self.taskman.update_progress(self.task_id, 10, '')
            success, output = handler.handle_simple(
                pacman.refresh_mirrors(self.root_password),
                output_handler=self._notify_output)

            if success:

                if sort_limit is not None and sort_limit >= 0:
                    self.taskman.update_progress(
                        self.task_id, 50, self.i18n[
                            'arch.custom_action.refresh_mirrors.status.updating']
                    )
                    try:
                        handler.handle_simple(
                            pacman.sort_fastest_mirrors(
                                self.root_password, sort_limit),
                            output_handler=self._notify_output)
                    except:
                        self.logger.error("Could not sort mirrors by speed")
                        traceback.print_exc()

                mirrors.register_sync(self.logger)
                self.refreshed = True
            else:
                self.logger.error("It was not possible to refresh mirrors")
        except:
            self.logger.error("It was not possible to refresh mirrors")
            traceback.print_exc()

        self.taskman.update_progress(self.task_id, 100, None)
        self.taskman.finish_task(self.task_id)
        tf = time.time()
        self.logger.info("Finished. Took {0:.2f} seconds".format(tf - ti))