def update_file(self, pkg: AppImage, root_password: Optional[str], watcher: ProcessWatcher): max_width = 350 file_chooser = FileChooserComponent(label=self.i18n['file'].capitalize(), allowed_extensions={'AppImage', '*'}, search_path=get_default_manual_installation_file_dir(), max_width=max_width) input_version = TextInputComponent(label=self.i18n['version'].capitalize(), max_width=max_width) file_chooser.observers.append(ManualInstallationFileObserver(None, input_version)) while True: if watcher.request_confirmation(title=self.i18n['appimage.custom_action.manual_update.details'], body=None, components=[FormComponent(label='', components=[file_chooser, input_version], spaces=False)], confirmation_label=self.i18n['proceed'].capitalize(), deny_label=self.i18n['cancel'].capitalize(), min_height=100, max_width=max_width + 150): if not file_chooser.file_path or not os.path.isfile(file_chooser.file_path) or not file_chooser.file_path.lower().strip().endswith('.appimage'): watcher.request_confirmation(title=self.i18n['error'].capitalize(), body=self.i18n['appimage.custom_action.install_file.invalid_file'], deny_button=False) else: break else: return False pkg.local_file_path = file_chooser.file_path pkg.version = input_version.get_value() reqs = UpgradeRequirements(to_install=None, to_remove=None, to_upgrade=[UpgradeRequirement(pkg=pkg)], cannot_upgrade=None) return self.upgrade(reqs, root_password=root_password, watcher=watcher)
def install_file(self, root_password: Optional[str], watcher: ProcessWatcher) -> bool: max_width = 350 file_chooser = FileChooserComponent(label=self.i18n['file'].capitalize(), allowed_extensions={'AppImage', '*'}, search_path=get_default_manual_installation_file_dir(), max_width=max_width) input_name = TextInputComponent(label=self.i18n['name'].capitalize(), max_width=max_width) input_version = TextInputComponent(label=self.i18n['version'].capitalize(), max_width=max_width) file_chooser.observers.append(ManualInstallationFileObserver(input_name, input_version)) input_description = TextInputComponent(label=self.i18n['description'].capitalize(), max_width=max_width) cat_ops = [InputOption(label=self.i18n['category.none'].capitalize(), value=0)] cat_ops.extend([InputOption(label=self.i18n.get(f'category.{c.lower()}', c.lower()).capitalize(), value=c) for c in self.context.default_categories]) inp_cat = SingleSelectComponent(label=self.i18n['category'], type_=SelectViewType.COMBO, options=cat_ops, default_option=cat_ops[0], max_width=max_width) form = FormComponent(label='', components=[file_chooser, input_name, input_version, input_description, inp_cat], spaces=False) while True: if watcher.request_confirmation(title=self.i18n['appimage.custom_action.install_file.details'], body=None, components=[form], confirmation_label=self.i18n['proceed'].capitalize(), deny_label=self.i18n['cancel'].capitalize(), min_height=100, max_width=max_width + 150): if not file_chooser.file_path or not os.path.isfile(file_chooser.file_path) or not file_chooser.file_path.lower().strip().endswith('.appimage'): watcher.request_confirmation(title=self.i18n['error'].capitalize(), body=self.i18n['appimage.custom_action.install_file.invalid_file'], deny_button=False) elif not input_name.get_value() or not input_name.get_value().strip(): watcher.request_confirmation(title=self.i18n['error'].capitalize(), body=self.i18n['appimage.custom_action.install_file.invalid_name'], deny_button=False) else: break else: return False appim = AppImage(i18n=self.i18n, imported=True) appim.name = input_name.get_value().strip() appim.local_file_path = file_chooser.file_path appim.version = input_version.get_value() appim.latest_version = input_version.get_value() appim.description = input_description.get_value() appim.categories = ['Imported'] if inp_cat.get_selected() != cat_ops[0].value: appim.categories.append(inp_cat.get_selected()) res = self.install(root_password=root_password, pkg=appim, disk_loader=None, watcher=watcher).success if res: appim.installed = True self.cache_to_disk(appim, None, False) return res
def confirm_purge(self, pkg_name: str, watcher: ProcessWatcher) -> bool: msg = self._i18n['debian.action.purge.confirmation'].format( pkg=bold(pkg_name)) return watcher.request_confirmation( title=self._i18n['debian.action.purge'], body=msg, confirmation_label=self._i18n['popup.button.continue'])
def request_optional_deps(pkgname: str, pkg_mirrors: dict, watcher: ProcessWatcher, i18n: I18n) -> Set[str]: opts = [] for p, d in pkg_mirrors.items(): op = InputOption( '{}{} ( {}: {} )'.format(p, ': ' + d['desc'] if d['desc'] else '', i18n['repository'], d['mirror'].upper()), p) op.icon_path = _get_mirror_icon(d['mirror']) 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}
def request_providers(providers_map: Dict[str, Set[str]], repo_map: Dict[str, str], watcher: ProcessWatcher, i18n: I18n) -> Set[str]: msg = "<p>{}.</p><p>{}.</p>".format(i18n['arch.dialog.providers.line1'], i18n['arch.dialog.providers.line2']) repo_icon_path = get_repo_icon_path() aur_icon_path = get_icon_path() form = FormComponent([], label='') for dep, providers in providers_map.items(): opts = [] providers_list = [*providers] providers_list.sort() for p in providers_list: repo = repo_map.get(p, 'aur') opts.append(InputOption(label=p, value=p, icon_path=aur_icon_path if repo == 'aur' else repo_icon_path, tooltip='{}: {}'.format(i18n['repository'].capitalize(), repo))) form.components.append(SingleSelectComponent(label=bold(dep.lower()), options=opts, default_option=opts[0], type_=SelectViewType.COMBO, max_per_line=1)) if watcher.request_confirmation(title=i18n['arch.providers'].capitalize(), body=msg, components=[form], confirmation_label=i18n['proceed'].capitalize(), deny_label=i18n['cancel'].capitalize()): return {s.get_selected() for s in form.components}
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}
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.map_update_sizes(repo_deps) if repo_deps else {} for p, d in pkg_repos.items(): size = sizes.get(p) label = f"{p} ({i18n['repository']}: {d['repository'].lower()}) | " \ f"{i18n['size'].capitalize()}: {get_human_size_str(size) if size is not None else '?'}" op = InputOption(label=label, value=p, tooltip=d.get('desc') or None) op.icon_path = _get_repo_icon(d['repository']) opts.append(op) view_opts = MultipleSelectComponent(label='', options=opts, default_options=set(opts)) msg = f"<p>{i18n['arch.install.optdeps.request.success'].format(pkg=bold(pkgname))}</p>" \ f"<p>{i18n['arch.install.optdeps.request.body']}:</p>" install = watcher.request_confirmation(title=i18n['arch.install.optdeps.request.title'], body=msg, components=[view_opts], confirmation_label=i18n['install'].capitalize(), deny_label=i18n['do_not.install'].capitalize(), min_width=600, min_height=200) if install: return {o.value for o in view_opts.values}
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())
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 = [] sorted_deps = [*deps] sorted_deps.sort(key=lambda e: e[0]) for dep in sorted_deps: op = InputOption( '{} ( {}: {} )'.format(dep[0], i18n['repository'], dep[1].upper()), dep[0]) op.read_only = True op.icon_path = _get_mirror_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())
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
def confirm_missing_deps(deps: Collection[Tuple[str, str]], watcher: ProcessWatcher, i18n: I18n) -> bool: opts = [] total_isize, total_dsize = None, None pkgs_data = pacman.map_updates_data(pkgs=tuple(d[0] for d in deps if d[1] != 'aur'), description=True) or dict() for dep in deps: ver, desc, isize, dsize = None, None, None, None data = pkgs_data.get(dep[0]) if data: desc, isize, dsize = (data.get(f) for f in ('des', 's', 'ds')) if isize is not None: if total_isize is None: total_isize = 0 total_isize += isize if dsize is not None: if total_dsize is None: total_dsize = 0 total_dsize += dsize label = f"{dep[0]} | " \ f"{i18n['size'].capitalize()}: {get_human_size_str(isize) if isize is not None else '?'}" \ f"{' ({}: {})'.format(i18n['download'].capitalize(), get_human_size_str(dsize)) if dsize else ''}" op = InputOption(label=label, value=dep[0], tooltip=desc) op.read_only = True op.icon_path = _get_repo_icon(dep[1]) opts.append(op) comp = MultipleSelectComponent(label='', options=opts, default_options=set(opts)) body = StringIO() body.write('<p>') body.write(i18n['arch.missing_deps.body'].format(deps=bold(str(len(deps))))) if total_isize is not None or total_dsize is not None: body.write(' (') if total_isize is not None: body.write(f"{i18n['size'].capitalize()}: {bold(get_human_size_str(total_isize))} | ") if total_dsize is not None: body.write(f"{i18n['download'].capitalize()}: {bold(get_human_size_str(total_dsize))}") body.write(')') body.write(':</p>') return watcher.request_confirmation(title=i18n['arch.missing_deps.title'], body=body.getvalue(), components=[comp], confirmation_label=i18n['continue'].capitalize(), deny_label=i18n['cancel'].capitalize(), min_width=625)
def install(self, pkg: SnapApplication, root_password: str, watcher: ProcessWatcher) -> bool: res, output = ProcessHandler(watcher).handle_simple( snap.install_and_stream(pkg.name, pkg.confinement, root_password)) if 'error:' in output: res = False if 'not available on stable' in output: channels = RE_AVAILABLE_CHANNELS.findall(output) if channels: opts = [ InputOption(label=c[0], value=c[1]) for c in channels ] channel_select = SingleSelectComponent( type_=SelectViewType.RADIO, label='', options=opts, default_option=opts[0]) body = '<p>{}.</p>'.format( self.i18n['snap.install.available_channels.message']. format(bold(self.i18n['stable']), bold(pkg.name))) body += '<p>{}:</p>'.format( self.i18n['snap.install.available_channels.help']) if watcher.request_confirmation( title=self. i18n['snap.install.available_channels.title'], body=body, components=[channel_select], confirmation_label=self.i18n['continue'], deny_label=self.i18n['cancel']): self.logger.info( "Installing '{}' with the custom command '{}'". format(pkg.name, channel_select.value)) res = ProcessHandler(watcher).handle( SystemProcess( new_root_subprocess( channel_select.value.value.split(' '), root_password=root_password))) if res: pkg.has_apps_field = snap.has_apps_field( pkg.name, self.ubuntu_distro) return res else: self.logger.error( "Could not find available channels in the installation output: {}" .format(output)) else: pkg.has_apps_field = snap.has_apps_field(pkg.name, self.ubuntu_distro) return res
def request_install_missing_deps(pkgname: str, pkg_mirrors: dict, watcher: ProcessWatcher, i18n: dict) -> bool: deps_str = ''.join([ '<br/><span style="font-weight:bold"> - {} ( {} )</span>'.format( d, m.upper()) for d, m in pkg_mirrors.items() ]) msg = '<p>{}</p>'.format( i18n['arch.missing_deps.body'].format(bold(pkgname)) + ':<br/>' + deps_str) msg += i18n['ask.continue'] return watcher.request_confirmation(i18n['arch.missing_deps.title'], msg)
def update_file(self, pkg: AppImage, root_password: str, watcher: ProcessWatcher): file_chooser = FileChooserComponent( label=self.i18n['file'].capitalize(), allowed_extensions={'AppImage'}) input_version = TextInputComponent( label=self.i18n['version'].capitalize()) while True: if watcher.request_confirmation( title=self. i18n['appimage.custom_action.manual_update.details'], body=None, components=[ FormComponent(label='', components=[file_chooser, input_version], spaces=False) ], confirmation_label=self.i18n['proceed'].capitalize(), deny_label=self.i18n['cancel'].capitalize()): if not file_chooser.file_path or not os.path.isfile( file_chooser.file_path): watcher.request_confirmation( title=self.i18n['error'].capitalize(), body=self.i18n[ 'appimage.custom_action.install_file.invalid_file'], deny_button=False) else: break else: return False pkg.local_file_path = file_chooser.file_path pkg.version = input_version.get_value() reqs = UpgradeRequirements(to_install=None, to_remove=None, to_upgrade=[UpgradeRequirement(pkg=pkg)], cannot_upgrade=None) return self.upgrade(reqs, root_password=root_password, watcher=watcher)
def confirm_transaction(self, to_install: Optional[Collection[DebianPackage]], removal: Optional[Collection[DebianPackage]], watcher: ProcessWatcher) -> bool: components = [] to_remove_data = self._map_to_remove(removal) text_width, select_width = 672, 595 if to_remove_data: to_remove_data[0].sort(key=attrgetter('label')) lb_rem = self._i18n['debian.transaction.to_remove'].format( no=bold(str(len(to_remove_data[0]))), fspace=bold(to_remove_data[1])) components.append(TextComponent(html=lb_rem, min_width=text_width)) components.append( MultipleSelectComponent(id_='rem', options=to_remove_data[0], label=None, default_options={*to_remove_data[0]}, max_width=select_width)) to_install_data = self._map_to_install(to_install) if to_install_data: to_install_data[0].sort(key=attrgetter('label')) lb_deps = self._i18n['debian.transaction.to_install'].format( no=bold(str(len(to_install_data[0]))), dsize=bold(to_install_data[2]), isize=bold(to_install_data[1])) components.append( TextComponent(html=f'<br/>{lb_deps}', min_width=text_width)) components.append( MultipleSelectComponent(id_='inst', label='', options=to_install_data[0], default_options={*to_install_data[0]}, max_width=select_width)) return watcher.request_confirmation( title=self._i18n['debian.transaction.title'], components=components, confirmation_label=self._i18n['popup.button.continue'], deny_label=self._i18n['popup.button.cancel'], body=None, min_width=text_width, min_height=54)
def reset(self, root_password: str, watcher: ProcessWatcher) -> bool: body = '<p>{}</p><p>{}</p>'.format(self.i18n['action.reset.body_1'].format(bold(self.context.app_name)), self.i18n['action.reset.body_2']) if watcher.request_confirmation(title=self.i18n['action.reset'], body=body, confirmation_label=self.i18n['proceed'].capitalize(), deny_label=self.i18n['cancel'].capitalize()): try: clean_app_files(managers=self.managers, logs=False) restart_app() except: return False return True
def confirm_removal(self, source_pkg: str, dependencies: Collection[DebianPackage], watcher: ProcessWatcher) -> bool: dep_views = [] freed_space = 0 for p in sorted(dependencies, key=attrgetter('name')): if p.transaction_size is not None: size = p.transaction_size * (-1 if p.transaction_size < 0 else 1) freed_space += size size_str = get_human_size_str(size) else: size_str = '?' dep_views.append( InputOption(label=f"{p.name}: -{size_str}", value=p.name, read_only=True, icon_path=DEBIAN_ICON_PATH, tooltip=p.description)) deps_container = MultipleSelectComponent(id_='deps', label='', options=dep_views, default_options={*dep_views}, max_width=537) freed_space_str = bold('-' + get_human_size_str(freed_space)) body_text = TextComponent(html=self._i18n['debian.remove_deps'].format( no=bold(str(len(dependencies))), pkg=bold(source_pkg), fspace=freed_space_str), min_width=653) return watcher.request_confirmation( title=self._i18n['debian.transaction.title'], components=[body_text, deps_container], confirmation_label=self._i18n['popup.button.continue'], deny_label=self._i18n['popup.button.cancel'], min_height=200, body=None)
def _ask_update_permission(self, to_update: List[EnvironmentComponent], watcher: ProcessWatcher) -> bool: icon = resource.get_path('img/web.png', ROOT_DIR) opts = [ InputOption(label='{} ( {} )'.format(f.name, f.size or '?'), tooltip=f.url, icon_path=icon, read_only=True, value=f.name) for f in to_update ] comps = MultipleSelectComponent(label=None, options=opts, default_options=set(opts)) return watcher.request_confirmation( title=self.i18n['web.install.env_update.title'], body=self.i18n['web.install.env_update.body'], components=[comps], confirmation_label=self.i18n['continue'].capitalize(), deny_label=self.i18n['cancel'].capitalize())
def request_optional_deps(pkgname: str, pkg_mirrors: dict, watcher: ProcessWatcher, i18n: dict) -> Set[str]: opts = [ InputOption( '{}{} ( {} )'.format(p, ': ' + d['desc'] if d['desc'] else '', d['mirror'].upper()), p) for p, d in pkg_mirrors.items() ] view_opts = MultipleSelectComponent(label='', options=opts, default_options=None) install = watcher.request_confirmation( title=i18n['arch.install.optdeps.request.title'], body='<p>{}</p>'.format( i18n['arch.install.optdeps.request.body'].format(bold(pkgname)) + ':'), components=[view_opts], confirmation_label=i18n['install'], deny_label=i18n['cancel']) if install: return {o.value for o in view_opts.values}
def install_file(self, root_password: str, watcher: ProcessWatcher) -> bool: file_chooser = FileChooserComponent( label=self.i18n['file'].capitalize(), allowed_extensions={'AppImage'}) input_name = TextInputComponent(label=self.i18n['name'].capitalize()) input_version = TextInputComponent( label=self.i18n['version'].capitalize()) input_description = TextInputComponent( label=self.i18n['description'].capitalize()) cat_ops = [ InputOption(label=self.i18n['category.none'].capitalize(), value=0) ] cat_ops.extend([ InputOption(label=self.i18n[c.lower()].capitalize(), value=c) for c in self.context.default_categories ]) inp_cat = SingleSelectComponent(label=self.i18n['category'], type_=SelectViewType.COMBO, options=cat_ops, default_option=cat_ops[0]) form = FormComponent(label='', components=[ file_chooser, input_name, input_version, input_description, inp_cat ], spaces=False) while True: if watcher.request_confirmation( title=self. i18n['appimage.custom_action.install_file.details'], body=None, components=[form], confirmation_label=self.i18n['proceed'].capitalize(), deny_label=self.i18n['cancel'].capitalize()): if not file_chooser.file_path or not os.path.isfile( file_chooser.file_path): watcher.request_confirmation( title=self.i18n['error'].capitalize(), body=self.i18n[ 'appimage.custom_action.install_file.invalid_file'], deny_button=False) elif not input_name.get_value() or not input_name.get_value( ).strip(): watcher.request_confirmation( title=self.i18n['error'].capitalize(), body=self.i18n[ 'appimage.custom_action.install_file.invalid_name'], deny_button=False) else: break else: return False appim = AppImage(i18n=self.i18n, imported=True, custom_actions=self.custom_app_actions) appim.name = input_name.get_value().strip() appim.local_file_path = file_chooser.file_path appim.version = input_version.get_value() appim.latest_version = input_version.get_value() appim.description = input_description.get_value() appim.categories = ['Imported'] if inp_cat.get_selected() != cat_ops[0].value: appim.categories.append(inp_cat.get_selected()) installed = self.install(root_password=root_password, pkg=appim, watcher=watcher) if installed: appim.installed = True self.cache_to_disk(appim, None, False) return installed
def install(self, pkg: SnapApplication, root_password: str, disk_loader: DiskCacheLoader, watcher: ProcessWatcher) -> TransactionResult: # retrieving all installed so it will be possible to know the additional installed runtimes after the operation succeeds if not snap.is_installed(): watcher.print("'snap' seems not to be installed") return TransactionResult.fail() if not snapd.is_running(): watcher.print("'snapd' seems not to be running") return TransactionResult.fail() installed_names = { s['name'] for s in SnapdClient(self.logger).list_all_snaps() } client = SnapdClient(self.logger) snap_config = read_config() try: channel = self._request_channel_installation( pkg=pkg, snap_config=snap_config, snapd_client=client, watcher=watcher) pkg.channel = channel except: watcher.print('Aborted by user') return TransactionResult.fail() res, output = ProcessHandler(watcher).handle_simple( snap.install_and_stream(app_name=pkg.name, confinement=pkg.confinement, root_password=root_password, channel=channel)) if 'error:' in output: res = False if 'not available on stable' in output: channels = RE_AVAILABLE_CHANNELS.findall(output) if channels: opts = [ InputOption(label=c[0], value=c[1]) for c in channels ] channel_select = SingleSelectComponent( type_=SelectViewType.RADIO, label='', options=opts, default_option=opts[0]) body = '<p>{}.</p>'.format( self.i18n['snap.install.available_channels.message']. format(bold(self.i18n['stable']), bold(pkg.name))) body += '<p>{}:</p>'.format( self.i18n['snap.install.available_channels.help']) if watcher.request_confirmation( title=self. i18n['snap.install.available_channels.title'], body=body, components=[channel_select], confirmation_label=self.i18n['continue'], deny_label=self.i18n['cancel']): self.logger.info( "Installing '{}' with the custom command '{}'". format(pkg.name, channel_select.value)) res = ProcessHandler(watcher).handle( SystemProcess( new_root_subprocess( channel_select.value.value.split(' '), root_password=root_password))) return self._gen_installation_response( success=res, pkg=pkg, installed=installed_names, disk_loader=disk_loader) else: self.logger.error( "Could not find available channels in the installation output: {}" .format(output)) return self._gen_installation_response(success=res, pkg=pkg, installed=installed_names, disk_loader=disk_loader)
def _ask_install_options( self, app: WebApplication, watcher: ProcessWatcher) -> Tuple[bool, List[str]]: watcher.change_substatus(self.i18n['web.install.substatus.options']) inp_url = TextInputComponent(label=self.i18n['address'], value=app.url, read_only=True) inp_name = TextInputComponent(label=self.i18n['name'], value=app.name) inp_desc = TextInputComponent(label=self.i18n['description'], value=app.description) cat_ops = [ InputOption(label=self.i18n['web.install.option.category.none']. capitalize(), value=0) ] cat_ops.extend([ InputOption(label=self.i18n[c.lower()].capitalize(), value=c) for c in self.context.default_categories ]) def_cat = cat_ops[0] if app.categories: for opt in cat_ops: if opt.value == app.categories[0]: def_cat = opt break inp_cat = SingleSelectComponent(label=self.i18n['category'], type_=SelectViewType.COMBO, options=cat_ops, default_option=def_cat) tray_op_off = InputOption( id_='tray_off', label=self.i18n['web.install.option.tray.off.label'], value=0, tooltip=self.i18n['web.install.option.tray.off.tip']) tray_op_default = InputOption( id_='tray_def', label=self.i18n['web.install.option.tray.default.label'], value='--tray', tooltip=self.i18n['web.install.option.tray.default.tip']) tray_op_min = InputOption( id_='tray_min', label=self.i18n['web.install.option.tray.min.label'], value='--tray=start-in-tray', tooltip=self.i18n['web.install.option.tray.min.tip']) tray_opts = [tray_op_off, tray_op_default, tray_op_min] def_tray_opt = None if app.preset_options: for opt in tray_opts: if opt.id in app.preset_options: def_tray_opt = opt break inp_tray = SingleSelectComponent( type_=SelectViewType.COMBO, options=tray_opts, default_option=def_tray_opt, label=self.i18n['web.install.option.tray.label']) icon_op_ded = InputOption( id_='icon_ded', label=self.i18n['web.install.option.wicon.deducted.label'], value=0, tooltip=self.i18n['web.install.option.wicon.deducted.tip'].format( 'Nativefier')) icon_op_disp = InputOption( id_='icon_disp', label=self.i18n['web.install.option.wicon.displayed.label'], value=1, tooltip=self.i18n['web.install.option.wicon.displayed.tip']) inp_icon = SingleSelectComponent( type_=SelectViewType.COMBO, options=[icon_op_disp, icon_op_ded], default_option=icon_op_disp if app.icon_url and app.save_icon else icon_op_ded, label=self.i18n['web.install.option.wicon.label']) icon_chooser = FileChooserComponent( allowed_extensions={'png', 'svg', 'ico', 'jpg', 'jpeg'}, label=self.i18n['web.install.option.icon.label']) form_1 = FormComponent( components=[ inp_url, inp_name, inp_desc, inp_cat, inp_icon, icon_chooser, inp_tray ], label=self.i18n['web.install.options.basic'].capitalize()) op_single = InputOption( id_='single', label=self.i18n['web.install.option.single.label'], value="--single-instance", tooltip=self.i18n['web.install.option.single.tip']) op_max = InputOption(id_='max', label=self.i18n['web.install.option.max.label'], value="--maximize", tooltip=self.i18n['web.install.option.max.tip']) op_fs = InputOption( id_='fullscreen', label=self.i18n['web.install.option.fullscreen.label'], value="--full-screen", tooltip=self.i18n['web.install.option.fullscreen.tip']) op_nframe = InputOption( id_='no_frame', label=self.i18n['web.install.option.noframe.label'], value="--hide-window-frame", tooltip=self.i18n['web.install.option.noframe.tip']) op_allow_urls = InputOption( id_='allow_urls', label=self.i18n['web.install.option.allow_urls.label'], value='--internal-urls=.*', tooltip=self.i18n['web.install.option.allow_urls.tip']) op_ncache = InputOption( id_='no_cache', label=self.i18n['web.install.option.nocache.label'], value="--clear-cache", tooltip=self.i18n['web.install.option.nocache.tip']) op_insecure = InputOption( id_='insecure', label=self.i18n['web.install.option.insecure.label'], value="--insecure", tooltip=self.i18n['web.install.option.insecure.tip']) op_igcert = InputOption( id_='ignore_certs', label=self.i18n['web.install.option.ignore_certificate.label'], value="--ignore-certificate", tooltip=self.i18n['web.install.option.ignore_certificate.tip']) adv_opts = [ op_single, op_allow_urls, op_max, op_fs, op_nframe, op_ncache, op_insecure, op_igcert ] def_adv_opts = {op_single, op_allow_urls} if app.preset_options: for opt in adv_opts: if opt.id in app.preset_options: def_adv_opts.add(opt) check_options = MultipleSelectComponent( options=adv_opts, default_options=def_adv_opts, label=self.i18n['web.install.options.advanced'].capitalize()) res = watcher.request_confirmation( title=self.i18n['web.install.options_dialog.title'], body=None, components=[form_1, check_options], confirmation_label=self.i18n['continue'].capitalize(), deny_label=self.i18n['cancel'].capitalize()) if res: selected = [] if check_options.values: selected.extend(check_options.get_selected_values()) tray_mode = inp_tray.get_selected() if tray_mode is not None and tray_mode != 0: selected.append(tray_mode) custom_name = inp_name.get_value() if custom_name: app.name = custom_name custom_desc = inp_desc.get_value() if custom_desc: app.description = inp_desc.get_value() cat = inp_cat.get_selected() if cat != 0: app.categories = [cat] if icon_chooser.file_path: app.set_custom_icon(icon_chooser.file_path) selected.append('--icon={}'.format(icon_chooser.file_path)) app.save_icon = inp_icon.value == icon_op_disp return res, selected return False, []
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()
def _request_channel_installation( self, pkg: SnapApplication, snap_config: Optional[dict], snapd_client: SnapdClient, watcher: ProcessWatcher, exclude_current: bool = False) -> Optional[str]: if snap_config is None or snap_config['install_channel']: try: data = [ r for r in snapd_client.find_by_name(pkg.name) if r['name'] == pkg.name ] except: self.logger.warning( "snapd client could not retrieve channels for '{}'".format( pkg.name)) return if not data: self.logger.warning( "snapd client could find a match for name '{}' when retrieving its channels" .format(pkg.name)) else: if not data[0].get('channels'): self.logger.info( "No channel available for '{}'. Skipping selection.". format(pkg.name)) else: if pkg.channel: current_channel = pkg.channel if '/' in pkg.channel else 'latest/{}'.format( pkg.channel) else: current_channel = 'latest/{}'.format(data[0].get( 'channel', 'stable')) opts = [] def_opt = None for channel in sorted(data[0]['channels'].keys()): if exclude_current: if channel != current_channel: opts.append( InputOption(label=channel, value=channel)) else: op = InputOption(label=channel, value=channel) opts.append(op) if not def_opt and channel == current_channel: def_opt = op if not opts: self.logger.info( "No different channel available for '{}'. Skipping selection." .format(pkg.name)) return select = SingleSelectComponent( label='', options=opts, default_option=def_opt if def_opt else opts[0], type_=SelectViewType.RADIO) if not watcher.request_confirmation( title=self. i18n['snap.install.available_channels.title'], body=self.i18n['snap.install.channel.body'] + ':', components=[select], confirmation_label=self.i18n['proceed'].capitalize( ), deny_label=self.i18n['cancel'].capitalize()): raise Exception('aborted') else: return select.get_selected()
def install(self, pkg: SnapApplication, root_password: str, disk_loader: DiskCacheLoader, watcher: ProcessWatcher) -> TransactionResult: info_path = self.get_info_path() if not info_path: self.logger.warning( 'Information directory was not found. It will not be possible to determine if the installed application can be launched' ) # retrieving all installed so it will be possible to know the additional installed runtimes after the operation succeeds installed_names = snap.list_installed_names() res, output = ProcessHandler(watcher).handle_simple( snap.install_and_stream(pkg.name, pkg.confinement, root_password)) if 'error:' in output: res = False if 'not available on stable' in output: channels = RE_AVAILABLE_CHANNELS.findall(output) if channels: opts = [ InputOption(label=c[0], value=c[1]) for c in channels ] channel_select = SingleSelectComponent( type_=SelectViewType.RADIO, label='', options=opts, default_option=opts[0]) body = '<p>{}.</p>'.format( self.i18n['snap.install.available_channels.message']. format(bold(self.i18n['stable']), bold(pkg.name))) body += '<p>{}:</p>'.format( self.i18n['snap.install.available_channels.help']) if watcher.request_confirmation( title=self. i18n['snap.install.available_channels.title'], body=body, components=[channel_select], confirmation_label=self.i18n['continue'], deny_label=self.i18n['cancel']): self.logger.info( "Installing '{}' with the custom command '{}'". format(pkg.name, channel_select.value)) res = ProcessHandler(watcher).handle( SystemProcess( new_root_subprocess( channel_select.value.value.split(' '), root_password=root_password))) if res and info_path: pkg.has_apps_field = snap.has_apps_field( pkg.name, info_path) return self._gen_installation_response( success=res, pkg=pkg, installed=installed_names, disk_loader=disk_loader) else: self.logger.error( "Could not find available channels in the installation output: {}" .format(output)) else: if info_path: pkg.has_apps_field = snap.has_apps_field(pkg.name, info_path) return self._gen_installation_response(success=res, pkg=pkg, installed=installed_names, disk_loader=disk_loader)