示例#1
0
    def request_backup(
            self,
            action_key: Optional[str],
            pkg: Optional[PackageView],
            i18n: I18n,
            app_config: dict,
            root_password: Optional[str],
            backup_only: bool = False) -> Tuple[bool, Optional[str]]:
        if not backup_only:
            if not self._check_backup_requirements(
                    app_config=app_config, pkg=pkg, action_key=action_key):
                return True, root_password

            if not self._should_backup(
                    action_key=action_key, app_config=app_config, i18n=i18n):
                return True, root_password

        pwd = root_password
        if not user.is_root() and pwd is None:
            valid_password, pwd = self.request_root_password()

            if not valid_password:
                return False, None

        return self._generate_backup(app_config=app_config,
                                     i18n=i18n,
                                     root_password=pwd), pwd
示例#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
示例#3
0
    def _request_password(self) -> Tuple[bool, Optional[str]]:
        if not user.is_root():
            success, pwd = self.request_root_password()

            if not success:
                return False, None

            return True, pwd

        return True, None
示例#4
0
    def _request_password(self) -> Tuple[bool, str]:
        if not user.is_root():
            pwd, success = self.request_root_password()

            if not success:
                return False, None

            return True, pwd

        return True, None
示例#5
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
示例#6
0
    def filter_to_update(
        self
    ) -> Tuple[List[PackageView],
               bool]:  # packages to update and if they require root privileges
        to_update, requires_root = [], False
        root_user = user.is_root()

        for pkg in self.pkgs:
            if pkg.model.update and pkg.update_checked:
                to_update.append(pkg)

            if not root_user and not requires_root and self.manager.requires_root(
                    'update', pkg.model):
                requires_root = True

        return to_update, requires_root
示例#7
0
    def _trim_disk(self, root_password: str, ask: bool):
        if not ask or self.request_confirmation(
                title=self.i18n['confirmation'].capitalize(),
                body=self.i18n['action.trim_disk.ask']):

            pwd = root_password

            if not pwd and user.is_root():
                pwd, success = self.request_root_password()

                if not success:
                    return

            self.change_status('{}...'.format(
                self.i18n['action.disk_trim'].capitalize()))
            self.change_substatus('')

            success, output = ProcessHandler(self).handle_simple(
                SimpleProcess(['fstrim', '/', '-v'], root_password=pwd))

            if not success:
                self.show_message(title=self.i18n['success'].capitalize(),
                                  body=self.i18n['action.disk_trim.error'],
                                  type_=MessageType.ERROR)
示例#8
0
    def run(self):
        root_user = user.is_root()
        to_update, upgrade_requires_root, bkp_supported = [], False, False

        for pkg in self.pkgs:
            if pkg.model.update and not pkg.model.is_update_ignored(
            ) and pkg.update_checked:
                to_update.append(pkg)

                if not bkp_supported and pkg.model.supports_backup():
                    bkp_supported = True

                if not root_user and not upgrade_requires_root and self.manager.requires_root(
                        SoftwareAction.UPGRADE, pkg.model):
                    upgrade_requires_root = True

        if upgrade_requires_root:
            valid_password, root_password = self._request_password()
        else:
            valid_password, root_password = True, None

        if not valid_password:
            self.notify_finished({
                'success': False,
                'updated': 0,
                'types': set(),
                'id': None
            })
            self.pkgs = None
            return

        if len(to_update) > 1:
            self.disable_progress_controll()
        else:
            self.enable_progress_controll()

        success = False

        updated, updated_types = 0, set()

        models = [view.model for view in to_update]

        self.change_substatus(self.i18n['action.update.requirements.status'])
        requirements = self.manager.get_upgrade_requirements(
            models, root_password, self)

        if not requirements:
            self.pkgs = None
            self.notify_finished({
                'success': success,
                'updated': updated,
                'types': updated_types,
                'id': None
            })
            return

        comps, required_size, extra_size = [], 0, 0

        if requirements.cannot_upgrade:
            comps.append(
                self._gen_cannot_upgrade_form(requirements.cannot_upgrade))

        if requirements.to_install:
            req_form, reqs_size = self._gen_to_install_form(
                requirements.to_install)
            required_size += reqs_size[0]
            extra_size += reqs_size[1]
            comps.append(req_form)

        if requirements.to_remove:
            comps.append(self._gen_to_remove_form(requirements.to_remove))

        can_upgrade = False
        if requirements.to_upgrade:
            can_upgrade = True
            updates_form, updates_size = self._gen_to_update_form(
                requirements.to_upgrade)
            required_size += updates_size[0]
            extra_size += updates_size[1]
            comps.append(updates_form)

        extra_size_text = '{}: {}'.format(
            self.i18n['action.update.total_size'].capitalize(),
            get_human_size_str(extra_size))
        req_size_text = '{}: {}'.format(
            self.i18n['action.update.required_size'].capitalize(),
            get_human_size_str(required_size))
        comps.insert(
            0,
            TextComponent('{}  |  {}'.format(extra_size_text, req_size_text),
                          size=14))
        comps.insert(1, TextComponent(''))

        if not self.request_confirmation(
                title=self.i18n['action.update.summary'].capitalize(),
                body='',
                components=comps,
                confirmation_label=self.i18n['proceed'].capitalize(),
                deny_label=self.i18n['cancel'].capitalize(),
                confirmation_button=can_upgrade):
            self.notify_finished({
                'success': success,
                'updated': updated,
                'types': updated_types,
                'id': None
            })
            self.pkgs = None
            return

        self.change_substatus('')

        app_config = CoreConfigManager().get_config()

        # backup dialog ( if enabled, supported and accepted )
        should_backup = bkp_supported
        should_backup = should_backup and self._check_backup_requirements(
            app_config=app_config, pkg=None, action_key='upgrade')
        should_backup = should_backup and self._should_backup(
            action_key='upgrade', app_config=app_config, i18n=self.i18n)

        # trim dialog ( if enabled and accepted )
        if app_config['disk']['trim']['after_upgrade'] is not False:
            should_trim = app_config['disk']['trim'][
                'after_upgrade'] or self._ask_for_trim()
        else:
            should_trim = False

        if should_trim and not root_user and root_password is None:  # trim requires root and the password might have not being asked yet
            valid_password, root_password = self._request_password()

            if not valid_password:
                self.notify_finished({
                    'success': False,
                    'updated': 0,
                    'types': set(),
                    'id': None
                })
                self.pkgs = None
                return

        # performing backup
        if should_backup:
            proceed, root_password = self.request_backup(
                action_key='upgrade',
                app_config=app_config,
                i18n=self.i18n,
                root_password=root_password,
                pkg=None,
                backup_only=True)
            if not proceed:
                self.notify_finished({
                    'success': False,
                    'updated': 0,
                    'types': set(),
                    'id': None
                })
                self.pkgs = None
                return

        self.change_substatus('')

        timestamp = datetime.now()
        upgrade_id = 'upgrade_{}{}{}_{}'.format(timestamp.year,
                                                timestamp.month, timestamp.day,
                                                int(time.time()))

        self._write_summary_log(upgrade_id, requirements)

        success = bool(self.manager.upgrade(requirements, root_password, self))
        self.change_substatus('')

        if success:
            updated = len(requirements.to_upgrade)
            updated_types.update(
                (req.pkg.__class__ for req in requirements.to_upgrade))

            if should_trim:
                self._trim_disk(root_password)

            if bool(app_config['updates']['ask_for_reboot']):
                msg = '<p>{}</p>{}</p><br/><p>{}</p>'.format(
                    self.i18n['action.update.success.reboot.line1'],
                    self.i18n['action.update.success.reboot.line2'],
                    self.i18n['action.update.success.reboot.line3'])
                self.request_reboot(msg)

        self.notify_finished({
            'success': success,
            'updated': updated,
            'types': updated_types,
            'id': upgrade_id
        })
        self.pkgs = None
示例#9
0
 def launch(self, pkg: WebApplication):
     subprocess.Popen(pkg.get_command(), shell=user.is_root())
示例#10
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()
示例#11
0
 def get_command(self) -> str:
     if self.installation_dir:
         return '{}{}'.format(self.get_exec_path(), ' --no-sandbox' if user.is_root() else '')
示例#12
0
    def run(self):
        to_update, requires_root = self.filter_to_update()

        root_password = None

        if not user.is_root() and requires_root:
            root_password, ok = self.request_root_password()

            if not ok:
                self.notify_finished({
                    'success': False,
                    'updated': 0,
                    'types': set(),
                    'id': None
                })
                self.pkgs = None
                return

        if len(to_update) > 1:
            self.disable_progress_controll()
        else:
            self.enable_progress_controll()

        success = False

        updated, updated_types = 0, set()

        models = [view.model for view in to_update]

        self.change_substatus(self.i18n['action.update.requirements.status'])
        requirements = self.manager.get_upgrade_requirements(
            models, root_password, self)

        if not requirements:
            self.pkgs = None
            self.notify_finished({
                'success': success,
                'updated': updated,
                'types': updated_types,
                'id': None
            })
            return

        comps, required_size, extra_size = [], 0, 0

        if requirements.cannot_upgrade:
            comps.append(
                self._gen_cannot_update_form(requirements.cannot_upgrade))

        if requirements.to_install:
            req_form, reqs_size = self._gen_to_install_form(
                requirements.to_install)
            required_size += reqs_size[0]
            extra_size += reqs_size[1]
            comps.append(req_form)

        if requirements.to_remove:
            comps.append(self._gen_to_remove_form(requirements.to_remove))

        updates_form, updates_size = self._gen_to_update_form(
            requirements.to_upgrade)
        required_size += updates_size[0]
        extra_size += updates_size[1]
        comps.append(updates_form)

        extra_size_text = '{}: {}'.format(
            self.i18n['action.update.total_size'].capitalize(),
            get_human_size_str(extra_size))
        req_size_text = '{}: {}'.format(
            self.i18n['action.update.required_size'].capitalize(),
            get_human_size_str(required_size))
        comps.insert(
            0,
            TextComponent(bold('{}  |  {}').format(extra_size_text,
                                                   req_size_text),
                          size=14))
        comps.insert(1, TextComponent(''))

        if not self.request_confirmation(
                title=self.i18n['action.update.summary'].capitalize(),
                body='',
                components=comps,
                confirmation_label=self.i18n['proceed'].capitalize(),
                deny_label=self.i18n['cancel'].capitalize()):
            self.notify_finished({
                'success': success,
                'updated': updated,
                'types': updated_types,
                'id': None
            })
            self.pkgs = None
            return

        self.change_substatus('')

        app_config = read_config()

        if bool(app_config['backup']
                ['enabled']) and app_config['backup']['upgrade'] in (
                    True, None) and timeshift.is_available():
            any_requires_bkp = False

            for dep in requirements.to_upgrade:
                if dep.pkg.supports_backup():
                    any_requires_bkp = True
                    break

            if any_requires_bkp:
                if not self.request_backup(app_config, 'upgrade', self.i18n,
                                           root_password):
                    self.notify_finished({
                        'success': success,
                        'updated': updated,
                        'types': updated_types,
                        'id': None
                    })
                    self.pkgs = None
                    return

        self.change_substatus('')

        timestamp = datetime.now()
        upgrade_id = 'upgrade_{}{}{}_{}'.format(timestamp.year,
                                                timestamp.month, timestamp.day,
                                                int(time.time()))

        self._write_summary_log(upgrade_id, requirements)

        success = bool(self.manager.upgrade(requirements, root_password, self))
        self.change_substatus('')

        if success:
            updated = len(requirements.to_upgrade)
            updated_types.update(
                (req.pkg.__class__ for req in requirements.to_upgrade))

            if app_config['disk']['trim']['after_upgrade'] is not False:
                self._trim_disk(
                    root_password,
                    ask=app_config['disk']['trim']['after_upgrade'] is None)

            msg = '<p>{}</p>{}</p><br/><p>{}</p>'.format(
                self.i18n['action.update.success.reboot.line1'],
                self.i18n['action.update.success.reboot.line2'],
                self.i18n['action.update.success.reboot.line3'])
            self.request_reboot(msg)

        self.notify_finished({
            'success': success,
            'updated': updated,
            'types': updated_types,
            'id': upgrade_id
        })
        self.pkgs = None