Example #1
0
    def _req_as_option(self,
                       req: UpgradeRequirement,
                       tooltip: bool = True,
                       custom_tooltip: str = None) -> InputOption:
        if req.pkg.installed:
            icon_path = req.pkg.get_disk_icon_path()

            if not icon_path or not os.path.isfile(icon_path):
                icon_path = req.pkg.get_type_icon_path()

        else:
            icon_path = req.pkg.get_type_icon_path()

        size_str = '{}: {}'.format(
            self.i18n['size'].capitalize(), '?'
            if req.extra_size is None else get_human_size_str(req.extra_size))
        if req.extra_size != req.required_size:
            size_str += ' ( {}: {} )'.format(
                self.i18n['action.update.pkg.required_size'].capitalize(),
                '?' if req.required_size is None else get_human_size_str(
                    req.required_size))

        label = '{}{} - {}'.format(
            req.pkg.name, ' ( {} )'.format(req.pkg.latest_version)
            if req.pkg.latest_version else '', size_str)

        return InputOption(label=label,
                           value=None,
                           tooltip=custom_tooltip if custom_tooltip else
                           (req.pkg.get_name_tooltip() if tooltip else None),
                           read_only=True,
                           icon_path=icon_path)
Example #2
0
    def get_info(self, pkg: SnapApplication) -> dict:
        info = {
            'description': pkg.description,
            'developer': pkg.developer,
            'license': pkg.license,
            'contact': pkg.contact,
            'snap-id': pkg.id,
            'name': pkg.name,
            'publisher': pkg.publisher,
            'revision': pkg.rev,
            'tracking': pkg.tracking,
            'channel': pkg.channel,
            'type': pkg.type
        }

        if pkg.installed:
            commands = [
                *{
                    c['name']
                    for c in SnapdClient(self.logger).list_commands(pkg.name)
                }
            ]
            commands.sort()
            info['commands'] = commands

            if pkg.installed_size:
                info['installed_size']: get_human_size_str(pkg.installed_size)
        elif pkg.download_size:
            info['download_size'] = get_human_size_str(pkg.download_size)

        return info
Example #3
0
    def get_info(self, pkg: WebApplication) -> dict:
        if pkg.installed:
            info = {
                '0{}_{}'.format(idx + 1, att): getattr(pkg, att)
                for idx, att in enumerate(('url', 'description', 'version',
                                           'categories', 'installation_dir',
                                           'desktop_entry'))
            }
            info['07_exec_file'] = pkg.get_exec_path()
            info['08_icon_path'] = pkg.get_disk_icon_path()

            if os.path.exists(pkg.installation_dir):
                info['09_size'] = get_human_size_str(
                    get_dir_size(pkg.installation_dir))

            config_dir = pkg.get_config_dir()

            if config_dir:
                info['10_config_dir'] = config_dir

            if info.get('04_categories'):
                info['04_categories'] = [
                    self.i18n[c.lower()].capitalize()
                    for c in info['04_categories']
                ]

            return info
        else:
            return {
                '0{}_{}'.format(idx + 1, att): getattr(pkg, att)
                for idx, att in enumerate(('url', 'description', 'version',
                                           'categories'))
            }
Example #4
0
def request_install_missing_deps(pkgname: str, deps: List[Tuple[str, str]],
                                 watcher: ProcessWatcher, i18n: I18n) -> bool:
    msg = '<p>{}</p>'.format(i18n['arch.missing_deps.body'].format(
        name=bold(pkgname) if pkgname else '', deps=bold(str(len(deps)))))

    opts = []

    repo_deps = [d[0] for d in deps if d[1] != 'aur']
    sizes = pacman.get_update_size(repo_deps) if repo_deps else {}

    for dep in deps:
        size = sizes.get(dep[0])
        op = InputOption(
            '{} ({}: {}) - {}: {}'.format(
                dep[0], i18n['repository'], dep[1].lower(),
                i18n['size'].capitalize(),
                get_human_size_str(size) if size else '?'), dep[0])
        op.read_only = True
        op.icon_path = _get_repo_icon(dep[1])
        opts.append(op)

    comp = MultipleSelectComponent(label='',
                                   options=opts,
                                   default_options=set(opts))
    return watcher.request_confirmation(
        i18n['arch.missing_deps.title'],
        msg, [comp],
        confirmation_label=i18n['continue'].capitalize(),
        deny_label=i18n['cancel'].capitalize())
Example #5
0
def request_optional_deps(pkgname: str, pkg_repos: dict,
                          watcher: ProcessWatcher, i18n: I18n) -> Set[str]:
    opts = []

    repo_deps = [
        p for p, data in pkg_repos.items() if data['repository'] != 'aur'
    ]
    sizes = pacman.get_update_size(repo_deps) if repo_deps else {}

    for p, d in pkg_repos.items():
        size = sizes.get(p)
        op = InputOption(
            '{}{} ({}: {}) - {}: {}'.format(
                p, ': ' + d['desc'] if d['desc'] else '', i18n['repository'],
                d['repository'].lower(), i18n['size'].capitalize(),
                get_human_size_str(size) if size else '?'), p)
        op.icon_path = _get_repo_icon(d['repository'])
        opts.append(op)

    view_opts = MultipleSelectComponent(label='',
                                        options=opts,
                                        default_options=set(opts))

    install = watcher.request_confirmation(
        title=i18n['arch.install.optdeps.request.title'],
        body='<p>{}.</p><p>{}:</p>'.format(
            i18n['arch.install.optdeps.request.body'].format(bold(pkgname)),
            i18n['arch.install.optdeps.request.help']),
        components=[view_opts],
        confirmation_label=i18n['install'].capitalize(),
        deny_label=i18n['do_not.install'].capitalize())

    if install:
        return {o.value for o in view_opts.values}
Example #6
0
    def _gen_to_install_form(
        self, reqs: List[UpgradeRequirement]
    ) -> Tuple[FormComponent, Tuple[int, int]]:
        opts = [self._req_as_option(r, custom_tooltip=r.reason) for r in reqs]
        comps = [
            MultipleSelectComponent(label='',
                                    options=opts,
                                    default_options=set(opts))
        ]
        required_size, extra_size = self._sum_pkgs_size(reqs)

        lb = '{} ( {}: {}. {}: {}. {}: {} )'.format(
            self.i18n['action.update.required_label'].capitalize(),
            self.i18n['amount'].capitalize(), len(opts),
            self.i18n['size'].capitalize(),
            '?' if extra_size is None else get_human_size_str(extra_size),
            self.i18n['action.update.pkg.required_size'].capitalize(), '?'
            if required_size is None else get_human_size_str(required_size))
        return FormComponent(label=lb,
                             components=comps), (required_size, extra_size)
Example #7
0
    def _gen_to_remove_form(self, reqs: List[UpgradeRequirement]) -> FormComponent:
        opts = [self._req_as_option(r, False, r.reason, required_size=False) for r in reqs]
        comps = [MultipleSelectComponent(label='', options=opts, default_options=set(opts))]
        required_size, extra_size = self._sum_pkgs_size(reqs)

        lb = '{} ( {}: {}. {}: {} )'.format(self.i18n['action.update.label_to_remove'].capitalize(),
                                            self.i18n['amount'].capitalize(),
                                            len(opts),
                                            self.i18n['size'].capitalize(),
                                            '?' if extra_size is None else get_human_size_str(-extra_size))
        return FormComponent(label=lb, components=comps)
Example #8
0
    def get_content_length(self, url: str, session: bool = True) -> str:
        params = {'url': url, 'allow_redirects': True, 'stream': True}
        if session:
            res = self.session.get(**params)
        else:
            res = requests.get(**params)

        if res.status_code == 200:
            size = res.headers.get('Content-Length')

            if size is not None:
                return system.get_human_size_str(size)
Example #9
0
    def get_content_length(self, url: str) -> str:
        """
        :param url:
        :return:
        """
        res = self.session.get(url, allow_redirects=True, stream=True)

        if res.status_code == 200:
            size = res.headers.get('Content-Length')

            if size is not None:
                return system.get_human_size_str(size)
Example #10
0
    def get_content_length(self, url: str, session: bool = True) -> str:
        size = self.get_content_length_in_bytes(url, session)

        if size:
            return system.get_human_size_str(size)
Example #11
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
Example #12
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
Example #13
0
    def run(self):
        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

        to_update = [
            pkg for pkg in self.pkgs if pkg.model.update
            and not pkg.model.is_update_ignored() and pkg.update_checked
        ]

        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('{}  |  {}'.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()

        # trim dialog
        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

        # backup process ( if enabled, supported and accepted )
        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 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