aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pym/gentoolkit/eshowkw/keywords_content.py')
-rw-r--r--pym/gentoolkit/eshowkw/keywords_content.py756
1 files changed, 399 insertions, 357 deletions
diff --git a/pym/gentoolkit/eshowkw/keywords_content.py b/pym/gentoolkit/eshowkw/keywords_content.py
index 786e8b9..4f9e3e1 100644
--- a/pym/gentoolkit/eshowkw/keywords_content.py
+++ b/pym/gentoolkit/eshowkw/keywords_content.py
@@ -1,4 +1,4 @@
-# vim:fileencoding=utf-8
+# vim:fileencoding=utf-8
# Copyright 2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
@@ -6,364 +6,406 @@ import portage as port
import os
from portage.output import colorize
-__all__ = ['keywords_content']
+__all__ = ["keywords_content"]
from gentoolkit.eshowkw.display_pretty import colorize_string
from gentoolkit.eshowkw.display_pretty import align_string
+
class keywords_content:
- class RedundancyChecker:
- def __listRedundant(self, masks, keywords, ignoreslots, slots):
- """List all redundant packages."""
- if ignoreslots:
- return self.__listRedundantAll(masks, keywords)
- else:
- return self.__listRedundantSlots(masks, keywords, slots)
-
- def __listRedundantSlots(self, masks, keywords, slots):
- """Search for redundant packages walking per keywords for specified slot."""
- output = list()
- zipped = list(zip(masks, keywords, slots))
- for slot in self.__uniq(slots):
- ms = list()
- ks = list()
- for m, k, s in zipped:
- if slot == s:
- ms.append(m)
- ks.append(k)
- output.append(self.__compareSelected(ms, ks))
- # this is required because the list itself is not just one level depth
- return list(''.join(output))
-
- @staticmethod
- def __uniq(seq):
- """Remove all duplicate elements from list."""
- seen = {}
- result = []
- for item in seq:
- if item in seen:
- continue
- seen[item] = 1
- result.append(item)
- return result
-
- @staticmethod
- def __cleanKeyword(keyword):
- """Remove masked arches and hardmasks from keywords since we don't care about that."""
- return ["%s" % x for x in keyword.split()
- if x != '-*' and not x.startswith('-')]
-
- def __listRedundantAll(self, masks, keywords):
- """Search for redundant packages using all versions ignoring its slotting."""
- return list(self.__compareSelected(list(masks), list(keywords)))
-
- def __compareSelected(self, masks, kws):
- """
- Rotate over list of keywords and compare each element with others.
- Selectively remove each already compared list from the remaining keywords.
- """
- result = []
- kws.reverse()
- masks.reverse()
- for i in range(len(kws)):
- kw = kws.pop()
- masks.pop()
- if self.__compareKeywordWithRest(kw, kws, masks):
- result.append('#')
- else:
- result.append('o')
- if len(result) == 0:
- result.append('o')
- return ''.join(result)
-
- def __compareKeywordWithRest(self, keyword, keywords, masks):
- """Compare keywords with list of keywords."""
- kw = self.__cleanKeyword(keyword)
- for kwi, mask in zip(keywords, masks):
- kwi = self.__cleanKeyword(kwi)
- if kwi and not mask:
- kw = self.__checkShadow(kw, kwi)
- if not kw:
- return True
- return False
-
- def __checkShadow(self, old, new):
- """Check if package version is overshadowed by other package version."""
- tmp = set(new)
- tmp.update("~%s" % x for x in new
- if not x.startswith("~"))
- return list(set(old).difference(tmp))
-
- def __init__(self, masks, keywords, slots, ignore_slots = False):
- """Query all relevant data for redundancy package checking"""
- self.redundant = self.__listRedundant(masks, keywords, ignore_slots, slots)
-
- class VersionChecker:
- def __getVersions(self, packages):
- """Obtain properly aligned version strings without colors."""
- revlength = max([len(self.__getRevision(x)) for x, repo in packages])
- return [self.__separateVersion(x, repo, revlength) for x, repo in packages]
-
- def __getRevision(self, cpv):
- """Get revision informations for each package for nice further alignment"""
- rev = port.catpkgsplit(cpv)[3]
- return rev if rev != 'r0' else ''
-
- def __separateVersion(self, cpv, repo, revlength):
- return self.__modifyVersionInfo(cpv, repo, port.versions.cpv_getversion(cpv), revlength)
-
- def __modifyVersionInfo(self, cpv, repo, pv, revlength):
- """Prefix and suffix version with string based on whether version is installed or masked and its revision."""
- mask = self.__getMaskStatus(cpv)
- install = self.__getInstallStatus(cpv, repo)
-
- # calculate suffix length
- currevlen = len(self.__getRevision(cpv))
- suffixlen = revlength - currevlen
- # +1 required for the dash in revision
- if suffixlen != 0 and currevlen == 0:
- suffixlen = suffixlen + 1
- suffix = ''
- for x in range(suffixlen):
- suffix = '%s ' % suffix
-
- if mask and install:
- pv = '[M][I]%s%s' % (pv, suffix)
- elif mask:
- pv = '[M]%s%s' % (pv, suffix)
- elif install:
- pv = '[I]%s%s' % (pv, suffix)
- else:
- pv = '%s%s' % (pv, suffix)
- return pv
-
- def __getMaskStatus(self, cpv):
- """Figure out if package is pmasked."""
- try:
- if "package.mask" in port.getmaskingstatus(cpv, settings=self.mysettings):
- return True
- except:
- # occurs when package is not known by portdb
- # so we consider it unmasked
- pass
- return False
-
-
- def __getInstallStatus(self, cpv, repo):
- """Check if package version we test is installed."""
- return bool(self.vartree.match("=%s::%s" % (cpv, repo)))
-
- def __init__(self, packages):
- """Query all relevant data for version data formatting"""
- self.vartree = port.db[port.root]['vartree'].dbapi
- self.mysettings = port.config(local_config=False)
- self.versions = self.__getVersions(packages)
- self.masks = list(map(lambda x: self.__getMaskStatus(x), packages))
-
- @staticmethod
- def __packages_sort(package_content):
- """
- Sort packages queried based on version and slot
- %% pn , repo, slot, eapi, keywords
- """
- if len(package_content) > 1:
- ver_map = {}
- for cpv in package_content:
- ver_map[cpv[0]] = '-'.join(port.versions.catpkgsplit(cpv[0])[2:])
- def cmp_cpv(cpv1, cpv2):
- return port.versions.vercmp(ver_map[cpv1[0]], ver_map[cpv2[0]])
-
- package_content.sort(key=port.util.cmp_sort_key(cmp_cpv))
-
- def __xmatch(self, pdb, package):
- """xmatch function that searches for all packages over all repos"""
- try:
- mycp = port.dep_expand(package, mydb=pdb, settings=pdb.settings).cp
- except port.exception.AmbiguousPackageName as Arg:
- msg_err = 'Ambiguous package name "%s".\n' % package
- found = 'Possibilities: %s' % Arg
- raise SystemExit('%s%s' % (msg_err, found))
- except port.exception.InvalidAtom:
- msg_err = 'No such package "%s"' % package
- raise SystemExit(msg_err)
-
- mysplit = mycp.split('/')
- mypkgs = []
- for oroot in pdb.porttrees:
- try:
- file_list = os.listdir(os.path.join(oroot, mycp))
- except OSError:
- continue
- for x in file_list:
- pf = x[:-7] if x[-7:] == '.ebuild' else []
- if pf:
- ps = port.pkgsplit(pf)
- if not ps or ps[0] != mysplit[1]:
- # we got garbage or ebuild with wrong name in the dir
- continue
- ver_match = port.versions.ver_regexp.match("-".join(ps[1:]))
- if ver_match is None or not ver_match.groups():
- # version is not allowed by portage or unset
- continue
- # obtain related data from metadata and append to the pkg list
- keywords, slot, eapi = self.__getMetadata(pdb, mysplit[0]+'/'+pf, oroot)
- mypkgs.append([mysplit[0]+'/'+pf, oroot, slot, eapi, keywords])
-
- self.__packages_sort(mypkgs)
- return mypkgs
-
- def __checkExist(self, pdb, package):
- """Check if specified package even exists."""
- matches = self.__xmatch(pdb, package)
- if len(matches) <= 0:
- msg_err = 'No such package "%s"' % package
- raise SystemExit(msg_err)
- return list(zip(*matches))
-
- @staticmethod
- def __getMetadata(pdb, package, repo):
- """Obtain all required metadata from portage auxdb"""
- try:
- metadata = pdb.aux_get(package, ['KEYWORDS', 'SLOT', 'EAPI'], repo)
- except KeyError:
- # portage prints out more verbose error for us if we were lucky
- raise SystemExit('Failed to obtain metadata')
- return metadata
-
- def __formatKeywords(self, keywords, keywords_list, usebold = False, toplist = 'archlist'):
- """Loop over all keywords and replace them with nice visual identifier"""
- # the % is fancy separator, we use it to split keywords for rotation
- # so we wont loose the empty spaces
- return ['% %'.join([self.__prepareKeywordChar(arch, i, version.split(), usebold, toplist)
- for i, arch in enumerate(keywords_list)])
- for version in keywords]
-
- @staticmethod
- def __prepareKeywordChar(arch, field, keywords, usebold = False, toplist = 'archlist'):
- """
- Convert specified keywords for package into their visual replacements.
- # possibilities:
- # ~arch -> orange ~
- # -arch -> red -
- # arch -> green +
- # -* -> red *
- """
- keys = [ '~%s' % arch, '-%s' % arch, '%s' % arch, '-*' ]
- values = [
- colorize('darkyellow', '~'),
- colorize('darkred', '-'),
- colorize('darkgreen', '+'),
- colorize('darkred', '*')
- ]
- # check what keyword we have
- # here we cant just append space because it would get stripped later
- char = colorize('darkgray','o')
- for k, v in zip(keys, values):
- if k in keywords:
- char = v
- break
- if toplist == 'archlist' and usebold and (field)%2 == 0 and char != ' ':
- char = colorize('bold', char)
- return char
-
- @staticmethod
- def __formatVersions(versions, align, length):
- """Append colors and align keywords properly"""
- # % are used as separators for further split so we wont loose spaces and coloring
- tmp = []
- for pv in versions:
- pv = align_string(pv, align, length)
- pv = '%'.join(list(pv))
- if pv.find('[%M%][%I%]') != -1:
- tmp.append(colorize_string('darkyellow', pv))
- elif pv.find('[%M%]') != -1:
- tmp.append(colorize_string('darkred', pv))
- elif pv.find('[%I%]') != -1:
- tmp.append(colorize_string('bold', pv))
- else:
- tmp.append(pv)
- return tmp
-
- @staticmethod
- def __formatAdditional(additional, color, length):
- """Align additional items properly"""
- # % are used as separators for further split so we wont loose spaces and coloring
- tmp = []
- for x in additional:
- tmpc = color
- x = align_string(x, 'left', length)
- x = '%'.join(list(x))
- if x == 'o':
- # the value is unset so the color is gray
- tmpc = 'darkgray'
- x = colorize_string(tmpc, x)
- tmp.append(x)
- return tmp
-
- @staticmethod
- def __formatEapis(eapis, repos, repos_configs, length):
- """Align eapis items properly"""
- # % are used as separators for further split so we wont loose spaces and coloring
- tmp = []
- for eapi, repo in zip(eapis, repos):
- tmp_eapi = eapi
- eapi = align_string(eapi, 'left', length)
- eapi = '%'.join(list(eapi))
- if repos_configs[repo].eapi_is_banned(tmp_eapi):
- eapi = colorize_string('red', eapi)
- elif repos_configs[repo].eapi_is_deprecated(tmp_eapi):
- eapi = colorize_string('yellow', eapi)
- else:
- eapi = colorize_string('green', eapi)
- tmp.append(eapi)
- return tmp
-
- @staticmethod
- def __prepareContentResult(versions, keywords, eapi, redundant, slots, slot_length, repos, linesep):
- """Parse version fields into one list with proper separators"""
- content = []
- oldslot = ''
- fieldsep = '% %|% %'
- normsep = '% %'
- for v, k, e, r, s, t in zip(versions, keywords, eapi, redundant, slots, repos):
- if oldslot != s:
- oldslot = s
- content.append(linesep)
- else:
- s = '%'.join(list(''.rjust(slot_length)))
- content.append('%s%s%s%s%s%s%s%s%s%s%s' % (v, fieldsep, k, fieldsep, e, normsep, r, normsep, s, fieldsep, t))
- return content
-
- def __init__(self, package, keywords_list, porttree, ignoreslots = False, content_align = 'bottom', usebold = False, toplist = 'archlist'):
- """Query all relevant data from portage databases."""
- packages, self.repositories, self.slots, self.eapi, self.keywords = self.__checkExist(porttree, package)
- # convert repositories from path to name
- self.repositories = [porttree.getRepositoryName(x) for x in self.repositories]
- self.slot_length = max([len(x) for x in self.slots])
- repositories_length = max([len(x) for x in self.repositories])
- self.keyword_length = len(keywords_list)
- vers =self.VersionChecker(list(zip(packages, self.repositories)))
- self.versions = vers.versions
- masks = vers.masks
- self.version_length = max([len(x) for x in self.versions])
- self.version_count = len(self.versions)
- self.redundant = self.RedundancyChecker(masks, self.keywords, self.slots, ignoreslots).redundant
- redundant_length = max([len(x) for x in self.redundant])
-
- ver = self.__formatVersions(self.versions, content_align, self.version_length)
- kws = self.__formatKeywords(self.keywords, keywords_list, usebold, toplist)
- repos_configs = porttree.repositories.prepos
- eap = self.__formatEapis(self.eapi, self.repositories, repos_configs, 1)
- red = self.__formatAdditional(self.redundant, 'purple', redundant_length)
- slt = self.__formatAdditional(self.slots, 'bold', self.slot_length)
- rep = self.__formatAdditional(self.repositories, 'yellow', repositories_length)
- # those + numbers are spaces in printout. keywords are multiplied also because of that
- linesep = '%s+%s+%s+%s' % (''.ljust(self.version_length+1, '-'),
- ''.ljust(self.keyword_length*2+1, '-'),
- ''.ljust(redundant_length+self.slot_length+1+4, '-'),
- ''.ljust(repositories_length+1, '-')
- )
-
- self.content = self.__prepareContentResult(ver, kws, eap, red, slt, self.slot_length, rep, linesep)
- self.content_length = len(linesep)
- self.cp = port.cpv_getkey(packages[0])
+ class RedundancyChecker:
+ def __listRedundant(self, masks, keywords, ignoreslots, slots):
+ """List all redundant packages."""
+ if ignoreslots:
+ return self.__listRedundantAll(masks, keywords)
+ else:
+ return self.__listRedundantSlots(masks, keywords, slots)
+
+ def __listRedundantSlots(self, masks, keywords, slots):
+ """Search for redundant packages walking per keywords for specified slot."""
+ output = list()
+ zipped = list(zip(masks, keywords, slots))
+ for slot in self.__uniq(slots):
+ ms = list()
+ ks = list()
+ for m, k, s in zipped:
+ if slot == s:
+ ms.append(m)
+ ks.append(k)
+ output.append(self.__compareSelected(ms, ks))
+ # this is required because the list itself is not just one level depth
+ return list("".join(output))
+
+ @staticmethod
+ def __uniq(seq):
+ """Remove all duplicate elements from list."""
+ seen = {}
+ result = []
+ for item in seq:
+ if item in seen:
+ continue
+ seen[item] = 1
+ result.append(item)
+ return result
+
+ @staticmethod
+ def __cleanKeyword(keyword):
+ """Remove masked arches and hardmasks from keywords since we don't care about that."""
+ return [
+ "%s" % x for x in keyword.split() if x != "-*" and not x.startswith("-")
+ ]
+
+ def __listRedundantAll(self, masks, keywords):
+ """Search for redundant packages using all versions ignoring its slotting."""
+ return list(self.__compareSelected(list(masks), list(keywords)))
+
+ def __compareSelected(self, masks, kws):
+ """
+ Rotate over list of keywords and compare each element with others.
+ Selectively remove each already compared list from the remaining keywords.
+ """
+ result = []
+ kws.reverse()
+ masks.reverse()
+ for i in range(len(kws)):
+ kw = kws.pop()
+ masks.pop()
+ if self.__compareKeywordWithRest(kw, kws, masks):
+ result.append("#")
+ else:
+ result.append("o")
+ if len(result) == 0:
+ result.append("o")
+ return "".join(result)
+
+ def __compareKeywordWithRest(self, keyword, keywords, masks):
+ """Compare keywords with list of keywords."""
+ kw = self.__cleanKeyword(keyword)
+ for kwi, mask in zip(keywords, masks):
+ kwi = self.__cleanKeyword(kwi)
+ if kwi and not mask:
+ kw = self.__checkShadow(kw, kwi)
+ if not kw:
+ return True
+ return False
+
+ def __checkShadow(self, old, new):
+ """Check if package version is overshadowed by other package version."""
+ tmp = set(new)
+ tmp.update("~%s" % x for x in new if not x.startswith("~"))
+ return list(set(old).difference(tmp))
+
+ def __init__(self, masks, keywords, slots, ignore_slots=False):
+ """Query all relevant data for redundancy package checking"""
+ self.redundant = self.__listRedundant(masks, keywords, ignore_slots, slots)
+
+ class VersionChecker:
+ def __getVersions(self, packages):
+ """Obtain properly aligned version strings without colors."""
+ revlength = max([len(self.__getRevision(x)) for x, repo in packages])
+ return [self.__separateVersion(x, repo, revlength) for x, repo in packages]
+
+ def __getRevision(self, cpv):
+ """Get revision informations for each package for nice further alignment"""
+ rev = port.catpkgsplit(cpv)[3]
+ return rev if rev != "r0" else ""
+
+ def __separateVersion(self, cpv, repo, revlength):
+ return self.__modifyVersionInfo(
+ cpv, repo, port.versions.cpv_getversion(cpv), revlength
+ )
+
+ def __modifyVersionInfo(self, cpv, repo, pv, revlength):
+ """Prefix and suffix version with string based on whether version is installed or masked and its revision."""
+ mask = self.__getMaskStatus(cpv)
+ install = self.__getInstallStatus(cpv, repo)
+
+ # calculate suffix length
+ currevlen = len(self.__getRevision(cpv))
+ suffixlen = revlength - currevlen
+ # +1 required for the dash in revision
+ if suffixlen != 0 and currevlen == 0:
+ suffixlen = suffixlen + 1
+ suffix = ""
+ for x in range(suffixlen):
+ suffix = "%s " % suffix
+
+ if mask and install:
+ pv = "[M][I]%s%s" % (pv, suffix)
+ elif mask:
+ pv = "[M]%s%s" % (pv, suffix)
+ elif install:
+ pv = "[I]%s%s" % (pv, suffix)
+ else:
+ pv = "%s%s" % (pv, suffix)
+ return pv
+
+ def __getMaskStatus(self, cpv):
+ """Figure out if package is pmasked."""
+ try:
+ if "package.mask" in port.getmaskingstatus(
+ cpv, settings=self.mysettings
+ ):
+ return True
+ except:
+ # occurs when package is not known by portdb
+ # so we consider it unmasked
+ pass
+ return False
+
+ def __getInstallStatus(self, cpv, repo):
+ """Check if package version we test is installed."""
+ return bool(self.vartree.match("=%s::%s" % (cpv, repo)))
+
+ def __init__(self, packages):
+ """Query all relevant data for version data formatting"""
+ self.vartree = port.db[port.root]["vartree"].dbapi
+ self.mysettings = port.config(local_config=False)
+ self.versions = self.__getVersions(packages)
+ self.masks = list(map(lambda x: self.__getMaskStatus(x), packages))
+
+ @staticmethod
+ def __packages_sort(package_content):
+ """
+ Sort packages queried based on version and slot
+ %% pn , repo, slot, eapi, keywords
+ """
+ if len(package_content) > 1:
+ ver_map = {}
+ for cpv in package_content:
+ ver_map[cpv[0]] = "-".join(port.versions.catpkgsplit(cpv[0])[2:])
+
+ def cmp_cpv(cpv1, cpv2):
+ return port.versions.vercmp(ver_map[cpv1[0]], ver_map[cpv2[0]])
+
+ package_content.sort(key=port.util.cmp_sort_key(cmp_cpv))
+
+ def __xmatch(self, pdb, package):
+ """xmatch function that searches for all packages over all repos"""
+ try:
+ mycp = port.dep_expand(package, mydb=pdb, settings=pdb.settings).cp
+ except port.exception.AmbiguousPackageName as Arg:
+ msg_err = 'Ambiguous package name "%s".\n' % package
+ found = "Possibilities: %s" % Arg
+ raise SystemExit("%s%s" % (msg_err, found))
+ except port.exception.InvalidAtom:
+ msg_err = 'No such package "%s"' % package
+ raise SystemExit(msg_err)
+
+ mysplit = mycp.split("/")
+ mypkgs = []
+ for oroot in pdb.porttrees:
+ try:
+ file_list = os.listdir(os.path.join(oroot, mycp))
+ except OSError:
+ continue
+ for x in file_list:
+ pf = x[:-7] if x[-7:] == ".ebuild" else []
+ if pf:
+ ps = port.pkgsplit(pf)
+ if not ps or ps[0] != mysplit[1]:
+ # we got garbage or ebuild with wrong name in the dir
+ continue
+ ver_match = port.versions.ver_regexp.match("-".join(ps[1:]))
+ if ver_match is None or not ver_match.groups():
+ # version is not allowed by portage or unset
+ continue
+ # obtain related data from metadata and append to the pkg list
+ keywords, slot, eapi = self.__getMetadata(
+ pdb, mysplit[0] + "/" + pf, oroot
+ )
+ mypkgs.append([mysplit[0] + "/" + pf, oroot, slot, eapi, keywords])
+
+ self.__packages_sort(mypkgs)
+ return mypkgs
+
+ def __checkExist(self, pdb, package):
+ """Check if specified package even exists."""
+ matches = self.__xmatch(pdb, package)
+ if len(matches) <= 0:
+ msg_err = 'No such package "%s"' % package
+ raise SystemExit(msg_err)
+ return list(zip(*matches))
+
+ @staticmethod
+ def __getMetadata(pdb, package, repo):
+ """Obtain all required metadata from portage auxdb"""
+ try:
+ metadata = pdb.aux_get(package, ["KEYWORDS", "SLOT", "EAPI"], repo)
+ except KeyError:
+ # portage prints out more verbose error for us if we were lucky
+ raise SystemExit("Failed to obtain metadata")
+ return metadata
+
+ def __formatKeywords(
+ self, keywords, keywords_list, usebold=False, toplist="archlist"
+ ):
+ """Loop over all keywords and replace them with nice visual identifier"""
+ # the % is fancy separator, we use it to split keywords for rotation
+ # so we wont loose the empty spaces
+ return [
+ "% %".join(
+ [
+ self.__prepareKeywordChar(
+ arch, i, version.split(), usebold, toplist
+ )
+ for i, arch in enumerate(keywords_list)
+ ]
+ )
+ for version in keywords
+ ]
+
+ @staticmethod
+ def __prepareKeywordChar(arch, field, keywords, usebold=False, toplist="archlist"):
+ """
+ Convert specified keywords for package into their visual replacements.
+ # possibilities:
+ # ~arch -> orange ~
+ # -arch -> red -
+ # arch -> green +
+ # -* -> red *
+ """
+ keys = ["~%s" % arch, "-%s" % arch, "%s" % arch, "-*"]
+ values = [
+ colorize("darkyellow", "~"),
+ colorize("darkred", "-"),
+ colorize("darkgreen", "+"),
+ colorize("darkred", "*"),
+ ]
+ # check what keyword we have
+ # here we cant just append space because it would get stripped later
+ char = colorize("darkgray", "o")
+ for k, v in zip(keys, values):
+ if k in keywords:
+ char = v
+ break
+ if toplist == "archlist" and usebold and (field) % 2 == 0 and char != " ":
+ char = colorize("bold", char)
+ return char
+
+ @staticmethod
+ def __formatVersions(versions, align, length):
+ """Append colors and align keywords properly"""
+ # % are used as separators for further split so we wont loose spaces and coloring
+ tmp = []
+ for pv in versions:
+ pv = align_string(pv, align, length)
+ pv = "%".join(list(pv))
+ if pv.find("[%M%][%I%]") != -1:
+ tmp.append(colorize_string("darkyellow", pv))
+ elif pv.find("[%M%]") != -1:
+ tmp.append(colorize_string("darkred", pv))
+ elif pv.find("[%I%]") != -1:
+ tmp.append(colorize_string("bold", pv))
+ else:
+ tmp.append(pv)
+ return tmp
+
+ @staticmethod
+ def __formatAdditional(additional, color, length):
+ """Align additional items properly"""
+ # % are used as separators for further split so we wont loose spaces and coloring
+ tmp = []
+ for x in additional:
+ tmpc = color
+ x = align_string(x, "left", length)
+ x = "%".join(list(x))
+ if x == "o":
+ # the value is unset so the color is gray
+ tmpc = "darkgray"
+ x = colorize_string(tmpc, x)
+ tmp.append(x)
+ return tmp
+
+ @staticmethod
+ def __formatEapis(eapis, repos, repos_configs, length):
+ """Align eapis items properly"""
+ # % are used as separators for further split so we wont loose spaces and coloring
+ tmp = []
+ for eapi, repo in zip(eapis, repos):
+ tmp_eapi = eapi
+ eapi = align_string(eapi, "left", length)
+ eapi = "%".join(list(eapi))
+ if repos_configs[repo].eapi_is_banned(tmp_eapi):
+ eapi = colorize_string("red", eapi)
+ elif repos_configs[repo].eapi_is_deprecated(tmp_eapi):
+ eapi = colorize_string("yellow", eapi)
+ else:
+ eapi = colorize_string("green", eapi)
+ tmp.append(eapi)
+ return tmp
+
+ @staticmethod
+ def __prepareContentResult(
+ versions, keywords, eapi, redundant, slots, slot_length, repos, linesep
+ ):
+ """Parse version fields into one list with proper separators"""
+ content = []
+ oldslot = ""
+ fieldsep = "% %|% %"
+ normsep = "% %"
+ for v, k, e, r, s, t in zip(versions, keywords, eapi, redundant, slots, repos):
+ if oldslot != s:
+ oldslot = s
+ content.append(linesep)
+ else:
+ s = "%".join(list("".rjust(slot_length)))
+ content.append(
+ "%s%s%s%s%s%s%s%s%s%s%s"
+ % (v, fieldsep, k, fieldsep, e, normsep, r, normsep, s, fieldsep, t)
+ )
+ return content
+
+ def __init__(
+ self,
+ package,
+ keywords_list,
+ porttree,
+ ignoreslots=False,
+ content_align="bottom",
+ usebold=False,
+ toplist="archlist",
+ ):
+ """Query all relevant data from portage databases."""
+ (
+ packages,
+ self.repositories,
+ self.slots,
+ self.eapi,
+ self.keywords,
+ ) = self.__checkExist(porttree, package)
+ # convert repositories from path to name
+ self.repositories = [porttree.getRepositoryName(x) for x in self.repositories]
+ self.slot_length = max([len(x) for x in self.slots])
+ repositories_length = max([len(x) for x in self.repositories])
+ self.keyword_length = len(keywords_list)
+ vers = self.VersionChecker(list(zip(packages, self.repositories)))
+ self.versions = vers.versions
+ masks = vers.masks
+ self.version_length = max([len(x) for x in self.versions])
+ self.version_count = len(self.versions)
+ self.redundant = self.RedundancyChecker(
+ masks, self.keywords, self.slots, ignoreslots
+ ).redundant
+ redundant_length = max([len(x) for x in self.redundant])
+
+ ver = self.__formatVersions(self.versions, content_align, self.version_length)
+ kws = self.__formatKeywords(self.keywords, keywords_list, usebold, toplist)
+ repos_configs = porttree.repositories.prepos
+ eap = self.__formatEapis(self.eapi, self.repositories, repos_configs, 1)
+ red = self.__formatAdditional(self.redundant, "purple", redundant_length)
+ slt = self.__formatAdditional(self.slots, "bold", self.slot_length)
+ rep = self.__formatAdditional(self.repositories, "yellow", repositories_length)
+ # those + numbers are spaces in printout. keywords are multiplied also because of that
+ linesep = "%s+%s+%s+%s" % (
+ "".ljust(self.version_length + 1, "-"),
+ "".ljust(self.keyword_length * 2 + 1, "-"),
+ "".ljust(redundant_length + self.slot_length + 1 + 4, "-"),
+ "".ljust(repositories_length + 1, "-"),
+ )
+
+ self.content = self.__prepareContentResult(
+ ver, kws, eap, red, slt, self.slot_length, rep, linesep
+ )
+ self.content_length = len(linesep)
+ self.cp = port.cpv_getkey(packages[0])