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
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 _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
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
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
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
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)
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
def launch(self, pkg: WebApplication): subprocess.Popen(pkg.get_command(), shell=user.is_root())
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 get_command(self) -> str: if self.installation_dir: return '{}{}'.format(self.get_exec_path(), ' --no-sandbox' if user.is_root() else '')
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