def _vacuum(self, entropy_client, inst_repo): """ Solo Smart Vacuum command. """ entropy_client.output( "%s..." % ( brown(_("Compacting the Installed Packages repository")), ), importance=1, level="info", header=darkgreen(" @@ "), back=True ) inst_repo.dropAllIndexes() inst_repo.vacuum() inst_repo.commit() entropy_client.output( "%s." % ( brown(_("Compaction complete")), ), importance=1, level="info", header=darkgreen(" @@ ") ) return 0
def _edit_file(self, idx, entropy_client, root, source, dest, paths_map, scandata): """ Edit the given source file. """ source_path = root + source dest_path = root + dest entropy_client.output("%s: %s" % ( darkred(_("Editing file")), darkgreen(source_path), )) entropy_client.edit_file(source_path) entropy_client.output( "%s: %s, %s" % (darkred(_("Edited file")), darkgreen(source_path), darkred(_("showing difference")))) diff = self._showdiff(entropy_client, dest_path, source_path) if not diff: entropy_client.output("%s: %s" % ( darkred(_("Automerging")), teal(source_path), )) scandata.merge(source) del paths_map[idx] return True, False return False, True
def _show_notice(self, entropy_client, key, mydict): """ Show Notice Board element. """ mytxt = "[%s] [%s] %s: %s" % ( blue(str(key)), brown(mydict['pubDate']), _("Title"), darkred(mydict['title']), ) entropy_client.output(mytxt) mytxt = "%s:\n\n%s\n" % ( darkgreen(_("Content")), mydict['description'], ) entropy_client.output(mytxt) mytxt = "%s: %s" % ( darkgreen(_("Link")), blue(mydict['link']), ) entropy_client.output(mytxt) def fake_callback(s): return True input_params = [('idx', _("Press Enter to continue"), fake_callback, False)] entropy_client.input_box('', input_params, cancel_button=True)
def _show_notice(self, entropy_server, key, mydict): """ Print notice board entry content """ mytxt = "[%s] [%s]" % ( blue(str(key)), brown(mydict['pubDate']), ) entropy_server.output(mytxt) entropy_server.output("", level="generic") entropy_server.output("%s: %s" % (darkgreen(_("Title")), purple(mydict['title'])), level="generic") entropy_server.output("", level="generic") entropy_server.output(mydict['description'], level="generic") entropy_server.output("", level="generic") mytxt = "%s: %s" % ( darkgreen(_("URL")), blue(mydict['link']), ) entropy_server.output(mytxt) def fake_callback(dummy_s): return True input_params = [('idx', _('Press Enter to continue'), fake_callback, False)] data = entropy_server.input_box('', input_params, cancel_button=True)
def _wait_resource(self, shared): """ Try to acquire the resource, on failure, print a warning and block until acquired. """ if shared: acquired = self.try_acquire_shared() else: acquired = self.try_acquire_exclusive() if acquired: return True if shared: msg = "%s %s ..." % ( blue(_("Acquiring shared lock on")), darkgreen(self.path()), ) else: msg = "%s %s ..." % ( blue(_("Acquiring exclusive lock on")), darkgreen(self.path()), ) self._out.output(msg, importance=0, back=True, level="warning") if shared: self.acquire_shared() else: self.acquire_exclusive() return True
def _show_package_dependencies(self, entropy_server, atom, orig_deps, partial = False): """ Print package dependencies for atom. """ if not partial: entropy_server.output( "%s, %s" % ( blue(atom), darkgreen(_("package dependencies"))), header=brown(" @@ ")) else: entropy_server.output("") for dep_str, dep_id in orig_deps: entropy_server.output( "[%s: %s] %s" % ( brown(_("type")), darkgreen(str(dep_id+1)), purple(dep_str)), header=brown(" #")) if not orig_deps: entropy_server.output( _("No dependencies"), header=brown(" # ")) else: self._show_dependencies_legend(entropy_server, " ") if partial: entropy_server.output("")
def _show_notice(self, entropy_client, key, mydict): """ Show Notice Board element. """ mytxt = "[%s] [%s] %s: %s" % ( blue(str(key)), brown(mydict['pubDate']), _("Title"), darkred(mydict['title']), ) entropy_client.output(mytxt) mytxt = "%s:\n\n%s\n" % ( darkgreen(_("Content")), mydict['description'], ) entropy_client.output(mytxt) mytxt = "%s: %s" % ( darkgreen(_("Link")), blue(mydict['link']), ) entropy_client.output(mytxt) def fake_callback(s): return True input_params = [ ('idx', _("Press Enter to continue"), fake_callback, False)] entropy_client.input_box('', input_params, cancel_button = True)
def __export_key(self, entropy_server, repo_sec, is_pubkey, repo, store_path): """ Internal key export logic. """ key_msg = _("Exporting private key for repository") func_check = repo_sec.is_privkey_available if is_pubkey: func_check = repo_sec.is_pubkey_available key_msg = _("Exporting public key for repository") try: if not func_check(repo): entropy_server.output("%s: %s" % ( blue(_("No keypair available for repository")), purple(repo), ), level = "error" ) return 1 except repo_sec.KeyExpired: entropy_server.output("%s: %s" % ( darkred(_("Keypair is EXPIRED for repository")), purple(repo), ), level = "error" ) return 1 entropy_server.output("%s: %s" % (blue(key_msg), purple(repo),)) if is_pubkey: key_stream = repo_sec.get_pubkey(repo) else: key_stream = repo_sec.get_privkey(repo) # write to file try: with open(store_path, "w") as dest_w: dest_w.write(key_stream) dest_w.flush() except IOError as err: entropy_server.output("%s: %s [%s]" % ( darkgreen( _("Unable to export GPG key for repository")), bold(repo), err, ), level = "error" ) return 1 entropy_server.output("%s: %s [%s]" % ( darkgreen(_("Exported GPG key for repository")), bold(repo), brown(store_path), ), level = "info" ) return 0
def _show_notice(self, entropy_server, key, mydict): """ Print notice board entry content """ mytxt = "[%s] [%s]" % ( blue(str(key)), brown(mydict['pubDate']), ) entropy_server.output(mytxt) entropy_server.output("", level="generic") entropy_server.output( "%s: %s" % (darkgreen(_("Title")), purple(mydict['title'])), level="generic") entropy_server.output("", level="generic") entropy_server.output(mydict['description'], level="generic") entropy_server.output("", level="generic") mytxt = "%s: %s" % ( darkgreen(_("URL")), blue(mydict['link']), ) entropy_server.output(mytxt) def fake_callback(dummy_s): return True input_params = [ ('idx', _('Press Enter to continue'), fake_callback, False) ] data = entropy_server.input_box( '', input_params, cancel_button = True)
def _edit_file(self, idx, entropy_client, root, source, dest, paths_map, scandata): """ Edit the given source file. """ source_path = root + source dest_path = root + dest entropy_client.output( "%s: %s" % ( darkred(_("Editing file")), darkgreen(source_path),)) entropy_client.edit_file(source_path) entropy_client.output( "%s: %s, %s" % ( darkred(_("Edited file")), darkgreen(source_path), darkred(_("showing difference"))) ) diff = self._showdiff( entropy_client, dest_path, source_path) if not diff: entropy_client.output( "%s: %s" % ( darkred(_("Automerging")), teal(source_path),) ) scandata.merge(source) del paths_map[idx] return True, False return False, True
def _wait_resource(self, shared): """ Try to acquire the resource, on failure, print a warning and block until acquired. """ if shared: acquired = self.try_acquire_shared() else: acquired = self.try_acquire_exclusive() if acquired: return True if shared: msg = "%s %s ..." % ( blue(_("Acquiring shared lock on")), darkgreen(self.path()),) else: msg = "%s %s ..." % ( blue(_("Acquiring exclusive lock on")), darkgreen(self.path()),) self._out.output( msg, importance=0, back=True, level="warning" ) if shared: self.acquire_shared() else: self.acquire_exclusive() return True
def _show_config_files_update(self, entropy_client): """ Inform User about configuration file updates, if any. """ entropy_client.output( blue(_("Scanning configuration files to update")), header=darkgreen(" @@ "), back=True) updates = entropy_client.ConfigurationUpdates() scandata = updates.get() if not scandata: entropy_client.output( blue(_("No configuration files to update.")), header=darkgreen(" @@ ")) return mytxt = ngettext( "There is %s configuration file needing update", "There are %s configuration files needing update", len(scandata)) % (len(scandata),) entropy_client.output( darkgreen(mytxt), level="warning") mytxt = "%s: %s" % ( purple(_("Please run")), bold("equo conf update")) entropy_client.output( darkgreen(mytxt), level="warning")
def _description(self, entropy_client, inst_repo): """ Solo Query Description command. """ quiet = self._nsargs.quiet verbose = self._nsargs.verbose descriptions = self._nsargs.descriptions settings = entropy_client.Settings() found = False if not quiet: entropy_client.output(darkgreen(_("Description Search")), header=darkred(" @@ ")) repo_number = 0 for repo_id in entropy_client.repositories(): repo_number += 1 repo_data = settings["repositories"]["available"][repo_id] if not quiet: header = ( const_convert_to_unicode(" #") + const_convert_to_unicode(repo_number) + const_convert_to_unicode(" ") ) entropy_client.output("%s" % (bold(repo_data["description"]),), header=blue(header)) repo = entropy_client.open_repository(repo_id) found = self._search_descriptions(descriptions, entropy_client, repo, quiet, verbose) if not quiet and not found: entropy_client.output(darkgreen("%s." % (_("No matches"),)), header=darkred(" @@ ")) return 0
def _call_locked(self, func): """ Execute the given function at func after acquiring Entropy Resources Lock, for given repository at repo. The signature of func is: int func(entropy_client). """ client = None acquired = False try: try: client = self._entropy() except PermissionDenied as err: print_error(err.value) return 1 blocking = os.getenv("__EQUO_LOCKS_BLOCKING__") if blocking: client.output(darkgreen( _("Acquiring Entropy Resources " "Lock, please wait...")), back=True) acquired = entropy.tools.acquire_entropy_locks( client, blocking=blocking, spinner=True) if not acquired: client.output( darkgreen(_("Another Entropy is currently running.")), level="error", importance=1 ) return 1 return func(client) finally: if client is not None: client.shutdown() if acquired: entropy.tools.release_entropy_locks(client)
def _garbage_collect_preserved_libs(self, preserved_mgr): """ Garbage collect (and remove) libraries preserved on the system no longer available or no longer needed by any installed package. """ preserved_libs = preserved_mgr.collect() inst_repo = preserved_mgr.installed_repository() for library, elfclass, path in preserved_libs: self._entropy.output( "%s: %s [%s, %s]" % ( brown(_("Removing library")), darkgreen(path), purple(library), teal(const_convert_to_unicode("%s" % (elfclass,))), ), importance = 0, level = "warning", header = darkgreen(" :: ") ) self._entropy.logger.log( "[Package]", etpConst['logging']['normal_loglevel_id'], "%s %s [%s:%s]" % ( const_convert_to_unicode("Removing library"), path, library, elfclass,) ) # This will also check if path and it's destinations (in case of # symlink) is owned by other packages. # If this is the case, removal will fail for that specific path. # This may be the case for packages like vmware-workstation, # containing symlinks pointing to system libraries. # See Sabayon bug #5182. remove_failed = preserved_mgr.remove(path) for failed_path, err in remove_failed: self._entropy.output( "%s: %s, %s" % ( purple(_("Failed to remove the library")), darkred(failed_path), err, ), importance = 1, level = "warning", header = brown(" ## ") ) self._entropy.logger.log( "[Package]", etpConst['logging']['normal_loglevel_id'], "Error during %s removal: %s" % (failed_path, err) ) preserved_mgr.unregister(library, elfclass, path) # commit changes to repository if collected if preserved_libs: inst_repo.commit()
def _status(self, entropy_server): """ Actual Eit lock|unlock --status code. Just show repo status. """ repositories = entropy_server.repositories() if self._repository_id not in repositories: entropy_server.output( "%s: %s" % ( _("Invalid Repository"), self._repository_id), level="error", importance=1) return 1 if not self._quiet: entropy_server.output( "%s:" % (darkgreen(_("Mirrors status")),), header=brown(" * ")) dbstatus = entropy_server.Mirrors.mirrors_status( self._repository_id) for uri, server_lock, client_lock in dbstatus: host = EntropyTransceiver.get_uri_name(uri) if not self._quiet: entropy_server.output( "[%s]" % (purple(host),), header=darkgreen(" @@ ")) if server_lock: lock_str = darkred(_("Locked")) quiet_lock_str = "locked" else: lock_str = darkgreen(_("Unlocked")) quiet_lock_str = "unlocked" if self._quiet: entropy_server.output( "%s server %s" % (host, quiet_lock_str), level="generic") else: entropy_server.output( "%s: %s" % (blue(_("server")), lock_str), header=brown(" # ")) if client_lock: lock_str = darkred(_("Locked")) quiet_lock_str = "locked" else: lock_str = darkgreen(_("Unlocked")) quiet_lock_str = "unlocked" if self._quiet: entropy_server.output( "%s client %s" % (host, quiet_lock_str), level="generic") else: entropy_server.output( "%s: %s" % (blue(_("client")), lock_str), header=brown(" # ")) return 0
def _add(self, entropy_server): """ Eit Repo Add command. """ current_repos = entropy_server.repositories() repository_id = self._nsargs.id desc = self._nsargs.desc repos = self._nsargs.repo pkg_only = self._nsargs.pkg_only repo_only = self._nsargs.repo_only base = self._nsargs.base if repository_id in current_repos: entropy_server.output("[%s] %s" % ( purple(repository_id), blue(_("repository already configured")), ), level="error", importance=1) return 1 toc = [] toc.append((purple(_("Repository id:")), teal(repository_id))) toc.append((darkgreen(_("Description:")), teal(desc))) base_str = _("Yes") if base is None: base_str = _("Unset") elif not base: base_str = _("No") toc.append((darkgreen(_("Base repository:")), teal(base_str))) for uri in repos: toc.append((purple(_("Packages + Database URI:")), uri)) for uri in repo_only: toc.append((purple(_("Database only URI:")), uri)) for uri in pkg_only: toc.append((purple(_("Packages only URI:")), uri)) toc.append(" ") print_table(entropy_server, toc) parser = RepositoryConfigParser() added = parser.add(repository_id, desc, repos, repo_only, pkg_only, base) if added: entropy_server.output("[%s] %s" % ( purple(repository_id), blue(_("repository added succesfully")), )) else: entropy_server.output("[%s] %s" % ( purple(repository_id), blue(_("cannot add repository")), ), level="warning", importance=1) return 0
def _add(self, entropy_client): """ Solo Repo Add command. """ settings = entropy_client.Settings() current_branch = settings['repositories']['branch'] current_product = settings['repositories']['product'] available_repos = settings['repositories']['available'] repository_id = self._nsargs.id repos = self._nsargs.repo pkgs = self._nsargs.pkg desc = self._nsargs.desc cformat = self._nsargs.cformat # show info toc = [] toc.append((purple(_("Repository id:")), teal(repository_id))) toc.append((darkgreen(_("Description:")), teal(desc))) toc.append((purple(_("Repository format:")), darkgreen(cformat))) for pkg_url in pkgs: toc.append((purple(_("Packages URL:")), pkg_url)) for repo_url in repos: toc.append((purple(_("Repository URL:")), repo_url)) toc.append(" ") print_table(entropy_client, toc) try: repodata = settings._generate_repository_metadata( repository_id, desc, pkgs, repos, current_product, current_branch) except AttributeError as err: entropy_client.output("[%s] %s" % ( purple(repository_id), err, ), level="error", importance=1) return 1 added = entropy_client.add_repository(repodata) if added: entropy_client.output("[%s] %s" % ( purple(repository_id), blue(_("repository added succesfully")), )) else: entropy_client.output("[%s] %s" % ( purple(repository_id), blue(_("cannot add repository")), ), level="warning", importance=1) return 0
def _showdiff(self, entropy_client, fromfile, tofile): args = ["diff", "-Nu", "'"+fromfile+"'", "'"+tofile+"'"] output = getoutput(' '.join(args)).split("\n") coloured = [] for line in output: if line.startswith("---"): line = darkred(line) elif line.startswith("+++"): line = darkgreen(line) elif line.startswith("@@"): line = brown(line) elif line.startswith("-"): line = blue(line) elif line.startswith("+"): line = darkgreen(line) coloured.append(line + "\n") fd, tmp_path = None, None try: fd, tmp_path = const_mkstemp( suffix="equo.conf.showdiff") with os.fdopen(fd, "w") as f: f.writelines(coloured) f.flush() finally: if fd is not None: try: os.close(fd) except OSError: pass print("") pager = os.getenv("PAGER", "/usr/bin/less") if os.path.lexists(pager): if pager == "/usr/bin/less": args = [pager, "-R", "--no-init", "--QUIT-AT-EOF", tmp_path] else: args = [pager, tmp_path] else: args = ["/bin/cat", tmp_path] try: subprocess.call(args) except OSError as err: if err.errno != errno.ENOENT: raise args = ["/bin/cat", tmp_path] subprocess.call(args) os.remove(tmp_path) if output == ['']: return [] return output
def _download(self, entropy_client): """ Solo Download command. """ ask = self._nsargs.ask pretend = self._nsargs.pretend verbose = self._nsargs.verbose quiet = self._nsargs.quiet deep = self._nsargs.deep deps = not self._nsargs.nodeps recursive = not self._nsargs.norecursive relaxed = self._nsargs.relaxed onlydeps = self._nsargs.onlydeps bdeps = self._nsargs.bdeps multifetch = self._nsargs.multifetch packages = self._scan_packages( entropy_client, self._nsargs.packages) if not packages: entropy_client.output( "%s." % ( darkred(_("No packages found")),), level="error", importance=1) return 1 action = darkgreen(_("Package download")) exit_st = self._show_packages_info( entropy_client, packages, deps, ask, pretend, verbose, quiet, action_name=action) if exit_st != 0: return 1 run_queue, removal_queue = self._generate_install_queue( entropy_client, packages, deps, False, deep, relaxed, onlydeps, bdeps, recursive) if (run_queue is None) or (removal_queue is None): return 1 elif not (run_queue or removal_queue): entropy_client.output( "%s." % (blue(_("Nothing to do")),), level="warning", header=darkgreen(" @@ ")) return 0 if pretend: entropy_client.output( "%s." % (blue(_("All done")),)) return 0 down_data = {} exit_st = self._download_packages( entropy_client, run_queue, down_data, multifetch, True) if exit_st == 0: self._signal_ugc(entropy_client, down_data) return exit_st
def _list(self, entropy_client): """ Solo Security List command. """ affected = self._nsargs.affected unaffected = self._nsargs.unaffected sec = entropy_client.Security() if not (affected or unaffected): advisory_ids = sec.list() elif affected: advisory_ids = sec.vulnerabilities() else: advisory_ids = sec.fixed_vulnerabilities() if not advisory_ids: entropy_client.output( "%s." % ( darkgreen(_("No advisories available or applicable")), ), header=brown(" :: ")) return 0 for advisory_id in sorted(advisory_ids): affected_deps = sec.affected_id(advisory_id) if affected and not affected_deps: continue if unaffected and affected_deps: continue if affected_deps: affection_string = darkred("A") else: affection_string = darkgreen("N") advisory = sec.advisory(advisory_id) if advisory is None: continue affected_data = advisory['affected'] if not affected_data: continue for a_key in list(affected_data.keys()): k_data = advisory['affected'][a_key] vulnerables = ', '.join(k_data[0]['vul_vers']) description = "[Id:%s:%s][%s] %s: %s" % ( darkgreen(advisory_id), affection_string, brown(vulnerables), darkred(a_key), blue(advisory['title'])) entropy_client.output(description) return 0
def _list(self, entropy_client, inst_repo): """ Solo PreservedLibs List command. """ quiet = self._nsargs.quiet verbose = self._nsargs.verbose preserved_mgr = preservedlibs.PreservedLibraries( inst_repo, None, frozenset(), root=etpConst['systemroot']) preserved = preserved_mgr.list() if not preserved: if not quiet: entropy_client.output( darkgreen(_("No preserved libraries found")), header=darkred(" @@ ")) return 0 for library, elfclass, path, atom in preserved: if quiet: entropy_client.output(path, level="generic") continue needed_by_str = const_convert_to_unicode("") if verbose: needed_by_str += ", %s:" % ( darkgreen(_("needed by")), ) entropy_client.output( "%s [%s:%s -> %s]%s" % ( darkred(path), purple(library), teal(const_convert_to_unicode(elfclass)), enlightenatom(atom), needed_by_str, )) if verbose: package_ids = inst_repo.searchNeeded( library, elfclass=elfclass) for package_id in package_ids: atom = inst_repo.retrieveAtom(package_id) if atom is None: continue entropy_client.output( "%s" % (enlightenatom(atom),), header=brown(" -> "), importance=0) return 0
def _showdiff(self, entropy_client, fromfile, tofile): args = ["diff", "-Nu", "'" + fromfile + "'", "'" + tofile + "'"] output = getoutput(' '.join(args)).split("\n") coloured = [] for line in output: if line.startswith("---"): line = darkred(line) elif line.startswith("+++"): line = darkgreen(line) elif line.startswith("@@"): line = brown(line) elif line.startswith("-"): line = blue(line) elif line.startswith("+"): line = darkgreen(line) coloured.append(line + "\n") fd, tmp_path = None, None try: fd, tmp_path = const_mkstemp(suffix="equo.conf.showdiff") with os.fdopen(fd, "w") as f: f.writelines(coloured) f.flush() finally: if fd is not None: try: os.close(fd) except OSError: pass print("") pager = os.getenv("PAGER", "/usr/bin/less") if os.path.lexists(pager): if pager == "/usr/bin/less": args = [pager, "-R", "--no-init", "--QUIT-AT-EOF", tmp_path] else: args = [pager, tmp_path] else: args = ["/bin/cat", tmp_path] try: subprocess.call(args) except OSError as err: if err.errno != errno.ENOENT: raise args = ["/bin/cat", tmp_path] subprocess.call(args) os.remove(tmp_path) if output == ['']: return [] return output
def _search_mimetype(self, entropy_client, inst_repo, associate=False): """ Solo Query Mimetype command. """ installed = self._nsargs.installed quiet = self._nsargs.quiet verbose = self._nsargs.verbose settings = entropy_client.Settings() inst_repo_id = inst_repo.repository_id() if associate: mimetypes = self._nsargs.files else: mimetypes = self._nsargs.mimes if not quiet: entropy_client.output(darkgreen(_("Searching Mimetype")), header=darkred(" @@ ")) found = False for mimetype in mimetypes: if associate: # consider mimetype a file path mimetype = get_file_mime(mimetype) if mimetype is None: continue if not quiet: entropy_client.output(bold(mimetype), header=blue(" # ")) if installed: matches = [(x, inst_repo_id) for x in entropy_client.search_installed_mimetype(mimetype)] else: matches = entropy_client.search_available_mimetype(mimetype) if matches: found = True key_sorter = lambda x: entropy_client.open_repository(x[1]).retrieveAtom(x[0]) for pkg_id, pkg_repo in sorted(matches, key=key_sorter): repo = entropy_client.open_repository(pkg_repo) print_package_info(pkg_id, entropy_client, repo, extended=verbose, quiet=quiet) if not quiet: entry_str = ngettext("entry", "entries", len(matches)) toc = [] toc.append(("%s:" % (blue(_("Keyword")),), purple(mimetype))) toc.append(("%s:" % (blue(_("Found")),), "%s %s" % (len(matches), brown(entry_str)))) print_table(entropy_client, toc) if not quiet and not found: entropy_client.output(darkgreen("%s." % (_("No matches"),)), header=darkred(" @@ ")) return 0
def _connect(self): """ Connect to FTP host. """ timeout = self._timeout if timeout is None: # default timeout set to 60 seconds timeout = EntropyFtpUriHandler._DEFAULT_TIMEOUT count = 10 while True: count -= 1 try: self.__ftpconn = self.ftplib.FTP() self.__ftpconn.connect(self.__ftphost, self.__ftpport, timeout) break except (socket.gaierror,) as e: raise TransceiverConnectionError(repr(e)) except (socket.error,) as e: if not count: raise TransceiverConnectionError(repr(e)) except: if not count: raise if self._verbose: mytxt = _("connecting with user") self.output( "[ftp:%s] %s: %s" % ( darkgreen(self.__ftphost), mytxt, blue(self.__ftpuser), ), importance = 1, level = "info", header = darkgreen(" * ") ) try: self.__ftpconn.login(self.__ftpuser, self.__ftppassword) except self.ftplib.error_perm as e: raise TransceiverConnectionError(repr(e)) if self._verbose: mytxt = _("switching to") self.output( "[ftp:%s] %s: %s" % ( darkgreen(self.__ftphost), mytxt, blue(self.__ftpdir), ), importance = 1, level = "info", header = darkgreen(" * ") ) # create dirs if they don't exist self._set_cwd(self.__ftpdir, dodir = True) self.__connected = True
def _connect(self): """ Connect to FTP host. """ timeout = self._timeout if timeout is None: # default timeout set to 60 seconds timeout = EntropyFtpUriHandler._DEFAULT_TIMEOUT count = 10 while True: count -= 1 try: self.__ftpconn = self.ftplib.FTP() self.__ftpconn.connect(self.__ftphost, self.__ftpport, timeout) break except (socket.gaierror, ) as e: raise TransceiverConnectionError(repr(e)) except (socket.error, ) as e: if not count: raise TransceiverConnectionError(repr(e)) except: if not count: raise if self._verbose: mytxt = _("connecting with user") self.output("[ftp:%s] %s: %s" % ( darkgreen(self.__ftphost), mytxt, blue(self.__ftpuser), ), importance=1, level="info", header=darkgreen(" * ")) try: self.__ftpconn.login(self.__ftpuser, self.__ftppassword) except self.ftplib.error_perm as e: raise TransceiverConnectionError(repr(e)) if self._verbose: mytxt = _("switching to") self.output("[ftp:%s] %s: %s" % ( darkgreen(self.__ftphost), mytxt, blue(self.__ftpdir), ), importance=1, level="info", header=darkgreen(" * ")) # create dirs if they don't exist self._set_cwd(self.__ftpdir, dodir=True) self.__connected = True
def _test(self, entropy_client): """ Command implementation. """ entropy_client.output("%s..." % (blue(_("Running dependency test")), ), header=darkred(" @@ ")) inst_repo = entropy_client.installed_repository() with inst_repo.shared(): not_found_deps, crying_atoms, found_deps = self._test_installed( entropy_client, inst_repo) if not not_found_deps: entropy_client.output(darkgreen(_("No missing dependencies")), header=darkred(" @@ ")) return 0 entropy_client.output( "%s:" % (blue(_("These are the dependencies not found")), ), header=darkred(" @@ ")) for atom in not_found_deps: entropy_client.output(darkred(atom), header=" # ") if atom in crying_atoms: entropy_client.output("%s:" % (darkred(_("Needed by")), ), header=blue(" # ")) for x in crying_atoms[atom]: entropy_client.output(darkgreen(x), header=blue(" # ")) if self._ask: rc = entropy_client.ask_question( " %s" % (_("Would you like to install the packages ?"), )) if rc == _("No"): return 1 else: mytxt = "%s %s %s" % ( blue(_("Installing available packages in")), darkred(_("10 seconds")), blue("..."), ) entropy_client.output(mytxt, header=darkred(" @@ ")) time.sleep(10) exit_st, _show_cfgupd = self._install_action( entropy_client, True, True, self._pretend, self._ask, False, self._quiet, False, False, False, False, False, False, False, 1, sorted(found_deps)) return exit_st
def _list(self, entropy_client, inst_repo): """ Solo PreservedLibs List command. """ quiet = self._nsargs.quiet verbose = self._nsargs.verbose preserved_mgr = preservedlibs.PreservedLibraries( inst_repo, None, frozenset(), root=etpConst['systemroot']) preserved = preserved_mgr.list() if not preserved: if not quiet: entropy_client.output(darkgreen( _("No preserved libraries found")), header=darkred(" @@ ")) return 0 for library, elfclass, path, atom in preserved: if quiet: entropy_client.output(path, level="generic") continue needed_by_str = const_convert_to_unicode("") if verbose: needed_by_str += ", %s:" % (darkgreen(_("needed by")), ) entropy_client.output("%s [%s:%s -> %s]%s" % ( darkred(path), purple(library), teal(const_convert_to_unicode(elfclass)), enlightenatom(atom), needed_by_str, )) if verbose: package_ids = inst_repo.searchNeeded(library, elfclass=elfclass) for package_id in package_ids: atom = inst_repo.retrieveAtom(package_id) if atom is None: continue entropy_client.output("%s" % (enlightenatom(atom), ), header=brown(" -> "), importance=0) return 0
def _status(self, entropy_server): """ Actual Eit lock|unlock --status code. Just show repo status. """ repositories = entropy_server.repositories() if self._repository_id not in repositories: entropy_server.output( "%s: %s" % (_("Invalid Repository"), self._repository_id), level="error", importance=1) return 1 if not self._quiet: entropy_server.output("%s:" % (darkgreen(_("Mirrors status")), ), header=brown(" * ")) dbstatus = entropy_server.Mirrors.mirrors_status(self._repository_id) for uri, server_lock, client_lock in dbstatus: host = EntropyTransceiver.get_uri_name(uri) if not self._quiet: entropy_server.output("[%s]" % (purple(host), ), header=darkgreen(" @@ ")) if server_lock: lock_str = darkred(_("Locked")) quiet_lock_str = "locked" else: lock_str = darkgreen(_("Unlocked")) quiet_lock_str = "unlocked" if self._quiet: entropy_server.output("%s server %s" % (host, quiet_lock_str), level="generic") else: entropy_server.output("%s: %s" % (blue(_("server")), lock_str), header=brown(" # ")) if client_lock: lock_str = darkred(_("Locked")) quiet_lock_str = "locked" else: lock_str = darkgreen(_("Unlocked")) quiet_lock_str = "unlocked" if self._quiet: entropy_server.output("%s client %s" % (host, quiet_lock_str), level="generic") else: entropy_server.output("%s: %s" % (blue(_("client")), lock_str), header=brown(" # ")) return 0
def _license(self, entropy_client): """ Solo Query License command. """ quiet = self._nsargs.quiet verbose = self._nsargs.verbose licenses = self._nsargs.licenses settings = entropy_client.Settings() if not quiet: entropy_client.output(darkgreen(_("License Search")), header=darkred(" @@ ")) found = False repo_number = 0 for repo_id in entropy_client.repositories(): repo_number += 1 repo_data = settings["repositories"]["available"][repo_id] if not quiet: header = ( const_convert_to_unicode(" #") + const_convert_to_unicode(repo_number) + const_convert_to_unicode(" ") ) entropy_client.output("%s" % (bold(repo_data["description"]),), header=blue(header)) repo = entropy_client.open_repository(repo_id) key_sorter = lambda x: repo.retrieveAtom(x) for mylicense in licenses: results = repo.searchLicense(mylicense, just_id=True) if not results: continue found = True for pkg_id in sorted(results, key=key_sorter): print_package_info(pkg_id, entropy_client, repo, extended=verbose, strict_output=quiet, quiet=quiet) if not quiet: res_txt = ngettext("entry", "entries", len(results)) toc = [] toc.append(("%s:" % (blue(_("Keyword")),), purple(mylicense))) toc.append(("%s:" % (blue(_("Found")),), "%s %s" % (len(results), brown(res_txt)))) print_table(entropy_client, toc) if not quiet and not found: entropy_client.output(darkgreen("%s." % (_("No matches"),)), header=darkred(" @@ ")) return 0
def _delete(self, entropy_server): """ Actual Eit key delete code. """ repo_sec = self._get_gpg(entropy_server) if repo_sec is None: return 1 repo = entropy_server.repository() entropy_server.output("%s: %s" % ( blue(_("Deleting keys for repository")), purple(repo),)) if not repo_sec.is_keypair_available(repo): entropy_server.output("%s: %s" % ( blue(_("No keys available for given repository")), purple(repo), ), level = "warning" ) return 0 answer = entropy_server.ask_question(_("Are you really sure?")) if answer == _("No"): return 1 try: key_meta = repo_sec.get_key_metadata(repo) except KeyError: entropy_server.output("%s: %s" % ( darkgreen(_("Keys metadata not available for")), bold(repo), ), level = "error" ) return 1 # remove signatures from repository database dbconn = entropy_server.open_server_repository( repo, read_only = False) dbconn.dropGpgSignatures() repo_sec.delete_keypair(repo) entropy_server.output("%s: %s" % ( darkgreen(_("Deleted GPG key with fingerprint")), bold(key_meta['fingerprint']), ), level = "info" ) return 0
def _load_maybe_add(self, currentdir, item, filepath, number): """ Scan given path and store config file update information if needed. """ try: tofile = item[10:] number = item[5:9] except IndexError as err: const_debug_write(__name__, "load_maybe_add, IndexError: " "%s, locals: %s" % (repr(err), locals())) return try: int(number) except ValueError as err: # not a number const_debug_write(__name__, "load_maybe_add, ValueError: " "%s, locals: %s" % (repr(err), locals())) return tofilepath = os.path.join(currentdir, tofile) # tofile is the target filename now # before adding, determine if we should automerge it if self._load_can_automerge(filepath, tofilepath): if not self._quiet: self._entropy.output( darkred("%s: %s") % (_("Automerging file"), darkgreen(filepath)), importance=0, level="info" ) try: rename_keep_permissions(filepath, tofilepath) except OSError as err: const_debug_write(__name__, "load_maybe_add, OSError: " "%s, locals: %s" % (repr(err), locals())) except IOError as err: const_debug_write(__name__, "load_maybe_add, IOError: " "%s, locals: %s" % (repr(err), locals())) return # store save_filepath = self._strip_root(self._unicode_path(filepath)) obj = { "destination": self._strip_root(self._unicode_path(tofilepath)), "automerge": False, # redundant but backward compat } self[save_filepath] = obj if not self._quiet: self._entropy.output( "%s: %s" % (brown(_("Found update")), self._unicode_path(darkgreen(filepath))), importance=0, level="info", )
def _sets(self, entropy_server): """ Eit query sets code. """ repository_ids = [] if self._repository_id is None: repository_ids += entropy_server.repositories() else: repository_ids.append(self._repository_id) repository_ids = tuple(repository_ids) sets = entropy_server.Sets() match_num = 0 if not self._nsargs.sets: self._nsargs.sets.append("*") for item in self._nsargs.sets: results = sets.search(item, match_repo=repository_ids) key_sorter = lambda x: x[1] for repo, set_name, set_data in sorted(results, key=key_sorter): match_num += 1 found = True if not self._quiet: entropy_server.output( "%s%s" % (brown(etpConst['packagesetprefix']), darkgreen(set_name),)) if self._verbose: elements = sorted(set_data) for element in elements: entropy_server.output( teal(element), header=" ") else: entropy_server.output( "%s%s" % (etpConst['packagesetprefix'], set_name,), level="generic") if self._verbose: for element in sorted(set_data): entropy_server.output( element, level="generic") if not self._quiet: entropy_server.output( "[%s] %s %s" % ( darkgreen(item), bold(str(match_num)), teal(_("sets found")))) return 0
def _interactive_merge(self, idx, entropy_client, root, source, dest, paths_map, scandata): """ Interactively merge config file. """ source_path = root + source dest_path = root + dest entropy_client.output( "%s: %s" % ( darkred(_("Interactive merge")), darkgreen(source_path),) ) merge_outcome_path, exit_status = self._interactive_merge_diff( source_path, dest_path) if exit_status in (2, 130): # quit return False, True try: entropy.tools.rename_keep_permissions( merge_outcome_path, source_path) except OSError as err: entropy_client.output( "%s: %s" % ( darkred(_("OSError during interactive merge")), repr(err),), level="error") return False, True except IOError as err: entropy_client.output( "%s: %s" % ( darkred(_("IOError during interactive merge")), repr(err),), level="error") return False, True merged = scandata.merge(source) del paths_map[idx] if not merged: entropy_client.output( "%s: %s" % ( darkred(_("Unable to merge file")), darkgreen(source_path),), level="error") return True, False
def _handle_preserved_lib(self, path, atom, preserved_mgr): """ Preserve libraries that would be removed but are still needed by installed packages. This is a safety measure for accidental removals. Proper library dependency ordering should be done during dependencies calculation. """ solved = preserved_mgr.resolve(path) if solved is None: return None paths = preserved_mgr.determine(path) if paths: self._entropy.output( "%s: %s, %s" % ( darkgreen(_("Protecting")), teal(path), darkgreen(_("library needed by:")), ), importance = 1, level = "warning", header = red(" ## ") ) library, elfclass, s_path = solved preserved_mgr.register(library, elfclass, s_path, atom) installed_package_ids = preserved_mgr.needed(path) installed_repository = preserved_mgr.installed_repository() for installed_package_id in installed_package_ids: atom = installed_repository.retrieveAtom(installed_package_id) self._entropy.output( brown(atom), importance = 0, level = "warning", header = darkgreen(" :: ") ) self._entropy.logger.log( "[Package]", etpConst['logging']['normal_loglevel_id'], "Protecting library %s, due to package: %s" % ( path, atom,) ) return paths
def _show_help(self, *args): # equo help <foo> <bar> if len(self._args) > 1: # syntax error return -10 parser = argparse.ArgumentParser( description=_("Entropy Command Line Client, Equo"), epilog="http://www.sabayon.org", formatter_class=ColorfulFormatter) # filtered out in solo.main. Will never get here parser.add_argument( "--color", action="store_true", default=None, help=_("force colored output")) descriptors = SoloCommandDescriptor.obtain() descriptors.sort(key = lambda x: x.get_name()) group = parser.add_argument_group("command", "available commands") for descriptor in descriptors: if descriptor.get_class().HIDDEN: continue aliases = descriptor.get_class().ALIASES aliases_str = ", ".join([teal(x) for x in aliases]) if aliases_str: aliases_str = " [%s]" % (aliases_str,) name = "%s%s" % (purple(descriptor.get_name()), aliases_str) desc = descriptor.get_description() group.add_argument(name, help=darkgreen(desc), action="store_true") parser.print_help() if not self._args: return 1 return 0
def _read_lic_selection(): entropy_client.output( darkred(_("Please select an option")), header=" ") entropy_client.output( "(%d) %s" % ( 1, darkgreen(_("Read the license"))), header=" ") entropy_client.output( "(%d) %s" % ( 2, brown(_("Accept the license (I've read it)"))), header=" ") entropy_client.output( "(%d) %s" % ( 3, darkred(_("Accept the license and don't " "ask anymore (I've read it)"))), header=" ") entropy_client.output( "(%d) %s" % (0, bold(_("Quit"))), header=" ") # wait user interaction try: action = readtext( " %s: " % ( _("Your choice (type a number and press enter)"),) ) except EOFError: action = None return action
def _advise_packages_update(self, entropy_client): """ Warn user about critical package updates, if any. """ client_settings = entropy_client.ClientSettings() misc_settings = client_settings['misc'] splitdebug = misc_settings['splitdebug'] forced_updates = misc_settings.get('forcedupdates') if forced_updates: crit_atoms, crit_matches = \ entropy_client.calculate_critical_updates() if crit_atoms: entropy_client.output("") entropy_client.output("") update_msg = _("Please update the following " "critical packages") entropy_client.output("%s:" % (purple(update_msg),), level="warning") for name in sorted(crit_atoms): entropy_client.output( brown(name), header=darkred(" # "), level="warning") entropy_client.output( darkgreen(_("You should install them as " "soon as possible")), header=darkred(" !!! "), level="warning") entropy_client.output("") entropy_client.output("")
def _show_preserved_libraries(self, entropy_client): """ Inform User about preserved libraries living on the filesystem. This method is process and thread safe. """ inst_repo = entropy_client.installed_repository() with inst_repo.shared(): preserved_mgr = PreservedLibraries( inst_repo, None, frozenset(), root=etpConst['systemroot']) preserved = preserved_mgr.list() if preserved: mytxt = ngettext( "There is %s preserved library on the system", "There are %s preserved libraries on the system", len(preserved)) % (len(preserved),) entropy_client.output( darkgreen(mytxt), level="warning") for library, elfclass, path, atom in preserved: entropy_client.output( "%s [%s:%s -> %s]" % ( darkred(path), purple(library), teal(const_convert_to_unicode(elfclass)), enlightenatom(atom), ))
def _show_graph_legend(entropy_client): entropy_client.output("%s:" % (purple(_("Legend")),)) entropy_client.output("[%s] %s" % (blue("x"), blue(_("packages passed as arguments")),)) entropy_client.output("[%s] %s" % (darkgreen("x"), darkgreen(_("packages with no further dependencies")),)) entropy_client.output("[%s] %s" % (purple("x"), purple(_("packages with further dependencies (node)")),)) entropy_client.output("[%s] %s" % (brown("x"), brown(_("packages already pulled in as dependency in upper levels (circularity)")),)) entropy_client.output("="*40, level="generic")
def _files(self, entropy_server): """ Actual Eit files code. """ exit_st = 0 for package in self._packages: pkg_id, pkg_repo = entropy_server.atom_match(package) if pkg_id == -1: exit_st = 1 if not self._quiet: entropy_server.output( "%s: %s" % ( purple(_("Not matched")), teal(package)), level="warning", importance=1) continue entropy_repository = entropy_server.open_repository(pkg_repo) files = entropy_repository.retrieveContent( pkg_id, order_by="file") atom = entropy_repository.retrieveAtom(pkg_id) if self._quiet: for path in files: entropy_server.output(path, level="generic") else: for path in files: entropy_server.output(path) entropy_server.output( "[%s] %s: %s %s" % ( purple(pkg_repo), darkgreen(atom), bold(str(len(files))), teal(_("files found")))) return exit_st
def _push_progress_to_output(self): mytxt = _("[F]") eta_txt = _("ETA") sec_txt = _("sec") # as in XX kb/sec current_txt = darkred(" %s: " % (mytxt,)) + \ darkgreen(str(round(float(self.__downloadedsize)/1000, 1))) + "/" \ + red(str(round(self.__remotesize, 1))) + " kB" # create progress bar barsize = 10 bartext = "[" curbarsize = 1 averagesize = (self.__average*barsize)/100 while averagesize > 0: curbarsize += 1 bartext += "=" averagesize -= 1 bartext += ">" diffbarsize = barsize - curbarsize while diffbarsize > 0: bartext += " " diffbarsize -= 1 if self.__show_speed: bartext += "] => %s" % (bytes_into_human(self.__datatransfer),) bartext += "/%s : %s: %s" % (sec_txt, eta_txt, self.__time_remaining,) else: bartext += "]" average = str(self.__average) if len(average) < 2: average = " "+average current_txt += " <-> "+average+"% "+bartext TextInterface.output(current_txt, back = True)
def _read_lic_selection(): entropy_client.output(darkred(_("Please select an option")), header=" ") entropy_client.output("(%d) %s" % (1, darkgreen(_("Read the license"))), header=" ") entropy_client.output( "(%d) %s" % (2, brown(_("Accept the license (I've read it)"))), header=" ") entropy_client.output("(%d) %s" % (3, darkred( _("Accept the license and don't " "ask anymore (I've read it)"))), header=" ") entropy_client.output("(%d) %s" % (0, bold(_("Quit"))), header=" ") # wait user interaction try: action = readtext( " %s: " % (_("Your choice (type a number and press enter)"), )) except EOFError: action = None return action
def _advise_packages_update(self, entropy_client): """ Warn user about critical package updates, if any. """ client_settings = entropy_client.ClientSettings() misc_settings = client_settings['misc'] splitdebug = misc_settings['splitdebug'] forced_updates = misc_settings.get('forcedupdates') if forced_updates: crit_atoms, crit_matches = \ entropy_client.calculate_critical_updates() if crit_atoms: entropy_client.output("") entropy_client.output("") update_msg = _("Please update the following " "critical packages") entropy_client.output("%s:" % (purple(update_msg), ), level="warning") for name in sorted(crit_atoms): entropy_client.output(brown(name), header=darkred(" # "), level="warning") entropy_client.output(darkgreen( _("You should install them as " "soon as possible")), header=darkred(" !!! "), level="warning") entropy_client.output("") entropy_client.output("")
def _show_preserved_libraries(self, entropy_client): """ Inform User about preserved libraries living on the filesystem. This method is process and thread safe. """ inst_repo = entropy_client.installed_repository() with inst_repo.shared(): preserved_mgr = PreservedLibraries(inst_repo, None, frozenset(), root=etpConst['systemroot']) preserved = preserved_mgr.list() if preserved: mytxt = ngettext("There is %s preserved library on the system", "There are %s preserved libraries on the system", len(preserved)) % (len(preserved), ) entropy_client.output(darkgreen(mytxt), level="warning") for library, elfclass, path, atom in preserved: entropy_client.output("%s [%s:%s -> %s]" % ( darkred(path), purple(library), teal(const_convert_to_unicode(elfclass)), enlightenatom(atom), ))
def notify(self): """ Overridden from BaseAntiMatterResult """ for package in self._result: if self._nsargs.extended: cp = package.key() slot = package.slot() from_ver = "x" inst = package.installed() if inst is not None: from_ver = inst.version to_ver = "x" avail = package.available() if avail is not None: to_ver = avail.version name = "%s:%s [%s->%s]" % (darkgreen(cp), brown(slot), teal(from_ver), purple(to_ver)) elif self._nsargs.verbose: name = package.target() else: name = package.keyslot() if self._nsargs.quiet: print_generic(name) else: print_info(name)
def revgraph_packages(packages, entropy_client, complete = False, repository_ids = None, quiet = False): if repository_ids is None: repository_ids = [entropy_client.installed_repository( ).repository_id()] found = False for repository_id in repository_ids: entropy_repository = entropy_client.open_repository(repository_id) for package in packages: pkg_id, pkg_rc = entropy_repository.atomMatch(package) if pkg_rc == 1: continue if not quiet: entropy_client.output( darkgreen("%s %s..." % ( _("Reverse graphing installed package"), purple(package),) ), header=brown(" @@ ")) found = True g_pkg = entropy_repository.retrieveAtom(pkg_id) _revgraph_package(entropy_client, pkg_id, g_pkg, entropy_repository, show_complete = complete, quiet = quiet) if not found: entropy_client.output( purple(_("No packages found")), level="warning", importance=1) return 1 return 0
def cleanup(entropy_client, directories): """ Temporary files cleaner. @param directories: list of directory paths @type directories: list @return: exit status @rtype: int """ counter = 0 for xdir in directories: if not os.path.isdir(xdir): continue entropy_client.output( "%s %s %s..." % ( _("Cleaning"), darkgreen(xdir), _("directory"),), back = True) for data in os.listdir(xdir): subprocess.call(["rm", "-rf", os.path.join(xdir, data)]) counter += 1 entropy_client.output( "%s: %s %s" % ( _("Cleaned"), counter, _("files and directories"),) ) return 0
def _selfile(self, entropy_client): entropy_client.output( darkred( _("Please choose a file to update by typing " "its identification number."))) entropy_client.output(darkred(_("Other options are:"))) entropy_client.output(" (%s) %s" % ( blue(const_convert_to_unicode("-1")), darkgreen(_("Exit")), )) entropy_client.output(" (%s) %s" % ( blue(const_convert_to_unicode("-3")), brown(_("Automerge all the files asking you one by one")), )) entropy_client.output(" (%s) %s" % ( blue(const_convert_to_unicode("-5")), darkred(_("Automerge all the files without questioning")), )) entropy_client.output(" (%s) %s" % ( blue(const_convert_to_unicode("-7")), brown(_("Discard all the files asking you one by one")), )) entropy_client.output(" (%s) %s" % ( blue(const_convert_to_unicode("-9")), darkred(_("Discard all the files without questioning")), )) # wait user interaction try: action = readtext( _("Your choice (type a number and press enter):") + " ") except EOFError: action = None return action
def graph_packages(packages, entropy_client, complete = False, repository_ids = None, quiet = False): found = False for package in packages: match = entropy_client.atom_match(package, match_repo = repository_ids) if match[0] == -1: continue if not quiet: entropy_client.output( darkgreen("%s %s..." % ( _("Graphing"), purple(package),) ), header=brown(" @@ ")) found = True pkg_id, repo_id = match repodb = entropy_client.open_repository(repo_id) g_pkg = repodb.retrieveAtom(pkg_id) _graph_package(match, g_pkg, entropy_client, show_complete = complete, quiet = quiet) if not found: entropy_client.output( purple(_("No packages found")), level="warning", importance=1) return 1 return 0
def _show_notice_board_summary(self, entropy_client, repository): """ Show NoticeBoard information to user after repository update. """ mytxt = "%s %s: %s" % ( darkgreen(" @@ "), brown(_("Notice board")), bold(repository), ) entropy_client.output(mytxt) mydict = self._check_notice_board_availability(entropy_client, repository) if not mydict: return for key in sorted(mydict.keys()): mydata = mydict.get(key) mytxt = " [%s] [%s] %s: %s" % ( blue(str(key)), brown(mydata['pubDate']), _("Title"), darkred(mydata['title']), ) entropy_client.output(mytxt)
def _parse_progress_line(self, line): line_data = line.strip().split() if len(line_data) < 5: const_debug_write(__name__, "_parse_progress_line: cannot parse: %s" % (line_data,)) # mmh... not possible to properly parse data self.output(line.strip(), back = True) return const_debug_write(__name__, "_parse_progress_line: parsing: %s" % (line_data,)) file_name = line_data[0] percent = line_data[1] tx_speed = line_data[3] tx_size = line_data[2] eta = line_data[4] # create text mytxt = _("Transfer status") current_txt = "<-> (%s) %s: " % (teal(file_name), brown(mytxt),) + \ darkgreen(tx_size) + " " + \ brown("[") + str(percent) + brown("]") + \ " " + eta + " " + tx_speed self.output(current_txt, back = True, header = " ")