aboutsummaryrefslogtreecommitdiff
path: root/pym
diff options
context:
space:
mode:
authorWolfgang E. Sanyer <WolfgangESanyer@gmail.com>2021-09-20 08:49:15 -0400
committerMatt Turner <mattst88@gentoo.org>2021-09-20 15:51:52 -0700
commitbbcd72b5fe85fe9bbca1913f8aa22077d94e75d0 (patch)
tree64a38c9e94cad7c800fcd1ca7307632f603e1315 /pym
parentequery: Remove leftovers from 'changes' removal (diff)
downloadgentoolkit-bbcd72b5fe85fe9bbca1913f8aa22077d94e75d0.tar.gz
gentoolkit-bbcd72b5fe85fe9bbca1913f8aa22077d94e75d0.tar.bz2
gentoolkit-bbcd72b5fe85fe9bbca1913f8aa22077d94e75d0.zip
Change tabs to spaces (using autopep8). Also, format repo using black.
The following command was used to change the tabs to spaces: autopep8 --in-place --select=E101,E11,E121,E122,E123,E124,E125,E126,E127,E128,E129,E131,E133,E20,E211,E22,E224,E224,E226,E227,E228,E231,E241,E242,E251,E252,E26,E265,E266,E27,E301,E302,E303,E304,E305,E306,W291,W293,W391 -r . And then black was run as `black .` on the entire tree Signed-off-by: Wolfgang E. Sanyer <WolfgangESanyer@gmail.com> Signed-off-by: Matt Turner <mattst88@gentoo.org>
Diffstat (limited to 'pym')
-rw-r--r--pym/gentoolkit/__init__.py10
-rw-r--r--pym/gentoolkit/atom.py626
-rw-r--r--pym/gentoolkit/base.py207
-rw-r--r--pym/gentoolkit/cpv.py400
-rw-r--r--pym/gentoolkit/dbapi.py8
-rw-r--r--pym/gentoolkit/dependencies.py608
-rw-r--r--pym/gentoolkit/eclean/clean.py274
-rw-r--r--pym/gentoolkit/eclean/cli.py1099
-rw-r--r--pym/gentoolkit/eclean/exclude.py483
-rw-r--r--pym/gentoolkit/eclean/output.py354
-rw-r--r--pym/gentoolkit/eclean/pkgindex.py148
-rw-r--r--pym/gentoolkit/eclean/search.py1122
-rwxr-xr-xpym/gentoolkit/ekeyword/ekeyword.py825
-rwxr-xr-xpym/gentoolkit/ekeyword/test_ekeyword.py638
-rw-r--r--pym/gentoolkit/enalyze/__init__.py163
-rw-r--r--pym/gentoolkit/enalyze/analyze.py928
-rw-r--r--pym/gentoolkit/enalyze/lib.py685
-rw-r--r--pym/gentoolkit/enalyze/output.py537
-rw-r--r--pym/gentoolkit/enalyze/rebuild.py708
-rw-r--r--pym/gentoolkit/eprefix.py6
-rw-r--r--pym/gentoolkit/equery/__init__.py556
-rw-r--r--pym/gentoolkit/equery/belongs.py218
-rw-r--r--pym/gentoolkit/equery/check.py453
-rw-r--r--pym/gentoolkit/equery/depends.py325
-rw-r--r--pym/gentoolkit/equery/depgraph.py395
-rw-r--r--pym/gentoolkit/equery/files.py496
-rw-r--r--pym/gentoolkit/equery/has.py326
-rw-r--r--pym/gentoolkit/equery/hasuse.py272
-rw-r--r--pym/gentoolkit/equery/keywords.py5
-rw-r--r--pym/gentoolkit/equery/list_.py424
-rw-r--r--pym/gentoolkit/equery/meta.py955
-rw-r--r--pym/gentoolkit/equery/size.py257
-rw-r--r--pym/gentoolkit/equery/uses.py522
-rw-r--r--pym/gentoolkit/equery/which.py156
-rw-r--r--pym/gentoolkit/errors.py205
-rw-r--r--pym/gentoolkit/eshowkw/__init__.py318
-rw-r--r--pym/gentoolkit/eshowkw/display_pretty.py208
-rw-r--r--pym/gentoolkit/eshowkw/keywords_content.py756
-rw-r--r--pym/gentoolkit/eshowkw/keywords_header.py273
-rw-r--r--pym/gentoolkit/flag.py276
-rw-r--r--pym/gentoolkit/formatters.py223
-rw-r--r--pym/gentoolkit/helpers.py492
-rwxr-xr-xpym/gentoolkit/imlate/imlate.py915
-rw-r--r--pym/gentoolkit/keyword.py180
-rw-r--r--pym/gentoolkit/metadata.py454
-rw-r--r--pym/gentoolkit/module_base.py268
-rw-r--r--pym/gentoolkit/package.py1118
-rw-r--r--pym/gentoolkit/pprinter.py253
-rw-r--r--pym/gentoolkit/profile.py192
-rw-r--r--pym/gentoolkit/query.py720
-rw-r--r--pym/gentoolkit/revdep_rebuild/analyse.py781
-rw-r--r--pym/gentoolkit/revdep_rebuild/assign.py312
-rw-r--r--pym/gentoolkit/revdep_rebuild/cache.py281
-rw-r--r--pym/gentoolkit/revdep_rebuild/collect.py437
-rw-r--r--pym/gentoolkit/revdep_rebuild/rebuild.py266
-rw-r--r--pym/gentoolkit/revdep_rebuild/runner.py93
-rw-r--r--pym/gentoolkit/revdep_rebuild/settings.py299
-rw-r--r--pym/gentoolkit/revdep_rebuild/stuff.py164
-rw-r--r--pym/gentoolkit/sets.py73
-rw-r--r--pym/gentoolkit/test/eclean/creator.py388
-rw-r--r--pym/gentoolkit/test/eclean/distsupport.py885
-rwxr-xr-xpym/gentoolkit/test/eclean/test_clean.py6
-rwxr-xr-xpym/gentoolkit/test/eclean/test_search.py1221
-rw-r--r--pym/gentoolkit/test/equery/test_init.py74
-rw-r--r--pym/gentoolkit/test/test_atom.py250
-rw-r--r--pym/gentoolkit/test/test_cpv.py219
-rw-r--r--pym/gentoolkit/test/test_helpers.py123
-rw-r--r--pym/gentoolkit/test/test_keyword.py91
-rw-r--r--pym/gentoolkit/test/test_profile.py92
-rw-r--r--pym/gentoolkit/test/test_query.py177
-rw-r--r--pym/gentoolkit/test/test_syntax.py38
-rw-r--r--pym/gentoolkit/textwrap_.py180
-rw-r--r--pym/gentoolkit/versionmatch.py209
73 files changed, 14948 insertions, 13751 deletions
diff --git a/pym/gentoolkit/__init__.py b/pym/gentoolkit/__init__.py
index 9af78fc..ab9ce9d 100644
--- a/pym/gentoolkit/__init__.py
+++ b/pym/gentoolkit/__init__.py
@@ -10,14 +10,14 @@ import sys
CONFIG = {
# Color handling: -1: Use Portage settings, 0: Force off, 1: Force on
- 'color': -1,
+ "color": -1,
# Guess piping output:
- 'piping': False if sys.stdout.isatty() else True,
+ "piping": False if sys.stdout.isatty() else True,
# Set some defaults:
- 'quiet': False,
+ "quiet": False,
# verbose is True if not quiet and not piping
- 'verbose': True,
- 'debug': False
+ "verbose": True,
+ "debug": False,
}
# vim: set ts=8 sw=4 tw=79:
diff --git a/pym/gentoolkit/atom.py b/pym/gentoolkit/atom.py
index 364fe4e..dd843d7 100644
--- a/pym/gentoolkit/atom.py
+++ b/pym/gentoolkit/atom.py
@@ -6,7 +6,7 @@
"""Subclasses portage.dep.Atom to provide methods on a Gentoo atom string."""
-__all__ = ('Atom',)
+__all__ = ("Atom",)
# =======
# Imports
@@ -24,319 +24,319 @@ from gentoolkit import errors
# Classes
# =======
+
class Atom(portage.dep.Atom, CPV):
- """Portage's Atom class with improvements from pkgcore.
+ """Portage's Atom class with improvements from pkgcore.
+
+ portage.dep.Atom provides the following instance variables:
+
+ @type operator: str
+ @ivar operator: one of ('=', '=*', '<', '>', '<=', '>=', '~', None)
+ @type cp: str
+ @ivar cp: cat/pkg
+ @type cpv: str
+ @ivar cpv: cat/pkg-ver (if ver)
+ @type slot: str or None (modified to tuple if not None)
+ @ivar slot: slot passed in as cpv:#
+ """
+
+ # Necessary for Portage versions < 2.1.7
+ _atoms = weakref.WeakValueDictionary()
+
+ def __init__(self, atom):
+ self.atom = atom
+ self.operator = self.blocker = self.use = self.slot = None
+
+ try:
+ portage.dep.Atom.__init__(self, atom)
+ except portage.exception.InvalidAtom:
+ raise errors.GentoolkitInvalidAtom(atom)
+
+ # Make operator compatible with intersects
+ if self.operator is None:
+ self.operator = ""
+
+ CPV.__init__(self, self.cpv)
+
+ # use_conditional is USE flag condition for this Atom to be required:
+ # For: !build? ( >=sys-apps/sed-4.0.5 ), use_conditional = '!build'
+ self.use_conditional = None
+
+ def __eq__(self, other):
+ if not isinstance(other, self.__class__):
+ err = "other isn't of %s type, is %s"
+ raise TypeError(err % (self.__class__, other.__class__))
+
+ if self.operator != other.operator:
+ return False
+
+ if not CPV.__eq__(self, other):
+ return False
+
+ if bool(self.blocker) != bool(other.blocker):
+ return False
+
+ if self.blocker and other.blocker:
+ if self.blocker.overlap.forbid != other.blocker.overlap.forbid:
+ return False
+
+ if self.use_conditional != other.use_conditional:
+ return False
+
+ # Don't believe Portage has something like this
+ # c = cmp(self.negate_vers, other.negate_vers)
+ # if c:
+ # return c
+
+ if self.slot != other.slot:
+ return False
+
+ this_use = None
+ if self.use is not None:
+ this_use = sorted(self.use.tokens)
+ that_use = None
+ if other.use is not None:
+ that_use = sorted(other.use.tokens)
+ if this_use != that_use:
+ return False
+
+ # Not supported by Portage Atom yet
+ # return cmp(self.repo_name, other.repo_name)
+ return True
+
+ def __hash__(self):
+ return hash(self.atom)
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __lt__(self, other):
+ if not isinstance(other, self.__class__):
+ err = "other isn't of %s type, is %s"
+ raise TypeError(err % (self.__class__, other.__class__))
+
+ if self.operator != other.operator:
+ return self.operator < other.operator
+
+ if not CPV.__eq__(self, other):
+ return CPV.__lt__(self, other)
+
+ if bool(self.blocker) != bool(other.blocker):
+ # We want non blockers, then blockers, so only return True
+ # if self.blocker is True and other.blocker is False.
+ return bool(self.blocker) > bool(other.blocker)
+
+ if self.blocker and other.blocker:
+ if self.blocker.overlap.forbid != other.blocker.overlap.forbid:
+ # we want !! prior to !
+ return self.blocker.overlap.forbid < other.blocker.overlap.forbid
+
+ # Don't believe Portage has something like this
+ # c = cmp(self.negate_vers, other.negate_vers)
+ # if c:
+ # return c
+
+ if self.slot != other.slot:
+ if self.slot is None:
+ return False
+ elif other.slot is None:
+ return True
+ return self.slot < other.slot
+
+ this_use = []
+ if self.use is not None:
+ this_use = sorted(self.use.tokens)
+ that_use = []
+ if other.use is not None:
+ that_use = sorted(other.use.tokens)
+ if this_use != that_use:
+ return this_use < that_use
+
+ # Not supported by Portage Atom yet
+ # return cmp(self.repo_name, other.repo_name)
+
+ return False
+
+ def __gt__(self, other):
+ if not isinstance(other, self.__class__):
+ err = "other isn't of %s type, is %s"
+ raise TypeError(err % (self.__class__, other.__class__))
+
+ return not self <= other
+
+ def __le__(self, other):
+ if not isinstance(other, self.__class__):
+ raise TypeError(
+ "other isn't of %s type, is %s" % (self.__class__, other.__class__)
+ )
+ return self < other or self == other
+
+ def __ge__(self, other):
+ if not isinstance(other, self.__class__):
+ raise TypeError(
+ "other isn't of %s type, is %s" % (self.__class__, other.__class__)
+ )
+ return self > other or self == other
+
+ def __repr__(self):
+ uc = self.use_conditional
+ uc = "%s? " % uc if uc is not None else ""
+ return "<%s %r>" % (self.__class__.__name__, "%s%s" % (uc, self.atom))
+
+ def __setattr__(self, name, value):
+ object.__setattr__(self, name, value)
+
+ def intersects(self, other):
+ """Check if a passed in package atom "intersects" this atom.
+
+ Lifted from pkgcore.
+
+ Two atoms "intersect" if a package can be constructed that
+ matches both:
+ - if you query for just "dev-lang/python" it "intersects" both
+ "dev-lang/python" and ">=dev-lang/python-2.4"
+ - if you query for "=dev-lang/python-2.4" it "intersects"
+ ">=dev-lang/python-2.4" and "dev-lang/python" but not
+ "<dev-lang/python-2.3"
+
+ @type other: L{gentoolkit.atom.Atom} or
+ L{gentoolkit.versionmatch.VersionMatch}
+ @param other: other package to compare
+ @see: L{pkgcore.ebuild.atom}
+ """
+ # Our "cp" (cat/pkg) must match exactly:
+ if self.cp != other.cp:
+ # Check to see if one is name only:
+ # We don't bother checking if self.category is None: it can't be
+ # because we're an Atom subclass and that would be invalid.
+ return not other.category and self.name == other.name
+
+ # Slot dep only matters if we both have one. If we do they
+ # must be identical:
+ this_slot = getattr(self, "slot", None)
+ that_slot = getattr(other, "slot", None)
+ if this_slot is not None and that_slot is not None and this_slot != that_slot:
+ return False
+
+ if self.repo is not None and other.repo is not None and self.repo != other.repo:
+ return False
+
+ # Use deps are similar: if one of us forces a flag on and the
+ # other forces it off we do not intersect. If only one of us
+ # cares about a flag it is irrelevant.
+
+ # Skip the (very common) case of one of us not having use deps:
+ this_use = getattr(self, "use", None)
+ that_use = getattr(other, "use", None)
+ if this_use and that_use:
+ # Set of flags we do not have in common:
+ flags = set(this_use.tokens) ^ set(that_use.tokens)
+ for flag in flags:
+ # If this is unset and we also have the set version we fail:
+ if flag[0] == "-" and flag[1:] in flags:
+ return False
+
+ # Remaining thing to check is version restrictions. Get the
+ # ones we can check without actual version comparisons out of
+ # the way first.
+
+ # If one of us is unversioned we intersect:
+ if not self.operator or not other.operator:
+ return True
+
+ # If we are both "unbounded" in the same direction we intersect:
+ if ("<" in self.operator and "<" in other.operator) or (
+ ">" in self.operator and ">" in other.operator
+ ):
+ return True
+
+ # If one of us is an exact match we intersect if the other matches it:
+ if self.operator == "=":
+ if other.operator == "=*":
+ return self.fullversion.startswith(other.fullversion)
+ return VersionMatch(other, op=other.operator).match(self)
+ if other.operator == "=":
+ if self.operator == "=*":
+ return other.fullversion.startswith(self.fullversion)
+ return VersionMatch(self, op=self.operator).match(other)
+
+ # If we are both ~ matches we match if we are identical:
+ if self.operator == other.operator == "~":
+ return self.version == other.version and self.revision == other.revision
+
+ # If we are both glob matches we match if one of us matches the other.
+ if self.operator == other.operator == "=*":
+ return self.fullversion.startswith(
+ other.fullversion
+ ) or other.fullversion.startswith(self.fullversion)
+
+ # If one of us is a glob match and the other a ~ we match if the glob
+ # matches the ~ (ignoring a revision on the glob):
+ if self.operator == "=*" and other.operator == "~":
+ return other.fullversion.startswith(self.version)
+ if other.operator == "=*" and self.operator == "~":
+ return self.fullversion.startswith(other.version)
+
+ # If we get here at least one of us is a <, <=, > or >=:
+ if self.operator in ("<", "<=", ">", ">="):
+ ranged, ranged.operator = self, self.operator
+ else:
+ ranged, ranged.operator = other, other.operator
+ other, other.operator = self, self.operator
+
+ if "<" in other.operator or ">" in other.operator:
+ # We are both ranged, and in the opposite "direction" (or
+ # we would have matched above). We intersect if we both
+ # match the other's endpoint (just checking one endpoint
+ # is not enough, it would give a false positive on <=2 vs >2)
+ return VersionMatch(other, op=other.operator).match(
+ ranged
+ ) and VersionMatch(ranged, op=ranged.operator).match(other)
+
+ if other.operator == "~":
+ # Other definitely matches its own version. If ranged also
+ # does we're done:
+ if VersionMatch(ranged, op=ranged.operator).match(other):
+ return True
+ # The only other case where we intersect is if ranged is a
+ # > or >= on other's version and a nonzero revision. In
+ # that case other will match ranged. Be careful not to
+ # give a false positive for ~2 vs <2 here:
+ return ranged.operator in (">", ">=") and VersionMatch(
+ other, op=other.operator
+ ).match(ranged)
+
+ if other.operator == "=*":
+ # a glob match definitely matches its own version, so if
+ # ranged does too we're done:
+ if VersionMatch(ranged, op=ranged.operator).match(other):
+ return True
+ if "<" in ranged.operator:
+ # If other.revision is not defined then other does not
+ # match anything smaller than its own fullversion:
+ if other.revision:
+ return False
+
+ # If other.revision is defined then we can always
+ # construct a package smaller than other.fullversion by
+ # tagging e.g. an _alpha1 on.
+ return ranged.fullversion.startswith(other.version)
+ else:
+ # Remaining cases where this intersects: there is a
+ # package greater than ranged.fullversion and
+ # other.fullversion that they both match.
+ return ranged.fullversion.startswith(other.version)
+
+ # Handled all possible ops.
+ raise NotImplementedError(
+ "Someone added an operator without adding it to intersects"
+ )
+
+ def get_depstr(self):
+ """Returns a string representation of the original dep"""
+ uc = self.use_conditional
+ uc = "%s? " % uc if uc is not None else ""
+ return "%s%s" % (uc, self.atom)
- portage.dep.Atom provides the following instance variables:
-
- @type operator: str
- @ivar operator: one of ('=', '=*', '<', '>', '<=', '>=', '~', None)
- @type cp: str
- @ivar cp: cat/pkg
- @type cpv: str
- @ivar cpv: cat/pkg-ver (if ver)
- @type slot: str or None (modified to tuple if not None)
- @ivar slot: slot passed in as cpv:#
- """
-
- # Necessary for Portage versions < 2.1.7
- _atoms = weakref.WeakValueDictionary()
-
- def __init__(self, atom):
- self.atom = atom
- self.operator = self.blocker = self.use = self.slot = None
-
- try:
- portage.dep.Atom.__init__(self, atom)
- except portage.exception.InvalidAtom:
- raise errors.GentoolkitInvalidAtom(atom)
-
- # Make operator compatible with intersects
- if self.operator is None:
- self.operator = ''
-
- CPV.__init__(self, self.cpv)
-
- # use_conditional is USE flag condition for this Atom to be required:
- # For: !build? ( >=sys-apps/sed-4.0.5 ), use_conditional = '!build'
- self.use_conditional = None
-
- def __eq__(self, other):
- if not isinstance(other, self.__class__):
- err = "other isn't of %s type, is %s"
- raise TypeError(err % (self.__class__, other.__class__))
-
- if self.operator != other.operator:
- return False
-
- if not CPV.__eq__(self, other):
- return False
-
- if bool(self.blocker) != bool(other.blocker):
- return False
-
- if self.blocker and other.blocker:
- if self.blocker.overlap.forbid != other.blocker.overlap.forbid:
- return False
-
- if self.use_conditional != other.use_conditional:
- return False
-
- # Don't believe Portage has something like this
- #c = cmp(self.negate_vers, other.negate_vers)
- #if c:
- # return c
-
- if self.slot != other.slot:
- return False
-
- this_use = None
- if self.use is not None:
- this_use = sorted(self.use.tokens)
- that_use = None
- if other.use is not None:
- that_use = sorted(other.use.tokens)
- if this_use != that_use:
- return False
-
- # Not supported by Portage Atom yet
- #return cmp(self.repo_name, other.repo_name)
- return True
-
- def __hash__(self):
- return hash(self.atom)
-
- def __ne__(self, other):
- return not self == other
-
- def __lt__(self, other):
- if not isinstance(other, self.__class__):
- err = "other isn't of %s type, is %s"
- raise TypeError(err % (self.__class__, other.__class__))
-
- if self.operator != other.operator:
- return self.operator < other.operator
-
- if not CPV.__eq__(self, other):
- return CPV.__lt__(self, other)
-
- if bool(self.blocker) != bool(other.blocker):
- # We want non blockers, then blockers, so only return True
- # if self.blocker is True and other.blocker is False.
- return bool(self.blocker) > bool(other.blocker)
-
- if self.blocker and other.blocker:
- if self.blocker.overlap.forbid != other.blocker.overlap.forbid:
- # we want !! prior to !
- return (self.blocker.overlap.forbid <
- other.blocker.overlap.forbid)
-
- # Don't believe Portage has something like this
- #c = cmp(self.negate_vers, other.negate_vers)
- #if c:
- # return c
-
- if self.slot != other.slot:
- if self.slot is None:
- return False
- elif other.slot is None:
- return True
- return self.slot < other.slot
-
- this_use = []
- if self.use is not None:
- this_use = sorted(self.use.tokens)
- that_use = []
- if other.use is not None:
- that_use = sorted(other.use.tokens)
- if this_use != that_use:
- return this_use < that_use
-
- # Not supported by Portage Atom yet
- #return cmp(self.repo_name, other.repo_name)
-
- return False
-
- def __gt__(self, other):
- if not isinstance(other, self.__class__):
- err = "other isn't of %s type, is %s"
- raise TypeError(err % (self.__class__, other.__class__))
-
- return not self <= other
-
- def __le__(self, other):
- if not isinstance(other, self.__class__):
- raise TypeError("other isn't of %s type, is %s" % (
- self.__class__, other.__class__)
- )
- return self < other or self == other
-
- def __ge__(self, other):
- if not isinstance(other, self.__class__):
- raise TypeError("other isn't of %s type, is %s" % (
- self.__class__, other.__class__)
- )
- return self > other or self == other
-
- def __repr__(self):
- uc = self.use_conditional
- uc = "%s? " % uc if uc is not None else ''
- return "<%s %r>" % (self.__class__.__name__, "%s%s" % (uc, self.atom))
-
- def __setattr__(self, name, value):
- object.__setattr__(self, name, value)
-
- def intersects(self, other):
- """Check if a passed in package atom "intersects" this atom.
-
- Lifted from pkgcore.
-
- Two atoms "intersect" if a package can be constructed that
- matches both:
- - if you query for just "dev-lang/python" it "intersects" both
- "dev-lang/python" and ">=dev-lang/python-2.4"
- - if you query for "=dev-lang/python-2.4" it "intersects"
- ">=dev-lang/python-2.4" and "dev-lang/python" but not
- "<dev-lang/python-2.3"
-
- @type other: L{gentoolkit.atom.Atom} or
- L{gentoolkit.versionmatch.VersionMatch}
- @param other: other package to compare
- @see: L{pkgcore.ebuild.atom}
- """
- # Our "cp" (cat/pkg) must match exactly:
- if self.cp != other.cp:
- # Check to see if one is name only:
- # We don't bother checking if self.category is None: it can't be
- # because we're an Atom subclass and that would be invalid.
- return (not other.category and self.name == other.name)
-
- # Slot dep only matters if we both have one. If we do they
- # must be identical:
- this_slot = getattr(self, 'slot', None)
- that_slot = getattr(other, 'slot', None)
- if (this_slot is not None and that_slot is not None and
- this_slot != that_slot):
- return False
-
- if (self.repo is not None and other.repo is not None and
- self.repo != other.repo):
- return False
-
- # Use deps are similar: if one of us forces a flag on and the
- # other forces it off we do not intersect. If only one of us
- # cares about a flag it is irrelevant.
-
- # Skip the (very common) case of one of us not having use deps:
- this_use = getattr(self, 'use', None)
- that_use = getattr(other, 'use', None)
- if this_use and that_use:
- # Set of flags we do not have in common:
- flags = set(this_use.tokens) ^ set(that_use.tokens)
- for flag in flags:
- # If this is unset and we also have the set version we fail:
- if flag[0] == '-' and flag[1:] in flags:
- return False
-
- # Remaining thing to check is version restrictions. Get the
- # ones we can check without actual version comparisons out of
- # the way first.
-
- # If one of us is unversioned we intersect:
- if not self.operator or not other.operator:
- return True
-
- # If we are both "unbounded" in the same direction we intersect:
- if (('<' in self.operator and '<' in other.operator) or
- ('>' in self.operator and '>' in other.operator)):
- return True
-
- # If one of us is an exact match we intersect if the other matches it:
- if self.operator == '=':
- if other.operator == '=*':
- return self.fullversion.startswith(other.fullversion)
- return VersionMatch(other, op=other.operator).match(self)
- if other.operator == '=':
- if self.operator == '=*':
- return other.fullversion.startswith(self.fullversion)
- return VersionMatch(self, op=self.operator).match(other)
-
- # If we are both ~ matches we match if we are identical:
- if self.operator == other.operator == '~':
- return (self.version == other.version and
- self.revision == other.revision)
-
- # If we are both glob matches we match if one of us matches the other.
- if self.operator == other.operator == '=*':
- return (self.fullversion.startswith(other.fullversion) or
- other.fullversion.startswith(self.fullversion))
-
- # If one of us is a glob match and the other a ~ we match if the glob
- # matches the ~ (ignoring a revision on the glob):
- if self.operator == '=*' and other.operator == '~':
- return other.fullversion.startswith(self.version)
- if other.operator == '=*' and self.operator == '~':
- return self.fullversion.startswith(other.version)
-
- # If we get here at least one of us is a <, <=, > or >=:
- if self.operator in ('<', '<=', '>', '>='):
- ranged, ranged.operator = self, self.operator
- else:
- ranged, ranged.operator = other, other.operator
- other, other.operator = self, self.operator
-
- if '<' in other.operator or '>' in other.operator:
- # We are both ranged, and in the opposite "direction" (or
- # we would have matched above). We intersect if we both
- # match the other's endpoint (just checking one endpoint
- # is not enough, it would give a false positive on <=2 vs >2)
- return (
- VersionMatch(other, op=other.operator).match(ranged) and
- VersionMatch(ranged, op=ranged.operator).match(other)
- )
-
- if other.operator == '~':
- # Other definitely matches its own version. If ranged also
- # does we're done:
- if VersionMatch(ranged, op=ranged.operator).match(other):
- return True
- # The only other case where we intersect is if ranged is a
- # > or >= on other's version and a nonzero revision. In
- # that case other will match ranged. Be careful not to
- # give a false positive for ~2 vs <2 here:
- return (ranged.operator in ('>', '>=') and
- VersionMatch(other, op=other.operator).match(ranged))
-
- if other.operator == '=*':
- # a glob match definitely matches its own version, so if
- # ranged does too we're done:
- if VersionMatch(ranged, op=ranged.operator).match(other):
- return True
- if '<' in ranged.operator:
- # If other.revision is not defined then other does not
- # match anything smaller than its own fullversion:
- if other.revision:
- return False
-
- # If other.revision is defined then we can always
- # construct a package smaller than other.fullversion by
- # tagging e.g. an _alpha1 on.
- return ranged.fullversion.startswith(other.version)
- else:
- # Remaining cases where this intersects: there is a
- # package greater than ranged.fullversion and
- # other.fullversion that they both match.
- return ranged.fullversion.startswith(other.version)
-
- # Handled all possible ops.
- raise NotImplementedError(
- 'Someone added an operator without adding it to intersects')
-
- def get_depstr(self):
- """Returns a string representation of the original dep
- """
- uc = self.use_conditional
- uc = "%s? " % uc if uc is not None else ''
- return "%s%s" % (uc, self.atom)
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/base.py b/pym/gentoolkit/base.py
index 372ed74..8dfa2db 100644
--- a/pym/gentoolkit/base.py
+++ b/pym/gentoolkit/base.py
@@ -6,7 +6,7 @@
"""Gentoolkit Base Module class to hold common module operation functions
"""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
import os
@@ -18,127 +18,132 @@ from gentoolkit.formatters import format_options
GLOBAL_OPTIONS = (
- (" -h, --help", "display this help message"),
- (" -q, --quiet", "minimal output"),
- (" -C, --no-color", "turn off colors"),
- (" -N, --no-pipe", "turn off pipe detection"),
- (" -V, --version", "display version info")
+ (" -h, --help", "display this help message"),
+ (" -q, --quiet", "minimal output"),
+ (" -C, --no-color", "turn off colors"),
+ (" -N, --no-pipe", "turn off pipe detection"),
+ (" -V, --version", "display version info"),
)
def initialize_configuration():
- """Setup the standard equery config"""
-
- # Get terminal size
- term_width = pp.output.get_term_size()[1]
- if term_width < 1:
- # get_term_size() failed. Set a sane default width:
- term_width = 80
- # Terminal size, minus a 1-char margin for text wrapping
- gentoolkit.CONFIG['termWidth'] = term_width - 1
- # Guess color output
- if (gentoolkit.CONFIG['color'] == -1 and (not sys.stdout.isatty() or
- os.getenv("NOCOLOR") in ("yes", "true")) or gentoolkit.CONFIG['color'] == 0):
- pp.output.nocolor()
- gentoolkit.CONFIG['verbose'] = not gentoolkit.CONFIG['piping']
+ """Setup the standard equery config"""
+
+ # Get terminal size
+ term_width = pp.output.get_term_size()[1]
+ if term_width < 1:
+ # get_term_size() failed. Set a sane default width:
+ term_width = 80
+ # Terminal size, minus a 1-char margin for text wrapping
+ gentoolkit.CONFIG["termWidth"] = term_width - 1
+ # Guess color output
+ if (
+ gentoolkit.CONFIG["color"] == -1
+ and (not sys.stdout.isatty() or os.getenv("NOCOLOR") in ("yes", "true"))
+ or gentoolkit.CONFIG["color"] == 0
+ ):
+ pp.output.nocolor()
+ gentoolkit.CONFIG["verbose"] = not gentoolkit.CONFIG["piping"]
def split_arguments(args):
- """Separate module name from module arguments"""
+ """Separate module name from module arguments"""
- return args.pop(0), args
+ return args.pop(0), args
def main_usage(module_info):
- """Return the main usage message for analyse"""
- return "%(usage)s %(product)s [%(g_opts)s] %(mod_name)s [%(mod_opts)s]" % {
- 'usage': pp.emph("Usage:"),
- 'product': pp.productname(module_info["__productname__"]),
- 'g_opts': pp.globaloption("global-options"),
- 'mod_name': pp.command("module-name"),
- 'mod_opts': pp.localoption("module-options")
- }
+ """Return the main usage message for analyse"""
+ return "%(usage)s %(product)s [%(g_opts)s] %(mod_name)s [%(mod_opts)s]" % {
+ "usage": pp.emph("Usage:"),
+ "product": pp.productname(module_info["__productname__"]),
+ "g_opts": pp.globaloption("global-options"),
+ "mod_name": pp.command("module-name"),
+ "mod_opts": pp.localoption("module-options"),
+ }
def print_version(module_info):
- """Print the version of this tool to the console."""
+ """Print the version of this tool to the console."""
- print("%(product)s (%(version)s) - %(docstring)s" % {
- "product": pp.productname(module_info["__productname__"]),
- "version": module_info["__version__"],
- "docstring": module_info["__doc__"]
- })
+ print(
+ "%(product)s (%(version)s) - %(docstring)s"
+ % {
+ "product": pp.productname(module_info["__productname__"]),
+ "version": module_info["__version__"],
+ "docstring": module_info["__doc__"],
+ }
+ )
def print_help(module_info, formatted_options=None, with_description=True):
- """Print description, usage and a detailed help message.
-
- @param with_description (bool): Option to print module's __doc__ or not
- """
-
- if with_description:
- print()
- print(module_info["__doc__"])
- print()
- print(main_usage(module_info))
- print()
- print(pp.globaloption("global options"))
- print(format_options(GLOBAL_OPTIONS))
- print()
- if formatted_options:
- print(pp.command("modules") + " (" + pp.command("short name") + ")")
- print(format_options(formatted_options))
- else:
- print("Error: calling function did not supply formatted options")
- print()
+ """Print description, usage and a detailed help message.
+
+ @param with_description (bool): Option to print module's __doc__ or not
+ """
+
+ if with_description:
+ print()
+ print(module_info["__doc__"])
+ print()
+ print(main_usage(module_info))
+ print()
+ print(pp.globaloption("global options"))
+ print(format_options(GLOBAL_OPTIONS))
+ print()
+ if formatted_options:
+ print(pp.command("modules") + " (" + pp.command("short name") + ")")
+ print(format_options(formatted_options))
+ else:
+ print("Error: calling function did not supply formatted options")
+ print()
def parse_global_options(global_opts, args, module_info, formatted_options):
- """Parse global input args and return True if we should display help for
- the called module, else False (or display help and exit from here).
- """
-
- need_help = False
- do_help = False
- opts = (opt[0] for opt in global_opts)
- for opt in opts:
- if opt in ('-h', '--help'):
- do_help = True
- if args:
- need_help = True
- else:
- do_help = True
- elif opt in ('-q','--quiet'):
- gentoolkit.CONFIG['quiet'] = True
- elif opt in ('-C', '--no-color', '--nocolor'):
- gentoolkit.CONFIG['color'] = 0
- pp.output.nocolor()
- elif opt in ('-N', '--no-pipe'):
- gentoolkit.CONFIG['piping'] = False
- elif opt in ('-V', '--version'):
- print_version(module_info)
- sys.exit(0)
- elif opt in ('--debug'):
- gentoolkit.CONFIG['debug'] = True
- if do_help:
- print_help( module_info, formatted_options)
- sys.exit(0)
- return need_help
+ """Parse global input args and return True if we should display help for
+ the called module, else False (or display help and exit from here).
+ """
+
+ need_help = False
+ do_help = False
+ opts = (opt[0] for opt in global_opts)
+ for opt in opts:
+ if opt in ("-h", "--help"):
+ do_help = True
+ if args:
+ need_help = True
+ else:
+ do_help = True
+ elif opt in ("-q", "--quiet"):
+ gentoolkit.CONFIG["quiet"] = True
+ elif opt in ("-C", "--no-color", "--nocolor"):
+ gentoolkit.CONFIG["color"] = 0
+ pp.output.nocolor()
+ elif opt in ("-N", "--no-pipe"):
+ gentoolkit.CONFIG["piping"] = False
+ elif opt in ("-V", "--version"):
+ print_version(module_info)
+ sys.exit(0)
+ elif opt in ("--debug"):
+ gentoolkit.CONFIG["debug"] = True
+ if do_help:
+ print_help(module_info, formatted_options)
+ sys.exit(0)
+ return need_help
def mod_usage(mod_name="module", arg="pkgspec", optional=False):
- """Provide a consistant usage message to the calling module.
-
- @type arg: string
- @param arg: what kind of argument the module takes (pkgspec, filename, etc)
- @type optional: bool
- @param optional: is the argument optional?
- """
-
- return "%(usage)s: %(mod_name)s [%(opts)s] %(arg)s" % {
- 'usage': pp.emph("Usage"),
- 'mod_name': pp.command(mod_name),
- 'opts': pp.localoption("options"),
- 'arg': ("[%s]" % pp.emph(arg)) if optional else pp.emph(arg)
- }
-
+ """Provide a consistant usage message to the calling module.
+
+ @type arg: string
+ @param arg: what kind of argument the module takes (pkgspec, filename, etc)
+ @type optional: bool
+ @param optional: is the argument optional?
+ """
+
+ return "%(usage)s: %(mod_name)s [%(opts)s] %(arg)s" % {
+ "usage": pp.emph("Usage"),
+ "mod_name": pp.command(mod_name),
+ "opts": pp.localoption("options"),
+ "arg": ("[%s]" % pp.emph(arg)) if optional else pp.emph(arg),
+ }
diff --git a/pym/gentoolkit/cpv.py b/pym/gentoolkit/cpv.py
index 5238e24..6b2a533 100644
--- a/pym/gentoolkit/cpv.py
+++ b/pym/gentoolkit/cpv.py
@@ -6,11 +6,7 @@
"""Provides attributes and methods for a category/package-version string."""
-__all__ = (
- 'CPV',
- 'compare_strs',
- 'split_cpv'
-)
+__all__ = ("CPV", "compare_strs", "split_cpv")
# =======
# Imports
@@ -26,228 +22,232 @@ from gentoolkit import errors
# Globals
# =======
-isvalid_version_re = re.compile(r"^(?:cvs\.)?(?:\d+)(?:\.\d+)*[a-z]?"
- r"(?:_(p(?:re)?|beta|alpha|rc)\d*)*$")
+isvalid_version_re = re.compile(
+ r"^(?:cvs\.)?(?:\d+)(?:\.\d+)*[a-z]?" r"(?:_(p(?:re)?|beta|alpha|rc)\d*)*$"
+)
isvalid_cat_re = re.compile(r"^(?:[a-zA-Z0-9][-a-zA-Z0-9+._]*(?:/(?!$))?)+$")
_pkg_re = re.compile(r"^[a-zA-Z0-9+._]+$")
# Prefix specific revision is of the form -r0<digit>+.<digit>+
-isvalid_rev_re = re.compile(r'(\d+|0\d+\.\d+)')
+isvalid_rev_re = re.compile(r"(\d+|0\d+\.\d+)")
# =======
# Classes
# =======
+
class CPV:
- """Provides methods on a category/package-version string.
-
- Will also correctly split just a package or package-version string.
-
- Example usage:
- >>> from gentoolkit.cpv import CPV
- >>> cpv = CPV('sys-apps/portage-2.2-r1')
- >>> cpv.category, cpv.name, cpv.fullversion
- ('sys-apps', 'portage', '2.2-r1')
- >>> str(cpv)
- 'sys-apps/portage-2.2-r1'
- >>> # An 'rc' (release candidate) version is less than non 'rc' version:
- ... CPV('sys-apps/portage-2') > CPV('sys-apps/portage-2_rc10')
- True
- """
-
- def __init__(self, cpv, validate=False):
- self.cpv = cpv
- self._category = None
- self._name = None
- self._version = None
- self._revision = None
- self._cp = None
- self._fullversion = None
-
- self.validate = validate
- if validate and not self.name:
- raise errors.GentoolkitInvalidCPV(cpv)
-
- @property
- def category(self):
- if self._category is None:
- self._set_cpv_chunks()
- return self._category
-
- @property
- def name(self):
- if self._name is None:
- self._set_cpv_chunks()
- return self._name
-
- @property
- def version(self):
- if self._version is None:
- self._set_cpv_chunks()
- return self._version
-
- @property
- def revision(self):
- if self._revision is None:
- self._set_cpv_chunks()
- return self._revision
-
- @property
- def cp(self):
- if self._cp is None:
- sep = '/' if self.category else ''
- self._cp = sep.join((self.category, self.name))
- return self._cp
-
- @property
- def fullversion(self):
- if self._fullversion is None:
- sep = '-' if self.revision else ''
- self._fullversion = sep.join((self.version, self.revision))
- return self._fullversion
-
- def _set_cpv_chunks(self):
- chunks = split_cpv(self.cpv, validate=self.validate)
- self._category = chunks[0]
- self._name = chunks[1]
- self._version = chunks[2]
- self._revision = chunks[3]
-
- def __eq__(self, other):
- if not isinstance(other, self.__class__):
- return False
- return self.cpv == other.cpv
-
- def __hash__(self):
- return hash(self.cpv)
-
- def __ne__(self, other):
- return not self == other
-
- def __lt__(self, other):
- if not isinstance(other, self.__class__):
- raise TypeError("other isn't of %s type, is %s" % (
- self.__class__, other.__class__)
- )
-
- if self.category != other.category:
- return self.category < other.category
- elif self.name != other.name:
- return self.name < other.name
- else:
- # FIXME: this cmp() hack is for vercmp not using -1,0,1
- # See bug 266493; this was fixed in portage-2.2_rc31
- #return vercmp(self.fullversion, other.fullversion)
- return vercmp(self.fullversion, other.fullversion) < 0
-
- def __gt__(self, other):
- if not isinstance(other, self.__class__):
- raise TypeError("other isn't of %s type, is %s" % (
- self.__class__, other.__class__)
- )
- return not self <= other
-
- def __le__(self, other):
- if not isinstance(other, self.__class__):
- raise TypeError("other isn't of %s type, is %s" % (
- self.__class__, other.__class__)
- )
- return self < other or self == other
-
- def __ge__(self, other):
- if not isinstance(other, self.__class__):
- raise TypeError("other isn't of %s type, is %s" % (
- self.__class__, other.__class__)
- )
- return self > other or self == other
-
- def __repr__(self):
- return "<%s %r>" % (self.__class__.__name__, str(self))
-
- def __str__(self):
- return self.cpv
+ """Provides methods on a category/package-version string.
+
+ Will also correctly split just a package or package-version string.
+
+ Example usage:
+ >>> from gentoolkit.cpv import CPV
+ >>> cpv = CPV('sys-apps/portage-2.2-r1')
+ >>> cpv.category, cpv.name, cpv.fullversion
+ ('sys-apps', 'portage', '2.2-r1')
+ >>> str(cpv)
+ 'sys-apps/portage-2.2-r1'
+ >>> # An 'rc' (release candidate) version is less than non 'rc' version:
+ ... CPV('sys-apps/portage-2') > CPV('sys-apps/portage-2_rc10')
+ True
+ """
+
+ def __init__(self, cpv, validate=False):
+ self.cpv = cpv
+ self._category = None
+ self._name = None
+ self._version = None
+ self._revision = None
+ self._cp = None
+ self._fullversion = None
+
+ self.validate = validate
+ if validate and not self.name:
+ raise errors.GentoolkitInvalidCPV(cpv)
+
+ @property
+ def category(self):
+ if self._category is None:
+ self._set_cpv_chunks()
+ return self._category
+
+ @property
+ def name(self):
+ if self._name is None:
+ self._set_cpv_chunks()
+ return self._name
+
+ @property
+ def version(self):
+ if self._version is None:
+ self._set_cpv_chunks()
+ return self._version
+
+ @property
+ def revision(self):
+ if self._revision is None:
+ self._set_cpv_chunks()
+ return self._revision
+
+ @property
+ def cp(self):
+ if self._cp is None:
+ sep = "/" if self.category else ""
+ self._cp = sep.join((self.category, self.name))
+ return self._cp
+
+ @property
+ def fullversion(self):
+ if self._fullversion is None:
+ sep = "-" if self.revision else ""
+ self._fullversion = sep.join((self.version, self.revision))
+ return self._fullversion
+
+ def _set_cpv_chunks(self):
+ chunks = split_cpv(self.cpv, validate=self.validate)
+ self._category = chunks[0]
+ self._name = chunks[1]
+ self._version = chunks[2]
+ self._revision = chunks[3]
+
+ def __eq__(self, other):
+ if not isinstance(other, self.__class__):
+ return False
+ return self.cpv == other.cpv
+
+ def __hash__(self):
+ return hash(self.cpv)
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __lt__(self, other):
+ if not isinstance(other, self.__class__):
+ raise TypeError(
+ "other isn't of %s type, is %s" % (self.__class__, other.__class__)
+ )
+
+ if self.category != other.category:
+ return self.category < other.category
+ elif self.name != other.name:
+ return self.name < other.name
+ else:
+ # FIXME: this cmp() hack is for vercmp not using -1,0,1
+ # See bug 266493; this was fixed in portage-2.2_rc31
+ # return vercmp(self.fullversion, other.fullversion)
+ return vercmp(self.fullversion, other.fullversion) < 0
+
+ def __gt__(self, other):
+ if not isinstance(other, self.__class__):
+ raise TypeError(
+ "other isn't of %s type, is %s" % (self.__class__, other.__class__)
+ )
+ return not self <= other
+
+ def __le__(self, other):
+ if not isinstance(other, self.__class__):
+ raise TypeError(
+ "other isn't of %s type, is %s" % (self.__class__, other.__class__)
+ )
+ return self < other or self == other
+
+ def __ge__(self, other):
+ if not isinstance(other, self.__class__):
+ raise TypeError(
+ "other isn't of %s type, is %s" % (self.__class__, other.__class__)
+ )
+ return self > other or self == other
+
+ def __repr__(self):
+ return "<%s %r>" % (self.__class__.__name__, str(self))
+
+ def __str__(self):
+ return self.cpv
# =========
# Functions
# =========
+
def compare_strs(pkg1, pkg2):
- """Similar to the builtin cmp, but for package strings. Usually called
- as: package_list.sort(cpv.compare_strs)
+ """Similar to the builtin cmp, but for package strings. Usually called
+ as: package_list.sort(cpv.compare_strs)
- An alternative is to use the CPV descriptor from gentoolkit.cpv:
- >>> package_list = ['sys-apps/portage-9999', 'media-video/ffmpeg-9999']
- >>> cpvs = sorted(CPV(x) for x in package_list)
+ An alternative is to use the CPV descriptor from gentoolkit.cpv:
+ >>> package_list = ['sys-apps/portage-9999', 'media-video/ffmpeg-9999']
+ >>> cpvs = sorted(CPV(x) for x in package_list)
- @see: >>> help(cmp)
- """
+ @see: >>> help(cmp)
+ """
- pkg1 = catpkgsplit(pkg1)
- pkg2 = catpkgsplit(pkg2)
- if pkg1[0] != pkg2[0]:
- return -1 if pkg1[0] < pkg2[0] else 1
- elif pkg1[1] != pkg2[1]:
- return -1 if pkg1[1] < pkg2[1] else 1
- else:
- return pkgcmp(pkg1[1:], pkg2[1:])
+ pkg1 = catpkgsplit(pkg1)
+ pkg2 = catpkgsplit(pkg2)
+ if pkg1[0] != pkg2[0]:
+ return -1 if pkg1[0] < pkg2[0] else 1
+ elif pkg1[1] != pkg2[1]:
+ return -1 if pkg1[1] < pkg2[1] else 1
+ else:
+ return pkgcmp(pkg1[1:], pkg2[1:])
def split_cpv(cpv, validate=True):
- """Split a cpv into category, name, version and revision.
-
- Modified from pkgcore.ebuild.cpv
-
- @type cpv: str
- @param cpv: pkg, cat/pkg, pkg-ver, cat/pkg-ver
- @rtype: tuple
- @return: (category, pkg_name, version, revision)
- Each tuple element is a string or empty string ("").
- """
-
- category = name = version = revision = ''
-
- try:
- category, pkgver = cpv.rsplit("/", 1)
- except ValueError:
- pkgver = cpv
- if validate and category and not isvalid_cat_re.match(category):
- raise errors.GentoolkitInvalidCPV(cpv)
- pkg_chunks = pkgver.split("-")
- lpkg_chunks = len(pkg_chunks)
- if lpkg_chunks == 1:
- return (category, pkg_chunks[0], version, revision)
- if isvalid_rev(pkg_chunks[-1]):
- if lpkg_chunks < 3:
- # needs at least ('pkg', 'ver', 'rev')
- raise errors.GentoolkitInvalidCPV(cpv)
- rev = pkg_chunks.pop(-1)
- if rev:
- revision = rev
-
- if isvalid_version_re.match(pkg_chunks[-1]):
- version = pkg_chunks.pop(-1)
-
- if not isvalid_pkg_name(pkg_chunks):
- raise errors.GentoolkitInvalidCPV(cpv)
- name = '-'.join(pkg_chunks)
-
- return (category, name, version, revision)
+ """Split a cpv into category, name, version and revision.
+
+ Modified from pkgcore.ebuild.cpv
+
+ @type cpv: str
+ @param cpv: pkg, cat/pkg, pkg-ver, cat/pkg-ver
+ @rtype: tuple
+ @return: (category, pkg_name, version, revision)
+ Each tuple element is a string or empty string ("").
+ """
+
+ category = name = version = revision = ""
+
+ try:
+ category, pkgver = cpv.rsplit("/", 1)
+ except ValueError:
+ pkgver = cpv
+ if validate and category and not isvalid_cat_re.match(category):
+ raise errors.GentoolkitInvalidCPV(cpv)
+ pkg_chunks = pkgver.split("-")
+ lpkg_chunks = len(pkg_chunks)
+ if lpkg_chunks == 1:
+ return (category, pkg_chunks[0], version, revision)
+ if isvalid_rev(pkg_chunks[-1]):
+ if lpkg_chunks < 3:
+ # needs at least ('pkg', 'ver', 'rev')
+ raise errors.GentoolkitInvalidCPV(cpv)
+ rev = pkg_chunks.pop(-1)
+ if rev:
+ revision = rev
+
+ if isvalid_version_re.match(pkg_chunks[-1]):
+ version = pkg_chunks.pop(-1)
+
+ if not isvalid_pkg_name(pkg_chunks):
+ raise errors.GentoolkitInvalidCPV(cpv)
+ name = "-".join(pkg_chunks)
+
+ return (category, name, version, revision)
def isvalid_pkg_name(chunks):
- if not chunks[0]:
- # this means a leading -
- return False
- mf = _pkg_re.match
- if not all(not s or mf(s) for s in chunks):
- return False
- if len(chunks) > 1 and chunks[-1].isdigit():
- # not allowed.
- return False
- return True
+ if not chunks[0]:
+ # this means a leading -
+ return False
+ mf = _pkg_re.match
+ if not all(not s or mf(s) for s in chunks):
+ return False
+ if len(chunks) > 1 and chunks[-1].isdigit():
+ # not allowed.
+ return False
+ return True
def isvalid_rev(s):
- return s and s[0] == 'r' and isvalid_rev_re.match(s[1:])
+ return s and s[0] == "r" and isvalid_rev_re.match(s[1:])
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/dbapi.py b/pym/gentoolkit/dbapi.py
index be37f32..9e480f8 100644
--- a/pym/gentoolkit/dbapi.py
+++ b/pym/gentoolkit/dbapi.py
@@ -9,14 +9,16 @@
take advantage of them being lazy-loaded.
"""
-print("gentoolkit.dbapi is deprecated.\n",
- "Please migrate to using the assigned calls directly")
+print(
+ "gentoolkit.dbapi is deprecated.\n",
+ "Please migrate to using the assigned calls directly",
+)
import portage
BINDB = portage.db[portage.root]["bintree"].dbapi
PORTDB = portage.db[portage.root]["porttree"].dbapi
VARDB = portage.db[portage.root]["vartree"].dbapi
-#virtuals = portage.db[portage.root]["virtuals"]
+# virtuals = portage.db[portage.root]["virtuals"]
# vim: set ts=8 sw=4 tw=79:
diff --git a/pym/gentoolkit/dependencies.py b/pym/gentoolkit/dependencies.py
index 38676a2..f94b82e 100644
--- a/pym/gentoolkit/dependencies.py
+++ b/pym/gentoolkit/dependencies.py
@@ -4,8 +4,8 @@
"""Provides a class for easy calculating dependencies for a given CPV."""
-__docformat__ = 'epytext'
-__all__ = ('Dependencies',)
+__docformat__ = "epytext"
+__all__ = ("Dependencies",)
# =======
# Imports
@@ -23,302 +23,314 @@ from gentoolkit.query import Query
# Classes
# =======
+
class Dependencies(Query):
- """Access a package's dependencies and reverse dependencies.
-
- Example usage:
- >>> from gentoolkit.dependencies import Dependencies
- >>> portage = Dependencies('sys-apps/portage-9999')
- >>> portage
- <Dependencies 'sys-apps/portage-9999'>
- >>> # All methods return gentoolkit.atom.Atom instances
- ... portage.get_depend()
- ... # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
- [<Atom 'python3? =dev-lang/python-3*'>,
- <Atom '!python3? >=dev-lang/python-2.7'>, ...]
-
- """
- def __init__(self, query, parser=None):
- Query.__init__(self, query)
- self.use = []
- self.depatom = str()
-
- # Allow a custom parser function:
- self.parser = parser if parser else self._parser
-
- def __eq__(self, other):
- if self.atom != other.atom:
- return False
- else:
- return True
-
- def __ne__(self, other):
- return not self == other
-
- def __hash__(self):
- return hash((self.atom, self.depatom, tuple(self.use)))
-
- def __repr__(self):
- return "<%s %r>" % (self.__class__.__name__, self.atom)
-
- def environment(self, envvars):
- """Returns predefined env vars DEPEND, SRC_URI, etc."""
-
- # Try to use the Portage tree first, since emerge only uses the tree
- # when calculating dependencies
- try:
- result = portage.db[portage.root]["porttree"].dbapi.aux_get(self.cpv, envvars)
- except KeyError:
- try:
- result = portage.db[portage.root]["vartree"].dbapi.aux_get(self.cpv, envvars)
- except KeyError:
- return []
- return result
-
- def _get_depend(self, env_vars, raw=False):
- raw_depend = ' '.join(self.environment(env_vars))
- if raw:
- return raw_depend
- try:
- return self.parser(raw_depend)
- except portage.exception.InvalidPackageName as err:
- raise errors.GentoolkitInvalidCPV(err)
-
- def get_depend(self, **kwargs):
- """Get the contents of DEPEND and parse it with self.parser."""
- return self._get_depend(('DEPEND', ), **kwargs)
-
- def get_pdepend(self, **kwargs):
- """Get the contents of PDEPEND and parse it with self.parser."""
- return self._get_depend(('PDEPEND', ), **kwargs)
-
- def get_rdepend(self, **kwargs):
- """Get the contents of RDEPEND and parse it with self.parser."""
- return self._get_depend(('RDEPEND', ), **kwargs)
-
- def get_all_depends(self, **kwargs):
- """Get the contents of ?DEPEND and parse it with self.parser."""
- env_vars = ('DEPEND', 'PDEPEND', 'RDEPEND', 'BDEPEND')
- return self._get_depend(env_vars, **kwargs)
-
- def graph_depends(
- self,
- max_depth=1,
- printer_fn=None,
- # The rest of these are only used internally:
- depth=1,
- seen=None,
- depcache=None,
- result=None
- ):
- """Graph direct dependencies for self.
-
- Optionally gather indirect dependencies.
-
- @type max_depth: int
- @keyword max_depth: Maximum depth to recurse if.
- <1 means no maximum depth
- >0 means recurse only this depth;
- @type printer_fn: callable
- @keyword printer_fn: If None, no effect. If set, it will be applied to
- each result.
- @rtype: list
- @return: [(depth, pkg), ...]
- """
- if seen is None:
- seen = set()
- if depcache is None:
- depcache = dict()
- if result is None:
- result = list()
-
- pkgdep = None
- deps = self.get_all_depends()
- for dep in deps:
- if dep.atom in depcache:
- continue
- try:
- pkgdep = depcache[dep.atom]
- except KeyError:
- pkgdep = Query(dep.atom).find_best()
- depcache[dep.atom] = pkgdep
- if not pkgdep:
- continue
- elif pkgdep.cpv in seen:
- continue
- if depth <= max_depth or max_depth == 0:
- if printer_fn is not None:
- printer_fn(depth, pkgdep, dep)
- result.append((depth,pkgdep))
-
- seen.add(pkgdep.cpv)
- if depth < max_depth or max_depth == 0:
- # result is passed in and added to directly
- # so rdeps is disposable
- rdeps = pkgdep.deps.graph_depends( # noqa
- max_depth=max_depth,
- printer_fn=printer_fn,
- # The rest of these are only used internally:
- depth=depth+1,
- seen=seen,
- depcache=depcache,
- result=result
- )
- return result
-
- def graph_reverse_depends(
- self,
- pkgset=None,
- max_depth=-1,
- only_direct=True,
- printer_fn=None,
- # The rest of these are only used internally:
- depth=0,
- depcache=None,
- seen=None,
- result=None
- ):
- """Graph direct reverse dependencies for self.
-
- Example usage:
- >>> from gentoolkit.dependencies import Dependencies
- >>> ffmpeg = Dependencies('media-video/ffmpeg-9999')
- >>> # I only care about installed packages that depend on me:
- ... from gentoolkit.helpers import get_installed_cpvs
- >>> # I want to pass in a sorted list. We can pass strings or
- ... # Package or Atom types, so I'll use Package to sort:
- ... from gentoolkit.package import Package
- >>> installed = sorted(get_installed_cpvs())
- >>> deptree = ffmpeg.graph_reverse_depends(
- ... only_direct=False, # Include indirect revdeps
- ... pkgset=installed) # from installed pkgset
- >>> len(deptree)
- 24
-
- @type pkgset: iterable
- @keyword pkgset: sorted pkg cpv strings or anything sublassing
- L{gentoolkit.cpv.CPV} to use for calculate our revdep graph.
- @type max_depth: int
- @keyword max_depth: Maximum depth to recurse if only_direct=False.
- -1 means no maximum depth;
- 0 is the same as only_direct=True;
- >0 means recurse only this many times;
- @type only_direct: bool
- @keyword only_direct: to recurse or not to recurse
- @type printer_fn: callable
- @keyword printer_fn: If None, no effect. If set, it will be applied to
- each L{gentoolkit.atom.Atom} object as it is added to the results.
- @rtype: list
- @return: L{gentoolkit.dependencies.Dependencies} objects
- """
- if not pkgset:
- err = ("%s kwarg 'pkgset' must be set. "
- "Can be list of cpv strings or any 'intersectable' object.")
- raise errors.GentoolkitFatalError(err % (self.__class__.__name__,))
-
- if depcache is None:
- depcache = dict()
- if seen is None:
- seen = set()
- if result is None:
- result = list()
-
- if depth == 0:
- pkgset = tuple(Dependencies(x) for x in pkgset)
-
- pkgdep = None
- for pkgdep in pkgset:
- raw_depends = pkgdep.get_all_depends(raw=True)
- if self.cp not in raw_depends:
- # fast path for obviously non-matching packages. This saves
- # us the work of instantiating a whole Atom() for *every*
- # dependency of *every* package in pkgset.
- continue
- try:
- all_depends = depcache[pkgdep]
- except KeyError:
- all_depends = uniqify(pkgdep.get_all_depends())
- depcache[pkgdep] = all_depends
-
- dep_is_displayed = False
- for dep in all_depends:
- # TODO: Add ability to determine if dep is enabled by USE flag.
- # Check portage.dep.use_reduce
- if dep.intersects(self):
- pkgdep.depth = depth
- pkgdep.matching_dep = dep
- if printer_fn is not None:
- printer_fn(pkgdep, dep_is_displayed=dep_is_displayed)
- result.append(pkgdep)
- dep_is_displayed = True
-
- # if --indirect specified, call ourselves again with the dep
- # Do not call if we have already called ourselves.
- if (
- dep_is_displayed and not only_direct and
- pkgdep.cpv not in seen and
- (depth < max_depth or max_depth == -1)
- ):
-
- seen.add(pkgdep.cpv)
- result.append(
- pkgdep.graph_reverse_depends(
- pkgset=pkgset,
- max_depth=max_depth,
- only_direct=only_direct,
- printer_fn=printer_fn,
- depth=depth+1,
- depcache=depcache,
- seen=seen,
- result=result
- )
- )
-
- if depth == 0:
- return result
- return pkgdep
-
- def _parser(self, deps, use_conditional=None, depth=0):
- """?DEPEND file parser.
-
- @rtype: list
- @return: L{gentoolkit.atom.Atom} objects
- """
- result = []
-
- if depth == 0:
- deps = paren_reduce(deps)
- for tok in deps:
- if tok == '||':
- continue
- if tok[-1] == '?':
- use_conditional = tok[:-1]
- continue
- if isinstance(tok, list):
- sub_r = self._parser(tok, use_conditional, depth=depth+1)
- result.extend(sub_r)
- use_conditional = None
- continue
- # FIXME: This is a quick fix for bug #299260.
- # A better fix is to not discard blockers in the parser,
- # but to check for atom.blocker in whatever equery/depends
- # (in this case) and ignore them there.
- # TODO: Test to see how much a performance impact ignoring
- # blockers here rather than checking for atom.blocker has.
- if tok[0] == '!':
- # We're not interested in blockers
- continue
- # skip it if it's empty
- if tok and tok != '':
- atom = Atom(tok)
- if use_conditional is not None:
- atom.use_conditional = use_conditional
- result.append(atom)
- else:
- message = "dependencies.py: _parser() found an empty " +\
- "dep string token for: %s, deps= %s"
- raise errors.GentoolkitInvalidAtom(message %(self.cpv, deps))
-
- return result
+ """Access a package's dependencies and reverse dependencies.
+
+ Example usage:
+ >>> from gentoolkit.dependencies import Dependencies
+ >>> portage = Dependencies('sys-apps/portage-9999')
+ >>> portage
+ <Dependencies 'sys-apps/portage-9999'>
+ >>> # All methods return gentoolkit.atom.Atom instances
+ ... portage.get_depend()
+ ... # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
+ [<Atom 'python3? =dev-lang/python-3*'>,
+ <Atom '!python3? >=dev-lang/python-2.7'>, ...]
+
+ """
+
+ def __init__(self, query, parser=None):
+ Query.__init__(self, query)
+ self.use = []
+ self.depatom = str()
+
+ # Allow a custom parser function:
+ self.parser = parser if parser else self._parser
+
+ def __eq__(self, other):
+ if self.atom != other.atom:
+ return False
+ else:
+ return True
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash((self.atom, self.depatom, tuple(self.use)))
+
+ def __repr__(self):
+ return "<%s %r>" % (self.__class__.__name__, self.atom)
+
+ def environment(self, envvars):
+ """Returns predefined env vars DEPEND, SRC_URI, etc."""
+
+ # Try to use the Portage tree first, since emerge only uses the tree
+ # when calculating dependencies
+ try:
+ result = portage.db[portage.root]["porttree"].dbapi.aux_get(
+ self.cpv, envvars
+ )
+ except KeyError:
+ try:
+ result = portage.db[portage.root]["vartree"].dbapi.aux_get(
+ self.cpv, envvars
+ )
+ except KeyError:
+ return []
+ return result
+
+ def _get_depend(self, env_vars, raw=False):
+ raw_depend = " ".join(self.environment(env_vars))
+ if raw:
+ return raw_depend
+ try:
+ return self.parser(raw_depend)
+ except portage.exception.InvalidPackageName as err:
+ raise errors.GentoolkitInvalidCPV(err)
+
+ def get_depend(self, **kwargs):
+ """Get the contents of DEPEND and parse it with self.parser."""
+ return self._get_depend(("DEPEND",), **kwargs)
+
+ def get_pdepend(self, **kwargs):
+ """Get the contents of PDEPEND and parse it with self.parser."""
+ return self._get_depend(("PDEPEND",), **kwargs)
+
+ def get_rdepend(self, **kwargs):
+ """Get the contents of RDEPEND and parse it with self.parser."""
+ return self._get_depend(("RDEPEND",), **kwargs)
+
+ def get_all_depends(self, **kwargs):
+ """Get the contents of ?DEPEND and parse it with self.parser."""
+ env_vars = ("DEPEND", "PDEPEND", "RDEPEND", "BDEPEND")
+ return self._get_depend(env_vars, **kwargs)
+
+ def graph_depends(
+ self,
+ max_depth=1,
+ printer_fn=None,
+ # The rest of these are only used internally:
+ depth=1,
+ seen=None,
+ depcache=None,
+ result=None,
+ ):
+ """Graph direct dependencies for self.
+
+ Optionally gather indirect dependencies.
+
+ @type max_depth: int
+ @keyword max_depth: Maximum depth to recurse if.
+ <1 means no maximum depth
+ >0 means recurse only this depth;
+ @type printer_fn: callable
+ @keyword printer_fn: If None, no effect. If set, it will be applied to
+ each result.
+ @rtype: list
+ @return: [(depth, pkg), ...]
+ """
+ if seen is None:
+ seen = set()
+ if depcache is None:
+ depcache = dict()
+ if result is None:
+ result = list()
+
+ pkgdep = None
+ deps = self.get_all_depends()
+ for dep in deps:
+ if dep.atom in depcache:
+ continue
+ try:
+ pkgdep = depcache[dep.atom]
+ except KeyError:
+ pkgdep = Query(dep.atom).find_best()
+ depcache[dep.atom] = pkgdep
+ if not pkgdep:
+ continue
+ elif pkgdep.cpv in seen:
+ continue
+ if depth <= max_depth or max_depth == 0:
+ if printer_fn is not None:
+ printer_fn(depth, pkgdep, dep)
+ result.append((depth, pkgdep))
+
+ seen.add(pkgdep.cpv)
+ if depth < max_depth or max_depth == 0:
+ # result is passed in and added to directly
+ # so rdeps is disposable
+ rdeps = pkgdep.deps.graph_depends( # noqa
+ max_depth=max_depth,
+ printer_fn=printer_fn,
+ # The rest of these are only used internally:
+ depth=depth + 1,
+ seen=seen,
+ depcache=depcache,
+ result=result,
+ )
+ return result
+
+ def graph_reverse_depends(
+ self,
+ pkgset=None,
+ max_depth=-1,
+ only_direct=True,
+ printer_fn=None,
+ # The rest of these are only used internally:
+ depth=0,
+ depcache=None,
+ seen=None,
+ result=None,
+ ):
+ """Graph direct reverse dependencies for self.
+
+ Example usage:
+ >>> from gentoolkit.dependencies import Dependencies
+ >>> ffmpeg = Dependencies('media-video/ffmpeg-9999')
+ >>> # I only care about installed packages that depend on me:
+ ... from gentoolkit.helpers import get_installed_cpvs
+ >>> # I want to pass in a sorted list. We can pass strings or
+ ... # Package or Atom types, so I'll use Package to sort:
+ ... from gentoolkit.package import Package
+ >>> installed = sorted(get_installed_cpvs())
+ >>> deptree = ffmpeg.graph_reverse_depends(
+ ... only_direct=False, # Include indirect revdeps
+ ... pkgset=installed) # from installed pkgset
+ >>> len(deptree)
+ 24
+
+ @type pkgset: iterable
+ @keyword pkgset: sorted pkg cpv strings or anything sublassing
+ L{gentoolkit.cpv.CPV} to use for calculate our revdep graph.
+ @type max_depth: int
+ @keyword max_depth: Maximum depth to recurse if only_direct=False.
+ -1 means no maximum depth;
+ 0 is the same as only_direct=True;
+ >0 means recurse only this many times;
+ @type only_direct: bool
+ @keyword only_direct: to recurse or not to recurse
+ @type printer_fn: callable
+ @keyword printer_fn: If None, no effect. If set, it will be applied to
+ each L{gentoolkit.atom.Atom} object as it is added to the results.
+ @rtype: list
+ @return: L{gentoolkit.dependencies.Dependencies} objects
+ """
+ if not pkgset:
+ err = (
+ "%s kwarg 'pkgset' must be set. "
+ "Can be list of cpv strings or any 'intersectable' object."
+ )
+ raise errors.GentoolkitFatalError(err % (self.__class__.__name__,))
+
+ if depcache is None:
+ depcache = dict()
+ if seen is None:
+ seen = set()
+ if result is None:
+ result = list()
+
+ if depth == 0:
+ pkgset = tuple(Dependencies(x) for x in pkgset)
+
+ pkgdep = None
+ for pkgdep in pkgset:
+ raw_depends = pkgdep.get_all_depends(raw=True)
+ if self.cp not in raw_depends:
+ # fast path for obviously non-matching packages. This saves
+ # us the work of instantiating a whole Atom() for *every*
+ # dependency of *every* package in pkgset.
+ continue
+ try:
+ all_depends = depcache[pkgdep]
+ except KeyError:
+ all_depends = uniqify(pkgdep.get_all_depends())
+ depcache[pkgdep] = all_depends
+
+ dep_is_displayed = False
+ for dep in all_depends:
+ # TODO: Add ability to determine if dep is enabled by USE flag.
+ # Check portage.dep.use_reduce
+ if dep.intersects(self):
+ pkgdep.depth = depth
+ pkgdep.matching_dep = dep
+ if printer_fn is not None:
+ printer_fn(pkgdep, dep_is_displayed=dep_is_displayed)
+ result.append(pkgdep)
+ dep_is_displayed = True
+
+ # if --indirect specified, call ourselves again with the dep
+ # Do not call if we have already called ourselves.
+ if (
+ dep_is_displayed
+ and not only_direct
+ and pkgdep.cpv not in seen
+ and (depth < max_depth or max_depth == -1)
+ ):
+
+ seen.add(pkgdep.cpv)
+ result.append(
+ pkgdep.graph_reverse_depends(
+ pkgset=pkgset,
+ max_depth=max_depth,
+ only_direct=only_direct,
+ printer_fn=printer_fn,
+ depth=depth + 1,
+ depcache=depcache,
+ seen=seen,
+ result=result,
+ )
+ )
+
+ if depth == 0:
+ return result
+ return pkgdep
+
+ def _parser(self, deps, use_conditional=None, depth=0):
+ """?DEPEND file parser.
+
+ @rtype: list
+ @return: L{gentoolkit.atom.Atom} objects
+ """
+ result = []
+
+ if depth == 0:
+ deps = paren_reduce(deps)
+ for tok in deps:
+ if tok == "||":
+ continue
+ if tok[-1] == "?":
+ use_conditional = tok[:-1]
+ continue
+ if isinstance(tok, list):
+ sub_r = self._parser(tok, use_conditional, depth=depth + 1)
+ result.extend(sub_r)
+ use_conditional = None
+ continue
+ # FIXME: This is a quick fix for bug #299260.
+ # A better fix is to not discard blockers in the parser,
+ # but to check for atom.blocker in whatever equery/depends
+ # (in this case) and ignore them there.
+ # TODO: Test to see how much a performance impact ignoring
+ # blockers here rather than checking for atom.blocker has.
+ if tok[0] == "!":
+ # We're not interested in blockers
+ continue
+ # skip it if it's empty
+ if tok and tok != "":
+ atom = Atom(tok)
+ if use_conditional is not None:
+ atom.use_conditional = use_conditional
+ result.append(atom)
+ else:
+ message = (
+ "dependencies.py: _parser() found an empty "
+ + "dep string token for: %s, deps= %s"
+ )
+ raise errors.GentoolkitInvalidAtom(message % (self.cpv, deps))
+
+ return result
+
# vim: set ts=4 sw=4 tw=0:
diff --git a/pym/gentoolkit/eclean/clean.py b/pym/gentoolkit/eclean/clean.py
index 3f6fe45..a6358a4 100644
--- a/pym/gentoolkit/eclean/clean.py
+++ b/pym/gentoolkit/eclean/clean.py
@@ -12,142 +12,138 @@ from gentoolkit.eclean.pkgindex import PkgIndex
class CleanUp:
- """Performs all cleaning actions to distfiles or package directories.
-
- @param controller: a progress output/user interaction controller function
- which returns a Boolean to control file deletion
- or bypassing/ignoring
- """
-
- def __init__(self, controller):
- self.controller = controller
-
- def clean_dist(self, clean_dict):
- """Calculate size of each entry for display, prompt user if needed,
- delete files if approved and return the total size of files that
- have been deleted.
-
- @param clean_dict: dictionary of {'display name':[list of files]}
-
- @rtype: int
- @return: total size that was cleaned
- """
- file_type = 'file'
- clean_size = 0
- # clean all entries one by one; sorting helps reading
- for key in sorted(clean_dict):
- clean_size += self._clean_files(clean_dict[key], key, file_type)
- # return total size of deleted or to delete files
- return clean_size
-
- def clean_pkgs(self, clean_dict, pkgdir):
- """Calculate size of each entry for display, prompt user if needed,
- delete files if approved and return the total size of files that
- have been deleted.
-
- @param clean_dict: dictionary of {'display name':[list of files]}
- @param metadata: package index of type portage.getbinpkg.PackageIndex()
- @param pkgdir: path to the package directory to be cleaned
-
- @rtype: int
- @return: total size that was cleaned
- """
- file_type = 'binary package'
- clean_size = 0
- # clean all entries one by one; sorting helps reading
- for key in sorted(clean_dict):
- clean_size += self._clean_files(clean_dict[key], key, file_type)
-
- # run 'emaint --fix' here
- if clean_size:
- index_control = PkgIndex(self.controller)
- # emaint is not yet importable so call it
- # print a blank line here for separation
- print()
- clean_size += index_control.call_emaint()
- # return total size of deleted or to delete files
- return clean_size
-
-
- def pretend_clean(self, clean_dict):
- """Shortcut function that calculates total space savings
- for the files in clean_dict.
-
- @param clean_dict: dictionary of {'display name':[list of files]}
- @rtype: integer
- @return: total size that would be cleaned
- """
- file_type = 'file'
- clean_size = 0
- # tally all entries one by one; sorting helps reading
- for key in sorted(clean_dict):
- key_size = self._get_size(clean_dict[key])
- self.controller(key_size, key, clean_dict[key], file_type)
- clean_size += key_size
- return clean_size
-
- def _get_size(self, key):
- """Determine the total size for an entry (may be several files)."""
- key_size = 0
- for file_ in key:
- #print file_
- # get total size for an entry (may be several files, and
- # links don't count
- # ...get its statinfo
- try:
- statinfo = os.stat(file_)
- if statinfo.st_nlink == 1:
- key_size += statinfo.st_size
- except EnvironmentError as er:
- print( pp.error(
- "Could not get stat info for:" + file_), file=sys.stderr)
- print( pp.error("Error: %s" %str(er)), file=sys.stderr)
- return key_size
-
- def _clean_files(self, files, key, file_type):
- """File removal function."""
- clean_size = 0
- for file_ in files:
- #print file_, type(file_)
- # ...get its statinfo
- try:
- statinfo = os.stat(file_)
- except EnvironmentError as er:
- if not os.path.exists(os.readlink(file_)):
- try:
- os.remove(file_)
- print( pp.error(
- "Removed broken symbolic link " + file_), file=sys.stderr)
- break
- except EnvironmentError as er:
- print( pp.error(
- "Error deleting broken symbolic link " + file_), file=sys.stderr)
- print( pp.error("Error: %s" %str(er)), file=sys.stderr)
- break
- else:
- print( pp.error(
- "Could not get stat info for:" + file_), file=sys.stderr)
- print( pp.error(
- "Error: %s" %str(er)), file=sys.stderr)
- if self.controller(statinfo.st_size, key, file_, file_type):
- # ... try to delete it.
- try:
- os.unlink(file_)
- # only count size if successfully deleted and not a link
- if statinfo.st_nlink == 1:
- clean_size += statinfo.st_size
- try:
- os.rmdir(os.path.dirname(file_))
- except OSError:
- pass
- except EnvironmentError as er:
- print( pp.error("Could not delete "+file_), file=sys.stderr)
- print( pp.error("Error: %s" %str(er)), file=sys.stderr)
- return clean_size
-
-
-
-
-
-
-
+ """Performs all cleaning actions to distfiles or package directories.
+
+ @param controller: a progress output/user interaction controller function
+ which returns a Boolean to control file deletion
+ or bypassing/ignoring
+ """
+
+ def __init__(self, controller):
+ self.controller = controller
+
+ def clean_dist(self, clean_dict):
+ """Calculate size of each entry for display, prompt user if needed,
+ delete files if approved and return the total size of files that
+ have been deleted.
+
+ @param clean_dict: dictionary of {'display name':[list of files]}
+
+ @rtype: int
+ @return: total size that was cleaned
+ """
+ file_type = "file"
+ clean_size = 0
+ # clean all entries one by one; sorting helps reading
+ for key in sorted(clean_dict):
+ clean_size += self._clean_files(clean_dict[key], key, file_type)
+ # return total size of deleted or to delete files
+ return clean_size
+
+ def clean_pkgs(self, clean_dict, pkgdir):
+ """Calculate size of each entry for display, prompt user if needed,
+ delete files if approved and return the total size of files that
+ have been deleted.
+
+ @param clean_dict: dictionary of {'display name':[list of files]}
+ @param metadata: package index of type portage.getbinpkg.PackageIndex()
+ @param pkgdir: path to the package directory to be cleaned
+
+ @rtype: int
+ @return: total size that was cleaned
+ """
+ file_type = "binary package"
+ clean_size = 0
+ # clean all entries one by one; sorting helps reading
+ for key in sorted(clean_dict):
+ clean_size += self._clean_files(clean_dict[key], key, file_type)
+
+ # run 'emaint --fix' here
+ if clean_size:
+ index_control = PkgIndex(self.controller)
+ # emaint is not yet importable so call it
+ # print a blank line here for separation
+ print()
+ clean_size += index_control.call_emaint()
+ # return total size of deleted or to delete files
+ return clean_size
+
+ def pretend_clean(self, clean_dict):
+ """Shortcut function that calculates total space savings
+ for the files in clean_dict.
+
+ @param clean_dict: dictionary of {'display name':[list of files]}
+ @rtype: integer
+ @return: total size that would be cleaned
+ """
+ file_type = "file"
+ clean_size = 0
+ # tally all entries one by one; sorting helps reading
+ for key in sorted(clean_dict):
+ key_size = self._get_size(clean_dict[key])
+ self.controller(key_size, key, clean_dict[key], file_type)
+ clean_size += key_size
+ return clean_size
+
+ def _get_size(self, key):
+ """Determine the total size for an entry (may be several files)."""
+ key_size = 0
+ for file_ in key:
+ # print file_
+ # get total size for an entry (may be several files, and
+ # links don't count
+ # ...get its statinfo
+ try:
+ statinfo = os.stat(file_)
+ if statinfo.st_nlink == 1:
+ key_size += statinfo.st_size
+ except EnvironmentError as er:
+ print(pp.error("Could not get stat info for:" + file_), file=sys.stderr)
+ print(pp.error("Error: %s" % str(er)), file=sys.stderr)
+ return key_size
+
+ def _clean_files(self, files, key, file_type):
+ """File removal function."""
+ clean_size = 0
+ for file_ in files:
+ # print file_, type(file_)
+ # ...get its statinfo
+ try:
+ statinfo = os.stat(file_)
+ except EnvironmentError as er:
+ if not os.path.exists(os.readlink(file_)):
+ try:
+ os.remove(file_)
+ print(
+ pp.error("Removed broken symbolic link " + file_),
+ file=sys.stderr,
+ )
+ break
+ except EnvironmentError as er:
+ print(
+ pp.error("Error deleting broken symbolic link " + file_),
+ file=sys.stderr,
+ )
+ print(pp.error("Error: %s" % str(er)), file=sys.stderr)
+ break
+ else:
+ print(
+ pp.error("Could not get stat info for:" + file_),
+ file=sys.stderr,
+ )
+ print(pp.error("Error: %s" % str(er)), file=sys.stderr)
+ if self.controller(statinfo.st_size, key, file_, file_type):
+ # ... try to delete it.
+ try:
+ os.unlink(file_)
+ # only count size if successfully deleted and not a link
+ if statinfo.st_nlink == 1:
+ clean_size += statinfo.st_size
+ try:
+ os.rmdir(os.path.dirname(file_))
+ except OSError:
+ pass
+ except EnvironmentError as er:
+ print(pp.error("Could not delete " + file_), file=sys.stderr)
+ print(pp.error("Error: %s" % str(er)), file=sys.stderr)
+ return clean_size
diff --git a/pym/gentoolkit/eclean/cli.py b/pym/gentoolkit/eclean/cli.py
index e31fde9..bb6deeb 100644
--- a/pym/gentoolkit/eclean/cli.py
+++ b/pym/gentoolkit/eclean/cli.py
@@ -4,10 +4,11 @@
# Distributed under the terms of the GNU General Public License v2
-__author__ = "Thomas de Grenier de Latour (tgl), " + \
- "modular re-write by: Brian Dolbec (dol-sen)"
-__email__ = "degrenier@easyconnect.fr, " + \
- "brian.dolbec@gmail.com"
+__author__ = (
+ "Thomas de Grenier de Latour (tgl), "
+ + "modular re-write by: Brian Dolbec (dol-sen)"
+)
+__email__ = "degrenier@easyconnect.fr, " + "brian.dolbec@gmail.com"
__version__ = "git"
__productname__ = "eclean"
__description__ = "A cleaning tool for Gentoo distfiles and binaries."
@@ -23,494 +24,654 @@ import portage
from portage.output import white, yellow, turquoise, green
import gentoolkit.pprinter as pp
-from gentoolkit.eclean.search import (DistfilesSearch,
- findPackages, port_settings, pkgdir)
-from gentoolkit.eclean.exclude import (parseExcludeFile,
- ParseExcludeFileException)
+from gentoolkit.eclean.search import (
+ DistfilesSearch,
+ findPackages,
+ port_settings,
+ pkgdir,
+)
+from gentoolkit.eclean.exclude import parseExcludeFile, ParseExcludeFileException
from gentoolkit.eclean.clean import CleanUp
from gentoolkit.eclean.output import OutputControl
-#from gentoolkit.eclean.dbapi import Dbapi
+
+# from gentoolkit.eclean.dbapi import Dbapi
from gentoolkit.eprefix import EPREFIX
+
def printVersion():
- """Output the version info."""
- print( "%s (%s) - %s" \
- % (__productname__, __version__, __description__))
- print()
- print("Author: %s <%s>" % (__author__,__email__))
- print("Copyright 2003-2009 Gentoo Foundation")
- print("Distributed under the terms of the GNU General Public License v2")
+ """Output the version info."""
+ print("%s (%s) - %s" % (__productname__, __version__, __description__))
+ print()
+ print("Author: %s <%s>" % (__author__, __email__))
+ print("Copyright 2003-2009 Gentoo Foundation")
+ print("Distributed under the terms of the GNU General Public License v2")
def printUsage(_error=None, help=None):
- """Print help message. May also print partial help to stderr if an
- error from {'options','actions'} is specified."""
-
- out = sys.stdout
- if _error:
- out = sys.stderr
- if not _error in ('actions', 'global-options', \
- 'packages-options', 'distfiles-options', \
- 'merged-packages-options', 'merged-distfiles-options', \
- 'time', 'size'):
- _error = None
- if not _error and not help: help = 'all'
- if _error == 'time':
- print( pp.error("Wrong time specification"), file=out)
- print( "Time specification should be an integer followed by a"+
- " single letter unit.", file=out)
- print( "Available units are: y (years), m (months), w (weeks), "+
- "d (days) and h (hours).", file=out)
- print( "For instance: \"1y\" is \"one year\", \"2w\" is \"two"+
- " weeks\", etc. ", file=out)
- return
- if _error == 'size':
- print( pp.error("Wrong size specification"), file=out)
- print( "Size specification should be an integer followed by a"+
- " single letter unit.", file=out)
- print( "Available units are: G, M, K and B.", file=out)
- print("For instance: \"10M\" is \"ten megabytes\", \"200K\" "+
- "is \"two hundreds kilobytes\", etc.", file=out)
- return
- if _error in ('global-options', 'packages-options', 'distfiles-options', \
- 'merged-packages-options', 'merged-distfiles-options',):
- print( pp.error("Wrong option on command line."), file=out)
- print( file=out)
- elif _error == 'actions':
- print( pp.error("Wrong or missing action name on command line."), file=out)
- print( file=out)
- print( white("Usage:"), file=out)
- if _error in ('actions','global-options', 'packages-options', \
- 'distfiles-options') or help == 'all':
- print( " "+turquoise(__productname__),
- yellow("[global-option] ..."),
- green("<action>"),
- yellow("[action-option] ..."), file=out)
- if _error == 'merged-distfiles-options' or help in ('all','distfiles'):
- print( " "+turquoise(__productname__+'-dist'),
- yellow("[global-option, distfiles-option] ..."), file=out)
- if _error == 'merged-packages-options' or help in ('all','packages'):
- print( " "+turquoise(__productname__+'-pkg'),
- yellow("[global-option, packages-option] ..."), file=out)
- if _error in ('global-options', 'actions'):
- print( " "+turquoise(__productname__),
- yellow("[--help, --version]"), file=out)
- if help == 'all':
- print( " "+turquoise(__productname__+"(-dist,-pkg)"),
- yellow("[--help, --version]"), file=out)
- if _error == 'merged-packages-options' or help == 'packages':
- print( " "+turquoise(__productname__+'-pkg'),
- yellow("[--help, --version]"), file=out)
- if _error == 'merged-distfiles-options' or help == 'distfiles':
- print( " "+turquoise(__productname__+'-dist'),
- yellow("[--help, --version]"), file=out)
- print(file=out)
- if _error in ('global-options', 'merged-packages-options', \
- 'merged-distfiles-options') or help:
- print( "Available global", yellow("options")+":", file=out)
- print( yellow(" -C, --nocolor")+
- " - turn off colors on output", file=out)
- print( yellow(" -d, --deep")+
- " - only keep the minimum for a reinstallation", file=out)
- print( yellow(" -e, --exclude-file=<path>")+
- " - path to the exclusion file", file=out)
- print( yellow(" -i, --interactive")+
- " - ask confirmation before deletions", file=out)
- print( yellow(" -n, --package-names")+
- " - protect all versions (when --deep)", file=out)
- print( yellow(" -p, --pretend")+
- " - only display what would be cleaned", file=out)
- print( yellow(" -q, --quiet")+
- " - be as quiet as possible", file=out)
- print( yellow(" -t, --time-limit=<time>")+
- " - don't delete files modified since "+yellow("<time>"), file=out)
- print( " "+yellow("<time>"), "is a duration: \"1y\" is"+
- " \"one year\", \"2w\" is \"two weeks\", etc. ", file=out)
- print( " "+"Units are: y (years), m (months), w (weeks), "+
- "d (days) and h (hours).", file=out)
- print( yellow(" -h, --help")+ \
- " - display the help screen", file=out)
- print( yellow(" -V, --version")+
- " - display version info", file=out)
- print( file=out)
- if _error == 'actions' or help == 'all':
- print( "Available", green("actions")+":", file=out)
- print( green(" packages")+
- " - clean outdated binary packages from PKGDIR", file=out)
- print( green(" distfiles")+
- " - clean outdated packages sources files from DISTDIR", file=out)
- print( file=out)
- if _error in ('packages-options','merged-packages-options') \
- or help in ('all','packages'):
- print( "Available", yellow("options"),"for the",
- green("packages"),"action:", file=out)
- print( yellow(" --changed-deps")+
- " - delete packages for which ebuild dependencies have changed", file=out)
- print( yellow(" -i, --ignore-failure")+
- " - ignore failure to locate PKGDIR", file=out)
- print( file=out)
- if _error in ('distfiles-options', 'merged-distfiles-options') \
- or help in ('all','distfiles'):
- print("Available", yellow("options"),"for the",
- green("distfiles"),"action:", file=out)
- print( yellow(" -f, --fetch-restricted")+
- " - protect fetch-restricted files (when --deep)", file=out)
- print( yellow(" -s, --size-limit=<size>")+
- " - don't delete distfiles bigger than "+yellow("<size>"), file=out)
- print( " "+yellow("<size>"), "is a size specification: "+
- "\"10M\" is \"ten megabytes\", \"200K\" is", file=out)
- print( " "+"\"two hundreds kilobytes\", etc. Units are: "+
- "G, M, K and B.", file=out)
- print( file=out)
- print( "More detailed instruction can be found in",
- turquoise("`man %s`" % __productname__), file=out)
+ """Print help message. May also print partial help to stderr if an
+ error from {'options','actions'} is specified."""
+
+ out = sys.stdout
+ if _error:
+ out = sys.stderr
+ if not _error in (
+ "actions",
+ "global-options",
+ "packages-options",
+ "distfiles-options",
+ "merged-packages-options",
+ "merged-distfiles-options",
+ "time",
+ "size",
+ ):
+ _error = None
+ if not _error and not help:
+ help = "all"
+ if _error == "time":
+ print(pp.error("Wrong time specification"), file=out)
+ print(
+ "Time specification should be an integer followed by a"
+ + " single letter unit.",
+ file=out,
+ )
+ print(
+ "Available units are: y (years), m (months), w (weeks), "
+ + "d (days) and h (hours).",
+ file=out,
+ )
+ print(
+ 'For instance: "1y" is "one year", "2w" is "two' + ' weeks", etc. ',
+ file=out,
+ )
+ return
+ if _error == "size":
+ print(pp.error("Wrong size specification"), file=out)
+ print(
+ "Size specification should be an integer followed by a"
+ + " single letter unit.",
+ file=out,
+ )
+ print("Available units are: G, M, K and B.", file=out)
+ print(
+ 'For instance: "10M" is "ten megabytes", "200K" '
+ + 'is "two hundreds kilobytes", etc.',
+ file=out,
+ )
+ return
+ if _error in (
+ "global-options",
+ "packages-options",
+ "distfiles-options",
+ "merged-packages-options",
+ "merged-distfiles-options",
+ ):
+ print(pp.error("Wrong option on command line."), file=out)
+ print(file=out)
+ elif _error == "actions":
+ print(pp.error("Wrong or missing action name on command line."), file=out)
+ print(file=out)
+ print(white("Usage:"), file=out)
+ if (
+ _error in ("actions", "global-options", "packages-options", "distfiles-options")
+ or help == "all"
+ ):
+ print(
+ " " + turquoise(__productname__),
+ yellow("[global-option] ..."),
+ green("<action>"),
+ yellow("[action-option] ..."),
+ file=out,
+ )
+ if _error == "merged-distfiles-options" or help in ("all", "distfiles"):
+ print(
+ " " + turquoise(__productname__ + "-dist"),
+ yellow("[global-option, distfiles-option] ..."),
+ file=out,
+ )
+ if _error == "merged-packages-options" or help in ("all", "packages"):
+ print(
+ " " + turquoise(__productname__ + "-pkg"),
+ yellow("[global-option, packages-option] ..."),
+ file=out,
+ )
+ if _error in ("global-options", "actions"):
+ print(" " + turquoise(__productname__), yellow("[--help, --version]"), file=out)
+ if help == "all":
+ print(
+ " " + turquoise(__productname__ + "(-dist,-pkg)"),
+ yellow("[--help, --version]"),
+ file=out,
+ )
+ if _error == "merged-packages-options" or help == "packages":
+ print(
+ " " + turquoise(__productname__ + "-pkg"),
+ yellow("[--help, --version]"),
+ file=out,
+ )
+ if _error == "merged-distfiles-options" or help == "distfiles":
+ print(
+ " " + turquoise(__productname__ + "-dist"),
+ yellow("[--help, --version]"),
+ file=out,
+ )
+ print(file=out)
+ if (
+ _error
+ in ("global-options", "merged-packages-options", "merged-distfiles-options")
+ or help
+ ):
+ print("Available global", yellow("options") + ":", file=out)
+ print(
+ yellow(" -C, --nocolor") + " - turn off colors on output",
+ file=out,
+ )
+ print(
+ yellow(" -d, --deep")
+ + " - only keep the minimum for a reinstallation",
+ file=out,
+ )
+ print(
+ yellow(" -e, --exclude-file=<path>") + " - path to the exclusion file",
+ file=out,
+ )
+ print(
+ yellow(" -i, --interactive")
+ + " - ask confirmation before deletions",
+ file=out,
+ )
+ print(
+ yellow(" -n, --package-names")
+ + " - protect all versions (when --deep)",
+ file=out,
+ )
+ print(
+ yellow(" -p, --pretend")
+ + " - only display what would be cleaned",
+ file=out,
+ )
+ print(
+ yellow(" -q, --quiet") + " - be as quiet as possible",
+ file=out,
+ )
+ print(
+ yellow(" -t, --time-limit=<time>")
+ + " - don't delete files modified since "
+ + yellow("<time>"),
+ file=out,
+ )
+ print(
+ " " + yellow("<time>"),
+ 'is a duration: "1y" is' + ' "one year", "2w" is "two weeks", etc. ',
+ file=out,
+ )
+ print(
+ " "
+ + "Units are: y (years), m (months), w (weeks), "
+ + "d (days) and h (hours).",
+ file=out,
+ )
+ print(
+ yellow(" -h, --help") + " - display the help screen",
+ file=out,
+ )
+ print(
+ yellow(" -V, --version") + " - display version info", file=out
+ )
+ print(file=out)
+ if _error == "actions" or help == "all":
+ print("Available", green("actions") + ":", file=out)
+ print(
+ green(" packages") + " - clean outdated binary packages from PKGDIR",
+ file=out,
+ )
+ print(
+ green(" distfiles")
+ + " - clean outdated packages sources files from DISTDIR",
+ file=out,
+ )
+ print(file=out)
+ if _error in ("packages-options", "merged-packages-options") or help in (
+ "all",
+ "packages",
+ ):
+ print(
+ "Available",
+ yellow("options"),
+ "for the",
+ green("packages"),
+ "action:",
+ file=out,
+ )
+ print(
+ yellow(" --changed-deps")
+ + " - delete packages for which ebuild dependencies have changed",
+ file=out,
+ )
+ print(
+ yellow(" -i, --ignore-failure")
+ + " - ignore failure to locate PKGDIR",
+ file=out,
+ )
+ print(file=out)
+ if _error in ("distfiles-options", "merged-distfiles-options") or help in (
+ "all",
+ "distfiles",
+ ):
+ print(
+ "Available",
+ yellow("options"),
+ "for the",
+ green("distfiles"),
+ "action:",
+ file=out,
+ )
+ print(
+ yellow(" -f, --fetch-restricted")
+ + " - protect fetch-restricted files (when --deep)",
+ file=out,
+ )
+ print(
+ yellow(" -s, --size-limit=<size>")
+ + " - don't delete distfiles bigger than "
+ + yellow("<size>"),
+ file=out,
+ )
+ print(
+ " " + yellow("<size>"),
+ "is a size specification: " + '"10M" is "ten megabytes", "200K" is',
+ file=out,
+ )
+ print(
+ " " + '"two hundreds kilobytes", etc. Units are: ' + "G, M, K and B.",
+ file=out,
+ )
+ print(file=out)
+ print(
+ "More detailed instruction can be found in",
+ turquoise("`man %s`" % __productname__),
+ file=out,
+ )
class ParseArgsException(Exception):
- """For parseArgs() -> main() communications."""
- def __init__(self, value):
- self.value = value # sdfgsdfsdfsd
- def __str__(self):
- return repr(self.value)
+ """For parseArgs() -> main() communications."""
+
+ def __init__(self, value):
+ self.value = value # sdfgsdfsdfsd
+
+ def __str__(self):
+ return repr(self.value)
def parseSize(size):
- """Convert a file size "Xu" ("X" is an integer, and "u" in
- [G,M,K,B]) into an integer (file size in Bytes).
-
- @raise ParseArgsException: in case of failure
- """
- units = {
- 'G': (1024**3),
- 'M': (1024**2),
- 'K': 1024,
- 'B': 1
- }
- try:
- match = re.match(r"^(?P<value>\d+)(?P<unit>[GMKBgmkb])?$",size)
- size = int(match.group('value'))
- if match.group('unit'):
- size *= units[match.group('unit').capitalize()]
- except:
- raise ParseArgsException('size')
- return size
+ """Convert a file size "Xu" ("X" is an integer, and "u" in
+ [G,M,K,B]) into an integer (file size in Bytes).
+
+ @raise ParseArgsException: in case of failure
+ """
+ units = {"G": (1024 ** 3), "M": (1024 ** 2), "K": 1024, "B": 1}
+ try:
+ match = re.match(r"^(?P<value>\d+)(?P<unit>[GMKBgmkb])?$", size)
+ size = int(match.group("value"))
+ if match.group("unit"):
+ size *= units[match.group("unit").capitalize()]
+ except:
+ raise ParseArgsException("size")
+ return size
def parseTime(timespec):
- """Convert a duration "Xu" ("X" is an int, and "u" a time unit in
- [Y,M,W,D,H]) into an integer which is a past EPOCH date.
- Raises ParseArgsException('time') in case of failure.
- (yep, big approximations inside... who cares?).
- """
- units = {'H' : (60 * 60)}
- units['D'] = units['H'] * 24
- units['W'] = units['D'] * 7
- units['M'] = units['D'] * 30
- units['Y'] = units['D'] * 365
- try:
- # parse the time specification
- match = re.match(r"^(?P<value>\d+)(?P<unit>[YMWDHymwdh])?$",timespec)
- value = int(match.group('value'))
- if not match.group('unit'): unit = 'D'
- else: unit = match.group('unit').capitalize()
- except:
- raise ParseArgsException('time')
- return time.time() - (value * units[unit])
+ """Convert a duration "Xu" ("X" is an int, and "u" a time unit in
+ [Y,M,W,D,H]) into an integer which is a past EPOCH date.
+ Raises ParseArgsException('time') in case of failure.
+ (yep, big approximations inside... who cares?).
+ """
+ units = {"H": (60 * 60)}
+ units["D"] = units["H"] * 24
+ units["W"] = units["D"] * 7
+ units["M"] = units["D"] * 30
+ units["Y"] = units["D"] * 365
+ try:
+ # parse the time specification
+ match = re.match(r"^(?P<value>\d+)(?P<unit>[YMWDHymwdh])?$", timespec)
+ value = int(match.group("value"))
+ if not match.group("unit"):
+ unit = "D"
+ else:
+ unit = match.group("unit").capitalize()
+ except:
+ raise ParseArgsException("time")
+ return time.time() - (value * units[unit])
def parseArgs(options={}):
- """Parse the command line arguments. Raise exceptions on
- errors or non-action modes (help/version). Returns an action, and affect
- the options dict.
- """
-
- def optionSwitch(option,opts,action=None):
- """local function for interpreting command line options
- and setting options accordingly"""
- return_code = True
- do_help = False
- for o, a in opts:
- if o in ("-h", "--help"):
- do_help = True
- elif o in ("-V", "--version"):
- raise ParseArgsException('version')
- elif o in ("-C", "--nocolor"):
- options['nocolor'] = True
- pp.output.nocolor()
- elif o in ("-d", "--deep", "--destructive"):
- options['destructive'] = True
- elif o in ("-D", "--deprecated"):
- options['deprecated'] = True
- elif o in ("-i", "--interactive") and not options['pretend']:
- options['interactive'] = True
- elif o in ("-p", "--pretend"):
- options['pretend'] = True
- options['interactive'] = False
- elif o in ("-q", "--quiet"):
- options['quiet'] = True
- options['verbose'] = False
- elif o in ("-t", "--time-limit"):
- options['time-limit'] = parseTime(a)
- elif o in ("-e", "--exclude-file"):
- print("cli --exclude option")
- options['exclude-file'] = a
- elif o in ("-n", "--package-names"):
- options['package-names'] = True
- elif o in ("-f", "--fetch-restricted"):
- options['fetch-restricted'] = True
- elif o in ("-s", "--size-limit"):
- options['size-limit'] = parseSize(a)
- elif o in ("-v", "--verbose") and not options['quiet']:
- options['verbose'] = True
- elif o in ("--changed-deps"):
- options['changed-deps'] = True
- elif o in ("-i", "--ignore-failure"):
- options['ignore-failure'] = True
- else:
- return_code = False
- # sanity check of --deep only options:
- for opt in ('fetch-restricted', 'package-names'):
- if (not options['destructive']) and options[opt]:
- if not options['quiet']:
- print( pp.error(
- "--%s only makes sense in --deep mode." % opt), file=sys.stderr)
- options[opt] = False
- if do_help:
- if action:
- raise ParseArgsException('help-'+action)
- else:
- raise ParseArgsException('help')
- return return_code
-
- # here are the different allowed command line options (getopt args)
- getopt_options = {'short':{}, 'long':{}}
- getopt_options['short']['global'] = "CdDipqe:t:nhVv"
- getopt_options['long']['global'] = ["nocolor", "deep", "destructive",
- "deprecated", "interactive", "pretend", "quiet", "exclude-file=",
- "time-limit=", "package-names", "help", "version", "verbose"]
- getopt_options['short']['distfiles'] = "fs:"
- getopt_options['long']['distfiles'] = ["fetch-restricted", "size-limit="]
- getopt_options['short']['packages'] = "i"
- getopt_options['long']['packages'] = ["ignore-failure", "changed-deps"]
- # set default options, except 'nocolor', which is set in main()
- options['interactive'] = False
- options['pretend'] = False
- options['quiet'] = False
- options['accept_all'] = False
- options['destructive'] = False
- options['deprecated'] = False
- options['time-limit'] = 0
- options['package-names'] = False
- options['fetch-restricted'] = False
- options['size-limit'] = 0
- options['verbose'] = False
- options['changed-deps'] = False
- options['ignore-failure'] = False
- # if called by a well-named symlink, set the action accordingly:
- action = None
- # temp print line to ensure it is the svn/branch code running, etc..
- #print( "###### svn/branch/gentoolkit_eclean ####### ==> ", os.path.basename(sys.argv[0]))
- if os.path.basename(sys.argv[0]).startswith(__productname__+'-pkg') or \
- os.path.basename(sys.argv[0]).startswith(__productname__+'-packages'):
- action = 'packages'
- elif os.path.basename(sys.argv[0]).startswith(__productname__+'-dist') or \
- os.path.basename(sys.argv[0]).startswith(__productname__+'distfiles'):
- action = 'distfiles'
- # prepare for the first getopt
- if action:
- short_opts = getopt_options['short']['global'] \
- + getopt_options['short'][action]
- long_opts = getopt_options['long']['global'] \
- + getopt_options['long'][action]
- opts_mode = 'merged-'+action
- else:
- short_opts = getopt_options['short']['global']
- long_opts = getopt_options['long']['global']
- opts_mode = 'global'
- # apply getopts to command line, show partial help on failure
- try:
- opts, args = getopt.getopt(sys.argv[1:], short_opts, long_opts)
- except:
- raise ParseArgsException(opts_mode+'-options')
- # set options accordingly
- optionSwitch(options,opts,action=action)
- # if action was already set, there should be no more args
- if action and len(args):
- raise ParseArgsException(opts_mode+'-options')
- # if action was set, there is nothing left to do
- if action:
- return action
- # So, we are in "eclean --foo action --bar" mode. Parse remaining args...
- # Only two actions are allowed: 'packages' and 'distfiles'.
- if not len(args) or not args[0] in ('packages','distfiles'):
- raise ParseArgsException('actions')
- action = args.pop(0)
- # parse the action specific options
- try:
- opts, args = getopt.getopt(args, \
- getopt_options['short'][action], \
- getopt_options['long'][action])
- except:
- raise ParseArgsException(action+'-options')
- # set options again, for action-specific options
- optionSwitch(options,opts,action=action)
- # any remaning args? Then die!
- if len(args):
- raise ParseArgsException(action+'-options')
- # returns the action. Options dictionary is modified by side-effect.
- return action
-
-
-def doAction(action,options,exclude={}, output=None):
- """doAction: execute one action, ie display a few message, call the right
- find* function, and then call doCleanup with its result."""
- # define vocabulary for the output
- if action == 'packages':
- files_type = "binary packages"
- else:
- files_type = "distfiles"
- saved = {}
- deprecated = {}
- # find files to delete, depending on the action
- if not options['quiet']:
- output.einfo("Building file list for "+action+" cleaning...")
- if action == 'packages':
- clean_me = findPackages(
- options,
- exclude=exclude,
- destructive=options['destructive'],
- package_names=options['package-names'],
- time_limit=options['time-limit'],
- pkgdir=pkgdir,
- #port_dbapi=Dbapi(portage.db[portage.root]["porttree"].dbapi),
- #var_dbapi=Dbapi(portage.db[portage.root]["vartree"].dbapi),
- )
- else:
- # accept defaults
- engine = DistfilesSearch(output=options['verbose-output'],
- #portdb=Dbapi(portage.db[portage.root]["porttree"].dbapi),
- #var_dbapi=Dbapi(portage.db[portage.root]["vartree"].dbapi),
- )
- clean_me, saved, deprecated = engine.findDistfiles(
- exclude=exclude,
- destructive=options['destructive'],
- fetch_restricted=options['fetch-restricted'],
- package_names=options['package-names'],
- time_limit=options['time-limit'],
- size_limit=options['size-limit'],
- deprecate = options['deprecated']
- )
-
- # initialize our cleaner
- cleaner = CleanUp(output.progress_controller)
-
- # actually clean files if something was found
- if clean_me:
- # verbose pretend message
- if options['pretend'] and not options['quiet']:
- output.einfo("Here are the "+files_type+" that would be deleted:")
- # verbose non-pretend message
- elif not options['quiet']:
- output.einfo("Cleaning " + files_type +"...")
- # do the cleanup, and get size of deleted files
- if options['pretend']:
- clean_size = cleaner.pretend_clean(clean_me)
- elif action in ['distfiles']:
- clean_size = cleaner.clean_dist(clean_me)
- elif action in ['packages']:
- clean_size = cleaner.clean_pkgs(clean_me,
- pkgdir)
- # vocabulary for final message
- if options['pretend']:
- verb = "would be"
- else:
- verb = "were"
- # display freed space
- if not options['quiet']:
- output.total('normal', clean_size, len(clean_me), verb, action)
- # nothing was found
- elif not options['quiet']:
- output.einfo("Your "+action+" directory was already clean.")
- if saved and not options['quiet']:
- print()
- print( (pp.emph(" The following ") + yellow("unavailable") +
- pp.emph(" files were saved from cleaning due to exclusion file entries")))
- output.set_colors('deprecated')
- clean_size = cleaner.pretend_clean(saved)
- output.total('deprecated', clean_size, len(saved), verb, action)
- if deprecated and not options['quiet']:
- print()
- print( (pp.emph(" The following ") + yellow("unavailable") +
- pp.emph(" installed packages were found")))
- output.set_colors('deprecated')
- output.list_pkgs(deprecated)
+ """Parse the command line arguments. Raise exceptions on
+ errors or non-action modes (help/version). Returns an action, and affect
+ the options dict.
+ """
+
+ def optionSwitch(option, opts, action=None):
+ """local function for interpreting command line options
+ and setting options accordingly"""
+ return_code = True
+ do_help = False
+ for o, a in opts:
+ if o in ("-h", "--help"):
+ do_help = True
+ elif o in ("-V", "--version"):
+ raise ParseArgsException("version")
+ elif o in ("-C", "--nocolor"):
+ options["nocolor"] = True
+ pp.output.nocolor()
+ elif o in ("-d", "--deep", "--destructive"):
+ options["destructive"] = True
+ elif o in ("-D", "--deprecated"):
+ options["deprecated"] = True
+ elif o in ("-i", "--interactive") and not options["pretend"]:
+ options["interactive"] = True
+ elif o in ("-p", "--pretend"):
+ options["pretend"] = True
+ options["interactive"] = False
+ elif o in ("-q", "--quiet"):
+ options["quiet"] = True
+ options["verbose"] = False
+ elif o in ("-t", "--time-limit"):
+ options["time-limit"] = parseTime(a)
+ elif o in ("-e", "--exclude-file"):
+ print("cli --exclude option")
+ options["exclude-file"] = a
+ elif o in ("-n", "--package-names"):
+ options["package-names"] = True
+ elif o in ("-f", "--fetch-restricted"):
+ options["fetch-restricted"] = True
+ elif o in ("-s", "--size-limit"):
+ options["size-limit"] = parseSize(a)
+ elif o in ("-v", "--verbose") and not options["quiet"]:
+ options["verbose"] = True
+ elif o in ("--changed-deps"):
+ options["changed-deps"] = True
+ elif o in ("-i", "--ignore-failure"):
+ options["ignore-failure"] = True
+ else:
+ return_code = False
+ # sanity check of --deep only options:
+ for opt in ("fetch-restricted", "package-names"):
+ if (not options["destructive"]) and options[opt]:
+ if not options["quiet"]:
+ print(
+ pp.error("--%s only makes sense in --deep mode." % opt),
+ file=sys.stderr,
+ )
+ options[opt] = False
+ if do_help:
+ if action:
+ raise ParseArgsException("help-" + action)
+ else:
+ raise ParseArgsException("help")
+ return return_code
+
+ # here are the different allowed command line options (getopt args)
+ getopt_options = {"short": {}, "long": {}}
+ getopt_options["short"]["global"] = "CdDipqe:t:nhVv"
+ getopt_options["long"]["global"] = [
+ "nocolor",
+ "deep",
+ "destructive",
+ "deprecated",
+ "interactive",
+ "pretend",
+ "quiet",
+ "exclude-file=",
+ "time-limit=",
+ "package-names",
+ "help",
+ "version",
+ "verbose",
+ ]
+ getopt_options["short"]["distfiles"] = "fs:"
+ getopt_options["long"]["distfiles"] = ["fetch-restricted", "size-limit="]
+ getopt_options["short"]["packages"] = "i"
+ getopt_options["long"]["packages"] = ["ignore-failure", "changed-deps"]
+ # set default options, except 'nocolor', which is set in main()
+ options["interactive"] = False
+ options["pretend"] = False
+ options["quiet"] = False
+ options["accept_all"] = False
+ options["destructive"] = False
+ options["deprecated"] = False
+ options["time-limit"] = 0
+ options["package-names"] = False
+ options["fetch-restricted"] = False
+ options["size-limit"] = 0
+ options["verbose"] = False
+ options["changed-deps"] = False
+ options["ignore-failure"] = False
+ # if called by a well-named symlink, set the action accordingly:
+ action = None
+ # temp print line to ensure it is the svn/branch code running, etc..
+ # print( "###### svn/branch/gentoolkit_eclean ####### ==> ", os.path.basename(sys.argv[0]))
+ if os.path.basename(sys.argv[0]).startswith(
+ __productname__ + "-pkg"
+ ) or os.path.basename(sys.argv[0]).startswith(__productname__ + "-packages"):
+ action = "packages"
+ elif os.path.basename(sys.argv[0]).startswith(
+ __productname__ + "-dist"
+ ) or os.path.basename(sys.argv[0]).startswith(__productname__ + "distfiles"):
+ action = "distfiles"
+ # prepare for the first getopt
+ if action:
+ short_opts = getopt_options["short"]["global"] + getopt_options["short"][action]
+ long_opts = getopt_options["long"]["global"] + getopt_options["long"][action]
+ opts_mode = "merged-" + action
+ else:
+ short_opts = getopt_options["short"]["global"]
+ long_opts = getopt_options["long"]["global"]
+ opts_mode = "global"
+ # apply getopts to command line, show partial help on failure
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], short_opts, long_opts)
+ except:
+ raise ParseArgsException(opts_mode + "-options")
+ # set options accordingly
+ optionSwitch(options, opts, action=action)
+ # if action was already set, there should be no more args
+ if action and len(args):
+ raise ParseArgsException(opts_mode + "-options")
+ # if action was set, there is nothing left to do
+ if action:
+ return action
+ # So, we are in "eclean --foo action --bar" mode. Parse remaining args...
+ # Only two actions are allowed: 'packages' and 'distfiles'.
+ if not len(args) or not args[0] in ("packages", "distfiles"):
+ raise ParseArgsException("actions")
+ action = args.pop(0)
+ # parse the action specific options
+ try:
+ opts, args = getopt.getopt(
+ args, getopt_options["short"][action], getopt_options["long"][action]
+ )
+ except:
+ raise ParseArgsException(action + "-options")
+ # set options again, for action-specific options
+ optionSwitch(options, opts, action=action)
+ # any remaning args? Then die!
+ if len(args):
+ raise ParseArgsException(action + "-options")
+ # returns the action. Options dictionary is modified by side-effect.
+ return action
+
+
+def doAction(action, options, exclude={}, output=None):
+ """doAction: execute one action, ie display a few message, call the right
+ find* function, and then call doCleanup with its result."""
+ # define vocabulary for the output
+ if action == "packages":
+ files_type = "binary packages"
+ else:
+ files_type = "distfiles"
+ saved = {}
+ deprecated = {}
+ # find files to delete, depending on the action
+ if not options["quiet"]:
+ output.einfo("Building file list for " + action + " cleaning...")
+ if action == "packages":
+ clean_me = findPackages(
+ options,
+ exclude=exclude,
+ destructive=options["destructive"],
+ package_names=options["package-names"],
+ time_limit=options["time-limit"],
+ pkgdir=pkgdir,
+ # port_dbapi=Dbapi(portage.db[portage.root]["porttree"].dbapi),
+ # var_dbapi=Dbapi(portage.db[portage.root]["vartree"].dbapi),
+ )
+ else:
+ # accept defaults
+ engine = DistfilesSearch(
+ output=options["verbose-output"],
+ # portdb=Dbapi(portage.db[portage.root]["porttree"].dbapi),
+ # var_dbapi=Dbapi(portage.db[portage.root]["vartree"].dbapi),
+ )
+ clean_me, saved, deprecated = engine.findDistfiles(
+ exclude=exclude,
+ destructive=options["destructive"],
+ fetch_restricted=options["fetch-restricted"],
+ package_names=options["package-names"],
+ time_limit=options["time-limit"],
+ size_limit=options["size-limit"],
+ deprecate=options["deprecated"],
+ )
+
+ # initialize our cleaner
+ cleaner = CleanUp(output.progress_controller)
+
+ # actually clean files if something was found
+ if clean_me:
+ # verbose pretend message
+ if options["pretend"] and not options["quiet"]:
+ output.einfo("Here are the " + files_type + " that would be deleted:")
+ # verbose non-pretend message
+ elif not options["quiet"]:
+ output.einfo("Cleaning " + files_type + "...")
+ # do the cleanup, and get size of deleted files
+ if options["pretend"]:
+ clean_size = cleaner.pretend_clean(clean_me)
+ elif action in ["distfiles"]:
+ clean_size = cleaner.clean_dist(clean_me)
+ elif action in ["packages"]:
+ clean_size = cleaner.clean_pkgs(clean_me, pkgdir)
+ # vocabulary for final message
+ if options["pretend"]:
+ verb = "would be"
+ else:
+ verb = "were"
+ # display freed space
+ if not options["quiet"]:
+ output.total("normal", clean_size, len(clean_me), verb, action)
+ # nothing was found
+ elif not options["quiet"]:
+ output.einfo("Your " + action + " directory was already clean.")
+ if saved and not options["quiet"]:
+ print()
+ print(
+ (
+ pp.emph(" The following ")
+ + yellow("unavailable")
+ + pp.emph(
+ " files were saved from cleaning due to exclusion file entries"
+ )
+ )
+ )
+ output.set_colors("deprecated")
+ clean_size = cleaner.pretend_clean(saved)
+ output.total("deprecated", clean_size, len(saved), verb, action)
+ if deprecated and not options["quiet"]:
+ print()
+ print(
+ (
+ pp.emph(" The following ")
+ + yellow("unavailable")
+ + pp.emph(" installed packages were found")
+ )
+ )
+ output.set_colors("deprecated")
+ output.list_pkgs(deprecated)
def main():
- """Parse command line and execute all actions."""
- # set default options
- options = {}
- options['nocolor'] = (port_settings.get("NOCOLOR") in ('yes','true')
- or not sys.stdout.isatty())
- if options['nocolor']:
- pp.output.nocolor()
- # parse command line options and actions
- try:
- action = parseArgs(options)
- # filter exception to know what message to display
- except ParseArgsException as e:
- if e.value == 'help':
- printUsage(help='all')
- sys.exit(0)
- elif e.value[:5] == 'help-':
- printUsage(help=e.value[5:])
- sys.exit(0)
- elif e.value == 'version':
- printVersion()
- sys.exit(0)
- else:
- printUsage(e.value)
- sys.exit(2)
- output = OutputControl(options)
- options['verbose-output'] = lambda x: None
- if not options['quiet']:
- if options['verbose']:
- options['verbose-output'] = output.einfo
- # parse the exclusion file
- if not 'exclude-file' in options:
- # set it to the default exclude file if it exists
- exclude_file = "%s/etc/%s/%s.exclude" % (EPREFIX,__productname__ , action)
- if os.path.isfile(exclude_file):
- options['exclude-file'] = exclude_file
- if 'exclude-file' in options:
- try:
- exclude = parseExcludeFile(options['exclude-file'],
- options['verbose-output'])
- except ParseExcludeFileException as e:
- print( pp.error(str(e)), file=sys.stderr)
- print( pp.error(
- "Invalid exclusion file: %s" % options['exclude-file']), file=sys.stderr)
- print( pp.error(
- "See format of this file in `man %s`" % __productname__), file=sys.stderr)
- sys.exit(1)
- else:
- exclude = {}
- # security check for non-pretend mode
- if not options['pretend'] and portage.secpass == 0:
- print( pp.error(
- "Permission denied: you must be root or belong to " +
- "the portage group."), file=sys.stderr)
- sys.exit(1)
- # execute action
- doAction(action, options, exclude=exclude,
- output=output)
+ """Parse command line and execute all actions."""
+ # set default options
+ options = {}
+ options["nocolor"] = (
+ port_settings.get("NOCOLOR") in ("yes", "true") or not sys.stdout.isatty()
+ )
+ if options["nocolor"]:
+ pp.output.nocolor()
+ # parse command line options and actions
+ try:
+ action = parseArgs(options)
+ # filter exception to know what message to display
+ except ParseArgsException as e:
+ if e.value == "help":
+ printUsage(help="all")
+ sys.exit(0)
+ elif e.value[:5] == "help-":
+ printUsage(help=e.value[5:])
+ sys.exit(0)
+ elif e.value == "version":
+ printVersion()
+ sys.exit(0)
+ else:
+ printUsage(e.value)
+ sys.exit(2)
+ output = OutputControl(options)
+ options["verbose-output"] = lambda x: None
+ if not options["quiet"]:
+ if options["verbose"]:
+ options["verbose-output"] = output.einfo
+ # parse the exclusion file
+ if not "exclude-file" in options:
+ # set it to the default exclude file if it exists
+ exclude_file = "%s/etc/%s/%s.exclude" % (EPREFIX, __productname__, action)
+ if os.path.isfile(exclude_file):
+ options["exclude-file"] = exclude_file
+ if "exclude-file" in options:
+ try:
+ exclude = parseExcludeFile(
+ options["exclude-file"], options["verbose-output"]
+ )
+ except ParseExcludeFileException as e:
+ print(pp.error(str(e)), file=sys.stderr)
+ print(
+ pp.error("Invalid exclusion file: %s" % options["exclude-file"]),
+ file=sys.stderr,
+ )
+ print(
+ pp.error("See format of this file in `man %s`" % __productname__),
+ file=sys.stderr,
+ )
+ sys.exit(1)
+ else:
+ exclude = {}
+ # security check for non-pretend mode
+ if not options["pretend"] and portage.secpass == 0:
+ print(
+ pp.error(
+ "Permission denied: you must be root or belong to "
+ + "the portage group."
+ ),
+ file=sys.stderr,
+ )
+ sys.exit(1)
+ # execute action
+ doAction(action, options, exclude=exclude, output=output)
if __name__ == "__main__":
- """actually call main() if launched as a script"""
- try:
- main()
- except KeyboardInterrupt:
- print( "Aborted.")
- sys.exit(130)
- sys.exit(0)
+ """actually call main() if launched as a script"""
+ try:
+ main()
+ except KeyboardInterrupt:
+ print("Aborted.")
+ sys.exit(130)
+ sys.exit(0)
diff --git a/pym/gentoolkit/eclean/exclude.py b/pym/gentoolkit/eclean/exclude.py
index 1da9523..a5c29d4 100644
--- a/pym/gentoolkit/eclean/exclude.py
+++ b/pym/gentoolkit/eclean/exclude.py
@@ -13,254 +13,283 @@ from portage import _encodings, _unicode_encode
# Misc. shortcuts to some portage stuff:
listdir = portage.listdir
-FILENAME_RE = [re.compile(r'(?P<pkgname>[-a-zA-z0-9\+]+)(?P<ver>-\d+\S+)'),
- re.compile(r'(?P<pkgname>[-a-zA-z]+)(?P<ver>_\d+\S+)'),
- re.compile(r'(?P<pkgname>[-a-zA-z_]+)(?P<ver>\d\d+\S+)'),
- re.compile(r'(?P<pkgname>[-a-zA-z0-9_]+)(?P<ver>-default\S+)'),
- re.compile(r'(?P<pkgname>[-a-zA-z0-9]+)(?P<ver>_\d\S+)'),
- re.compile(r'(?P<pkgname>[-a-zA-z0-9\+\.]+)(?P<ver>-\d+\S+)'),
- re.compile(r'(?P<pkgname>[-a-zA-z0-9\+\.]+)(?P<ver>.\d+\S+)')]
+FILENAME_RE = [
+ re.compile(r"(?P<pkgname>[-a-zA-z0-9\+]+)(?P<ver>-\d+\S+)"),
+ re.compile(r"(?P<pkgname>[-a-zA-z]+)(?P<ver>_\d+\S+)"),
+ re.compile(r"(?P<pkgname>[-a-zA-z_]+)(?P<ver>\d\d+\S+)"),
+ re.compile(r"(?P<pkgname>[-a-zA-z0-9_]+)(?P<ver>-default\S+)"),
+ re.compile(r"(?P<pkgname>[-a-zA-z0-9]+)(?P<ver>_\d\S+)"),
+ re.compile(r"(?P<pkgname>[-a-zA-z0-9\+\.]+)(?P<ver>-\d+\S+)"),
+ re.compile(r"(?P<pkgname>[-a-zA-z0-9\+\.]+)(?P<ver>.\d+\S+)"),
+]
debug_modules = []
+
def dprint(module, message):
- if module in debug_modules:
- print(message)
+ if module in debug_modules:
+ print(message)
+
def isValidCP(cp):
- """Check whether a string is a valid cat/pkg-name.
+ """Check whether a string is a valid cat/pkg-name.
- This is for 2.0.51 vs. CVS HEAD compatibility, I've not found any function
- for that which would exists in both. Weird...
+ This is for 2.0.51 vs. CVS HEAD compatibility, I've not found any function
+ for that which would exists in both. Weird...
- @param cp: catageory/package string
- @rtype: bool
- """
+ @param cp: catageory/package string
+ @rtype: bool
+ """
- if not '/' in cp:
- return False
- try:
- portage.cpv_getkey(cp+"-0")
- except:
- return False
- else:
- return True
+ if not "/" in cp:
+ return False
+ try:
+ portage.cpv_getkey(cp + "-0")
+ except:
+ return False
+ else:
+ return True
class ParseExcludeFileException(Exception):
- """For parseExcludeFile() -> main() communication.
+ """For parseExcludeFile() -> main() communication.
+
+ @param value: Error message string
+ """
+
+ def __init__(self, value):
+ self.value = value
- @param value: Error message string
- """
- def __init__(self, value):
- self.value = value
- def __str__(self):
- return repr(self.value)
+ def __str__(self):
+ return repr(self.value)
def parseExcludeFile(filepath, output):
- """Parses an exclusion file.
-
- @param filepath: file containing the list of cat/pkg's to exclude
- @param output: --verbose enabled output method or "lambda x: None"
-
- @rtype: dict
- @return: an exclusion dict
- @raise ParseExcludeFileException: in case of fatal error
- """
-
- exclude = {
- 'categories': {},
- 'packages': {},
- 'anti-packages': {},
- 'filenames': {}
- }
- output("Parsing Exclude file: " + filepath)
- try:
- file_ = open(_unicode_encode(filepath,
- encoding=_encodings['fs']), mode="r", encoding=_encodings['content'])
- except IOError:
- raise ParseExcludeFileException("Could not open exclusion file: " +
- filepath)
- filecontents = file_.readlines()
- file_.close()
- cat_re = re.compile(r'^(?P<cat>[a-zA-Z0-9]+-[a-zA-Z0-9]+)(/\*)?$')
- cp_re = re.compile(r'^(?P<cp>[-a-zA-Z0-9_]+/[-a-zA-Z0-9_]+)$')
- # used to output the line number for exception error reporting
- linenum = 0
- for line in filecontents:
- # need to increment it here due to continue statements.
- linenum += 1
- line = line.strip()
- if not len(line): # skip blank a line
- continue
- if line[0] == '#': # skip a comment line
- continue
- #print( "parseExcludeFile: line=", line)
- try: # category matching
- cat = cat_re.match(line).group('cat')
- #print( "parseExcludeFile: found cat=", cat)
- except:
- pass
- else:
- if not cat in portage.settings.categories:
- raise ParseExcludeFileException("Invalid category: "+cat +
- " @line # " + str(linenum))
- exclude['categories'][cat] = None
- continue
- dict_key = 'packages'
- if line[0] == '!': # reverses category setting
- dict_key = 'anti-packages'
- line = line[1:]
- try: # cat/pkg matching
- cp = cp_re.match(line).group('cp')
- #print( "parseExcludeFile: found cp=", cp)
- if isValidCP(cp):
- exclude[dict_key][cp] = None
- continue
- else:
- raise ParseExcludeFileException("Invalid cat/pkg: "+cp +
- " @line # " + str(linenum))
- except:
- pass
- #raise ParseExcludeFileException("Invalid line: "+line)
- try: # filename matching.
- exclude['filenames'][line] = re.compile(line)
- #print( "parseExcludeFile: found filenames", line)
- except:
- try:
- exclude['filenames'][line] = re.compile(re.escape(line))
- #print( "parseExcludeFile: found escaped filenames", line)
- except:
- raise ParseExcludeFileException("Invalid file name/regular " +
- "expression: @line # " + str(linenum) + " line=" +line)
- output("Exclude file parsed. Found " +
- "%d categories, %d packages, %d anti-packages %d filenames"
- %(len(exclude['categories']), len(exclude['packages']),
- len(exclude['anti-packages']), len(exclude['filenames'])))
- #print()
- #print( "parseExcludeFile: final exclude_dict = ", exclude)
- #print()
- return exclude
-
-def cp_all(categories, portdb=portage.portdb ):
- """temp function until the new portdb.cp_all([cat,...])
- behaviour is fully available.
-
- @param categories: list of categories to get all packages for
- eg. ['app-portage', 'sys-apps',...]
- @rtype: list of cat/pkg's ['foo/bar', 'foo/baz']
- """
- try:
- cps = portdb.cp_all(categories)
- # NOTE: the following backup code should be removed
- # when all available versions of portage have the
- # categories parameter in cp_all()
- except: # new behaviour not available
- #~ message = "Exception: eclean.exclude.cp_all() " +\
- #~ "new portdb.cp_all() behavior not found. using fallback code"
- #~ print( warn(message), file=sys.stderr)
- cps = []
- # XXX: i smell an access to something which is really out of API...
- _pkg_dir_name_re = re.compile(r'^\w[-+\w]*$')
- for tree in portdb.porttrees:
- for cat in categories:
- for pkg in listdir(os.path.join(tree,cat),
- EmptyOnError=1, ignorecvs=1, dirsonly=1):
- if not _pkg_dir_name_re.match(pkg) or pkg == "CVS":
- continue
- cps.append(cat+'/'+pkg)
- #print( "cp_all: new cps list=", cps)
- return cps
+ """Parses an exclusion file.
+
+ @param filepath: file containing the list of cat/pkg's to exclude
+ @param output: --verbose enabled output method or "lambda x: None"
+
+ @rtype: dict
+ @return: an exclusion dict
+ @raise ParseExcludeFileException: in case of fatal error
+ """
+
+ exclude = {"categories": {}, "packages": {}, "anti-packages": {}, "filenames": {}}
+ output("Parsing Exclude file: " + filepath)
+ try:
+ file_ = open(
+ _unicode_encode(filepath, encoding=_encodings["fs"]),
+ mode="r",
+ encoding=_encodings["content"],
+ )
+ except IOError:
+ raise ParseExcludeFileException("Could not open exclusion file: " + filepath)
+ filecontents = file_.readlines()
+ file_.close()
+ cat_re = re.compile(r"^(?P<cat>[a-zA-Z0-9]+-[a-zA-Z0-9]+)(/\*)?$")
+ cp_re = re.compile(r"^(?P<cp>[-a-zA-Z0-9_]+/[-a-zA-Z0-9_]+)$")
+ # used to output the line number for exception error reporting
+ linenum = 0
+ for line in filecontents:
+ # need to increment it here due to continue statements.
+ linenum += 1
+ line = line.strip()
+ if not len(line): # skip blank a line
+ continue
+ if line[0] == "#": # skip a comment line
+ continue
+ # print( "parseExcludeFile: line=", line)
+ try: # category matching
+ cat = cat_re.match(line).group("cat")
+ # print( "parseExcludeFile: found cat=", cat)
+ except:
+ pass
+ else:
+ if not cat in portage.settings.categories:
+ raise ParseExcludeFileException(
+ "Invalid category: " + cat + " @line # " + str(linenum)
+ )
+ exclude["categories"][cat] = None
+ continue
+ dict_key = "packages"
+ if line[0] == "!": # reverses category setting
+ dict_key = "anti-packages"
+ line = line[1:]
+ try: # cat/pkg matching
+ cp = cp_re.match(line).group("cp")
+ # print( "parseExcludeFile: found cp=", cp)
+ if isValidCP(cp):
+ exclude[dict_key][cp] = None
+ continue
+ else:
+ raise ParseExcludeFileException(
+ "Invalid cat/pkg: " + cp + " @line # " + str(linenum)
+ )
+ except:
+ pass
+ # raise ParseExcludeFileException("Invalid line: "+line)
+ try: # filename matching.
+ exclude["filenames"][line] = re.compile(line)
+ # print( "parseExcludeFile: found filenames", line)
+ except:
+ try:
+ exclude["filenames"][line] = re.compile(re.escape(line))
+ # print( "parseExcludeFile: found escaped filenames", line)
+ except:
+ raise ParseExcludeFileException(
+ "Invalid file name/regular "
+ + "expression: @line # "
+ + str(linenum)
+ + " line="
+ + line
+ )
+ output(
+ "Exclude file parsed. Found "
+ + "%d categories, %d packages, %d anti-packages %d filenames"
+ % (
+ len(exclude["categories"]),
+ len(exclude["packages"]),
+ len(exclude["anti-packages"]),
+ len(exclude["filenames"]),
+ )
+ )
+ # print()
+ # print( "parseExcludeFile: final exclude_dict = ", exclude)
+ # print()
+ return exclude
+
+
+def cp_all(categories, portdb=portage.portdb):
+ """temp function until the new portdb.cp_all([cat,...])
+ behaviour is fully available.
+
+ @param categories: list of categories to get all packages for
+ eg. ['app-portage', 'sys-apps',...]
+ @rtype: list of cat/pkg's ['foo/bar', 'foo/baz']
+ """
+ try:
+ cps = portdb.cp_all(categories)
+ # NOTE: the following backup code should be removed
+ # when all available versions of portage have the
+ # categories parameter in cp_all()
+ except: # new behaviour not available
+ # ~ message = "Exception: eclean.exclude.cp_all() " +\
+ # ~ "new portdb.cp_all() behavior not found. using fallback code"
+ # ~ print( warn(message), file=sys.stderr)
+ cps = []
+ # XXX: i smell an access to something which is really out of API...
+ _pkg_dir_name_re = re.compile(r"^\w[-+\w]*$")
+ for tree in portdb.porttrees:
+ for cat in categories:
+ for pkg in listdir(
+ os.path.join(tree, cat), EmptyOnError=1, ignorecvs=1, dirsonly=1
+ ):
+ if not _pkg_dir_name_re.match(pkg) or pkg == "CVS":
+ continue
+ cps.append(cat + "/" + pkg)
+ # print( "cp_all: new cps list=", cps)
+ return cps
+
def exclDictExpand(exclude):
- """Returns a dictionary of all CP/CPV from porttree which match
- the exclusion dictionary.
- """
- d = {}
- if 'categories' in exclude:
- # replace the following cp_all call with
- # portage.portdb.cp_all([cat1, cat2])
- # when it is available in all portage versions.
- cps = cp_all(exclude['categories'])
- for cp in cps:
- d[cp] = None
- if 'packages' in exclude:
- for cp in exclude['packages']:
- d[cp] = None
- if 'anti-packages' in exclude:
- for cp in exclude['anti-packages']:
- if cp in d:
- del d[cp]
- return d
-
-def exclDictMatchCP(exclude,pkg):
- """Checks whether a CP matches the exclusion rules."""
- if pkg is None:
- return False
- if 'anti-packages' in exclude and pkg in exclude['anti-packages']:
- return False
- if 'packages' in exclude and pkg in exclude['packages']:
- return True
- try:
- cat = pkg.split('/')[0]
- except:
- dprint( "exclude", "exclDictMatchCP: Invalid package name: " +\
- "%s, Could not determine category" %pkg)
- cat = ''
- if 'categories' in exclude and cat in exclude['categories']:
- return True
- return False
+ """Returns a dictionary of all CP/CPV from porttree which match
+ the exclusion dictionary.
+ """
+ d = {}
+ if "categories" in exclude:
+ # replace the following cp_all call with
+ # portage.portdb.cp_all([cat1, cat2])
+ # when it is available in all portage versions.
+ cps = cp_all(exclude["categories"])
+ for cp in cps:
+ d[cp] = None
+ if "packages" in exclude:
+ for cp in exclude["packages"]:
+ d[cp] = None
+ if "anti-packages" in exclude:
+ for cp in exclude["anti-packages"]:
+ if cp in d:
+ del d[cp]
+ return d
+
+
+def exclDictMatchCP(exclude, pkg):
+ """Checks whether a CP matches the exclusion rules."""
+ if pkg is None:
+ return False
+ if "anti-packages" in exclude and pkg in exclude["anti-packages"]:
+ return False
+ if "packages" in exclude and pkg in exclude["packages"]:
+ return True
+ try:
+ cat = pkg.split("/")[0]
+ except:
+ dprint(
+ "exclude",
+ "exclDictMatchCP: Invalid package name: "
+ + "%s, Could not determine category" % pkg,
+ )
+ cat = ""
+ if "categories" in exclude and cat in exclude["categories"]:
+ return True
+ return False
+
def exclDictExpandPkgname(exclude):
- """Returns a set of all pkgnames from porttree which match
- the exclusion dictionary.
- """
- p = set()
- if 'categories' in exclude:
- # replace the following cp_all call with
- # portage.portdb.cp_all([cat1, cat2])
- # when it is available in all portage versions.
- cps = cp_all(exclude['categories'])
- for cp in cps:
- pkgname = cp.split('/')[1]
- p.add(pkgname)
- if 'packages' in exclude:
- for cp in exclude['packages']:
- pkgname = cp.split('/')[1]
- p.add(pkgname)
- if 'anti-packages' in exclude:
- for cp in exclude['anti-packages']:
- if cp in p:
- p.remove(cp)
- return p
+ """Returns a set of all pkgnames from porttree which match
+ the exclusion dictionary.
+ """
+ p = set()
+ if "categories" in exclude:
+ # replace the following cp_all call with
+ # portage.portdb.cp_all([cat1, cat2])
+ # when it is available in all portage versions.
+ cps = cp_all(exclude["categories"])
+ for cp in cps:
+ pkgname = cp.split("/")[1]
+ p.add(pkgname)
+ if "packages" in exclude:
+ for cp in exclude["packages"]:
+ pkgname = cp.split("/")[1]
+ p.add(pkgname)
+ if "anti-packages" in exclude:
+ for cp in exclude["anti-packages"]:
+ if cp in p:
+ p.remove(cp)
+ return p
def exclMatchFilename(exclude_names, filename):
- """Attempts to split the package name out of a filename
- and then checks if it matches any exclusion rules.
-
- This is intended to be run on the cleaning list after all
- normal checks and removal of protected files. This will reduce
- the number of files to perform this last minute check on
-
- @param exclude_names: a set of pkgnames to exlcude
- @param filename:
-
- @rtype: bool
- """
- found = False
- index = 0
- while not found and index < len(FILENAME_RE):
- found = FILENAME_RE[index].match(filename)
- index += 1
- if not found:
- dprint( "exclude", "exclMatchFilename: filename: " +\
- "%s, Could not determine package name" %filename)
- return False
- pkgname = found.group('pkgname')
- dprint("exclude", "exclMatchFilename: found pkgname = " +
- "%s, %s, %d, %s" %(pkgname, str(pkgname in exclude_names),
- index-1, filename))
- return (pkgname in exclude_names)
+ """Attempts to split the package name out of a filename
+ and then checks if it matches any exclusion rules.
+
+ This is intended to be run on the cleaning list after all
+ normal checks and removal of protected files. This will reduce
+ the number of files to perform this last minute check on
+
+ @param exclude_names: a set of pkgnames to exlcude
+ @param filename:
+ @rtype: bool
+ """
+ found = False
+ index = 0
+ while not found and index < len(FILENAME_RE):
+ found = FILENAME_RE[index].match(filename)
+ index += 1
+ if not found:
+ dprint(
+ "exclude",
+ "exclMatchFilename: filename: "
+ + "%s, Could not determine package name" % filename,
+ )
+ return False
+ pkgname = found.group("pkgname")
+ dprint(
+ "exclude",
+ "exclMatchFilename: found pkgname = "
+ + "%s, %s, %d, %s"
+ % (pkgname, str(pkgname in exclude_names), index - 1, filename),
+ )
+ return pkgname in exclude_names
diff --git a/pym/gentoolkit/eclean/output.py b/pym/gentoolkit/eclean/output.py
index e2ed221..62777b7 100644
--- a/pym/gentoolkit/eclean/output.py
+++ b/pym/gentoolkit/eclean/output.py
@@ -10,173 +10,187 @@ from gentoolkit.pprinter import cpv, number
class OutputControl:
- """Outputs data according to predetermined options and handles any user
- interaction.
-
- @param options: dictionary of boolean options as determined in cli.py
- used here: interactive, pretend, quiet, accept_all, nocolor.
- """
-
- def __init__(self, options):
- if not options:
- # set some defaults
- self.options['interactive'] = False
- self.options['pretend'] = True
- self.options['quiet'] = False
- self.options['accept_all'] = False
- self.options['nocolor'] = False
- else:
- self.options = options
- self.set_colors("normal")
-
- def set_colors(self, mode):
- """Sets the colors for the progress_controller
- and prettysize output
-
- @param mode: string, 1 of ["normal", "deprecated"]
- """
- if mode == "normal":
- self.pkg_color = cpv # green
- self.numbers = number # turquoise
- self.brace = blue
- elif mode == "deprecated":
- self.pkg_color = yellow
- self.numbers = teal # darkgreen
- self.brace = blue
-
- def einfo(self, message=""):
- """Display an info message depending on a color mode.
-
- @param message: text string to display
-
- @outputs to stdout.
- """
- if not self.options['nocolor']:
- prefix = " "+green('*')
- else:
- prefix = ">>>"
- print(prefix,message)
-
- def eprompt(self, message):
- """Display a user question depending on a color mode.
-
- @param message: text string to display
-
- @output to stdout
- """
- if not self.options['nocolor']:
- prefix = " "+red('>')+" "
- else:
- prefix = "??? "
- sys.stdout.write(prefix+message)
- sys.stdout.flush()
-
- def prettySize(self, size, justify=False, color=None):
- """int -> byte/kilo/mega/giga converter. Optionally
- justify the result. Output is a string.
-
- @param size: integer
- @param justify: optional boolean, defaults to False
- @param color: optional color, defaults to green
- as defined in portage.output
-
- @returns a formatted and (escape sequenced)
- colorized text string
- """
- if color == None:
- color = self.numbers
- units = [" G"," M"," K"," B"]
- # by using 1000 as the changeover, the integer portion
- # of the number will never be more than 3 digits long
- # but the true base 2 value of 1024 is used for the actual
- # calulation to maintain better accuracy.
- while len(units) and size >= 1000:
- size = size / 1024.0
- units.pop()
- sizestr = "%.1f" %(round(size,1)) + units[-1]
- if justify:
- sizestr = " " + self.brace("[ ") + \
- color(sizestr.rjust(8)) + self.brace(" ]")
- return sizestr
-
- def yesNoAllPrompt(self, message="Do you want to proceed?"):
- """Print a prompt until user answer in yes/no/all. Return a
- boolean for answer, and also may affect the 'accept_all' option.
-
- @param message: optional different input string from the default
- message of: "Do you want to proceed?"
- @outputs to stdout
- @modifies class var options['accept_all']
- @rtype: bool
- """
- user_string="xxx"
- while not user_string.lower() in ["","y","n","a","yes","no","all"]:
- self.eprompt(message+" [Y/n/a]: ")
- user_string = sys.stdin.readline().rstrip('\n')
- user_string = user_string.strip()
- if user_string.lower() in ["a","all"]:
- self.options['accept_all'] = True
- answer = user_string.lower() in ["","y","a","yes","all"]
- return answer
-
- def progress_controller(self, size, key, clean_list, file_type):
- """Callback function for doCleanup. It outputs data according to the
- options configured.
- Alternatively it handles user interaction for decisions that are
- required.
-
- @param size: Integer of the file(s) size
- @param key: the filename/pkgname currently being processed
- @param clean_list: list of files being processed.
- """
- if not self.options['quiet']:
- # pretty print mode
- print(self.prettySize(size,True), self.pkg_color(key))
- elif self.options['pretend'] or self.options['interactive']:
- # file list mode
- for file_ in clean_list:
- print(file_)
- if self.options['pretend']:
- return False
- elif not self.options['interactive'] \
- or self.options['accept_all'] \
- or self.yesNoAllPrompt("Do you want to delete this " + file_type + "?"):
- return True
- return False
-
- def total(self, mode, size, num_files, verb, action):
- """outputs the formatted totals to stdout
-
- @param mode: sets color and message. 1 of ['normal', 'deprecated']
- @param size: total space savings
- @param num_files: total number of files
- @param verb: string eg. 1 of ["would be", "has been"]
- @param action: string eg 1 of ['distfiles', 'packages']
- """
- self.set_colors(mode)
- if mode =="normal":
- message="Total space from "+red(str(num_files))+" files "+\
- verb+" freed in the " + action + " directory"
- print( " ===========")
- print( self.prettySize(size, True, red), message)
- elif mode == "deprecated":
- message = "Total space from "+red(str(num_files))+" package files\n"+\
- " Re-run the last command with the -D " +\
- "option to clean them as well"
- print( " ===========")
- print( self.prettySize(size, True, red), message)
-
- def list_pkgs(self, pkgs):
- """outputs the packages to stdout
-
- @param pkgs: dict. of {cat/pkg-ver: src_uri,}
- """
- indent = ' ' * 12
- keys = sorted(pkgs)
- for key in keys:
- if pkgs[key]:
- saved = ""
- else:
- saved = " ...distfile name(s) not known/saved"
- print( indent,self.pkg_color(key) + saved)
- print()
+ """Outputs data according to predetermined options and handles any user
+ interaction.
+
+ @param options: dictionary of boolean options as determined in cli.py
+ used here: interactive, pretend, quiet, accept_all, nocolor.
+ """
+
+ def __init__(self, options):
+ if not options:
+ # set some defaults
+ self.options["interactive"] = False
+ self.options["pretend"] = True
+ self.options["quiet"] = False
+ self.options["accept_all"] = False
+ self.options["nocolor"] = False
+ else:
+ self.options = options
+ self.set_colors("normal")
+
+ def set_colors(self, mode):
+ """Sets the colors for the progress_controller
+ and prettysize output
+
+ @param mode: string, 1 of ["normal", "deprecated"]
+ """
+ if mode == "normal":
+ self.pkg_color = cpv # green
+ self.numbers = number # turquoise
+ self.brace = blue
+ elif mode == "deprecated":
+ self.pkg_color = yellow
+ self.numbers = teal # darkgreen
+ self.brace = blue
+
+ def einfo(self, message=""):
+ """Display an info message depending on a color mode.
+
+ @param message: text string to display
+
+ @outputs to stdout.
+ """
+ if not self.options["nocolor"]:
+ prefix = " " + green("*")
+ else:
+ prefix = ">>>"
+ print(prefix, message)
+
+ def eprompt(self, message):
+ """Display a user question depending on a color mode.
+
+ @param message: text string to display
+
+ @output to stdout
+ """
+ if not self.options["nocolor"]:
+ prefix = " " + red(">") + " "
+ else:
+ prefix = "??? "
+ sys.stdout.write(prefix + message)
+ sys.stdout.flush()
+
+ def prettySize(self, size, justify=False, color=None):
+ """int -> byte/kilo/mega/giga converter. Optionally
+ justify the result. Output is a string.
+
+ @param size: integer
+ @param justify: optional boolean, defaults to False
+ @param color: optional color, defaults to green
+ as defined in portage.output
+
+ @returns a formatted and (escape sequenced)
+ colorized text string
+ """
+ if color == None:
+ color = self.numbers
+ units = [" G", " M", " K", " B"]
+ # by using 1000 as the changeover, the integer portion
+ # of the number will never be more than 3 digits long
+ # but the true base 2 value of 1024 is used for the actual
+ # calulation to maintain better accuracy.
+ while len(units) and size >= 1000:
+ size = size / 1024.0
+ units.pop()
+ sizestr = "%.1f" % (round(size, 1)) + units[-1]
+ if justify:
+ sizestr = (
+ " " + self.brace("[ ") + color(sizestr.rjust(8)) + self.brace(" ]")
+ )
+ return sizestr
+
+ def yesNoAllPrompt(self, message="Do you want to proceed?"):
+ """Print a prompt until user answer in yes/no/all. Return a
+ boolean for answer, and also may affect the 'accept_all' option.
+
+ @param message: optional different input string from the default
+ message of: "Do you want to proceed?"
+ @outputs to stdout
+ @modifies class var options['accept_all']
+ @rtype: bool
+ """
+ user_string = "xxx"
+ while not user_string.lower() in ["", "y", "n", "a", "yes", "no", "all"]:
+ self.eprompt(message + " [Y/n/a]: ")
+ user_string = sys.stdin.readline().rstrip("\n")
+ user_string = user_string.strip()
+ if user_string.lower() in ["a", "all"]:
+ self.options["accept_all"] = True
+ answer = user_string.lower() in ["", "y", "a", "yes", "all"]
+ return answer
+
+ def progress_controller(self, size, key, clean_list, file_type):
+ """Callback function for doCleanup. It outputs data according to the
+ options configured.
+ Alternatively it handles user interaction for decisions that are
+ required.
+
+ @param size: Integer of the file(s) size
+ @param key: the filename/pkgname currently being processed
+ @param clean_list: list of files being processed.
+ """
+ if not self.options["quiet"]:
+ # pretty print mode
+ print(self.prettySize(size, True), self.pkg_color(key))
+ elif self.options["pretend"] or self.options["interactive"]:
+ # file list mode
+ for file_ in clean_list:
+ print(file_)
+ if self.options["pretend"]:
+ return False
+ elif (
+ not self.options["interactive"]
+ or self.options["accept_all"]
+ or self.yesNoAllPrompt("Do you want to delete this " + file_type + "?")
+ ):
+ return True
+ return False
+
+ def total(self, mode, size, num_files, verb, action):
+ """outputs the formatted totals to stdout
+
+ @param mode: sets color and message. 1 of ['normal', 'deprecated']
+ @param size: total space savings
+ @param num_files: total number of files
+ @param verb: string eg. 1 of ["would be", "has been"]
+ @param action: string eg 1 of ['distfiles', 'packages']
+ """
+ self.set_colors(mode)
+ if mode == "normal":
+ message = (
+ "Total space from "
+ + red(str(num_files))
+ + " files "
+ + verb
+ + " freed in the "
+ + action
+ + " directory"
+ )
+ print(" ===========")
+ print(self.prettySize(size, True, red), message)
+ elif mode == "deprecated":
+ message = (
+ "Total space from "
+ + red(str(num_files))
+ + " package files\n"
+ + " Re-run the last command with the -D "
+ + "option to clean them as well"
+ )
+ print(" ===========")
+ print(self.prettySize(size, True, red), message)
+
+ def list_pkgs(self, pkgs):
+ """outputs the packages to stdout
+
+ @param pkgs: dict. of {cat/pkg-ver: src_uri,}
+ """
+ indent = " " * 12
+ keys = sorted(pkgs)
+ for key in keys:
+ if pkgs[key]:
+ saved = ""
+ else:
+ saved = " ...distfile name(s) not known/saved"
+ print(indent, self.pkg_color(key) + saved)
+ print()
diff --git a/pym/gentoolkit/eclean/pkgindex.py b/pym/gentoolkit/eclean/pkgindex.py
index 46c734d..617b437 100644
--- a/pym/gentoolkit/eclean/pkgindex.py
+++ b/pym/gentoolkit/eclean/pkgindex.py
@@ -14,77 +14,77 @@ import portage
class PkgIndex:
- """Handle the cleaning of the binpkg Package
- Index file
-
- @type output: class
- @param output: optional output class for printing
- """
-
- def __init__(self, controller=None):
- self.controller = controller
- # backup command line call
- self.emaint_cmd = "%s/usr/sbin/emaint --fix binhost" % EPREFIX
-
-
- def _get_emaint_binhost(self):
- """Obtain a reference to the binhost module class
-
- @sets: self.binhost to BinhostHandler class
- @rtype: boolean
- """
- # About noqa below: I don't understand how this code can run at all.
- # TODO: verify soundness
- try:
- self.emaint_control = Modules() # noqa
- self.binhost = self.emaint_control._get_class('binhost')
- except InvalidModuleName as er: # noqa
- print( pp.error("Error importing emaint binhost module"), file=sys.stderr)
- print( pp.error("Original error: " + er), file=sys.stderr)
- except:
- return False
- return True
-
-
- def _load_modules(self):
- """Import the emaint modules and report the success/fail of them
- """
- try:
- from emaint.module import Modules # noqa
- from emaint.main import TaskHandler # noqa
- except ImportError:
- return False
- return True
-
-
- def clean_pkgs_index(self,):
- """This will clean the binpkgs packages index file"""
- go = self._load_modules()
- if go:
- if self.get_emaint_binhost():
- self.taskmaster = TaskHandler(show_progress_bar=True) # noqa
- tasks = [self.binhost]
- self.taskmaster.run_tasks(tasks)
-
-
- def call_emaint(self):
- """Run the stand alone emaint script from
- a subprocess call.
-
- @rtype: integer
- @return: the difference in file size
- """
- file_ = os.path.join(portage.settings['PKGDIR'], 'Packages')
- statinfo = os.stat(file_)
- size1 = statinfo.st_size
- try:
- retcode = subprocess.call(self.emaint_cmd, shell=True)
- if retcode < 0:
- print( pp.error("Child was terminated by signal" + str(-retcode)), file=sys.stderr)
- except OSError as e:
- print( pp.error("Execution failed:" + e), file=sys.stderr)
- print()
- statinfo = os.stat(file_)
- clean_size = size1 - statinfo.st_size
- self.controller(clean_size, "Packages Index", file_, "Index")
- return clean_size
+ """Handle the cleaning of the binpkg Package
+ Index file
+
+ @type output: class
+ @param output: optional output class for printing
+ """
+
+ def __init__(self, controller=None):
+ self.controller = controller
+ # backup command line call
+ self.emaint_cmd = "%s/usr/sbin/emaint --fix binhost" % EPREFIX
+
+ def _get_emaint_binhost(self):
+ """Obtain a reference to the binhost module class
+
+ @sets: self.binhost to BinhostHandler class
+ @rtype: boolean
+ """
+ # About noqa below: I don't understand how this code can run at all.
+ # TODO: verify soundness
+ try:
+ self.emaint_control = Modules() # noqa
+ self.binhost = self.emaint_control._get_class("binhost")
+ except InvalidModuleName as er: # noqa
+ print(pp.error("Error importing emaint binhost module"), file=sys.stderr)
+ print(pp.error("Original error: " + er), file=sys.stderr)
+ except:
+ return False
+ return True
+
+ def _load_modules(self):
+ """Import the emaint modules and report the success/fail of them"""
+ try:
+ from emaint.module import Modules # noqa
+ from emaint.main import TaskHandler # noqa
+ except ImportError:
+ return False
+ return True
+
+ def clean_pkgs_index(
+ self,
+ ):
+ """This will clean the binpkgs packages index file"""
+ go = self._load_modules()
+ if go:
+ if self.get_emaint_binhost():
+ self.taskmaster = TaskHandler(show_progress_bar=True) # noqa
+ tasks = [self.binhost]
+ self.taskmaster.run_tasks(tasks)
+
+ def call_emaint(self):
+ """Run the stand alone emaint script from
+ a subprocess call.
+
+ @rtype: integer
+ @return: the difference in file size
+ """
+ file_ = os.path.join(portage.settings["PKGDIR"], "Packages")
+ statinfo = os.stat(file_)
+ size1 = statinfo.st_size
+ try:
+ retcode = subprocess.call(self.emaint_cmd, shell=True)
+ if retcode < 0:
+ print(
+ pp.error("Child was terminated by signal" + str(-retcode)),
+ file=sys.stderr,
+ )
+ except OSError as e:
+ print(pp.error("Execution failed:" + e), file=sys.stderr)
+ print()
+ statinfo = os.stat(file_)
+ clean_size = size1 - statinfo.st_size
+ self.controller(clean_size, "Packages Index", file_, "Index")
+ return clean_size
diff --git a/pym/gentoolkit/eclean/search.py b/pym/gentoolkit/eclean/search.py
index 8f6e52f..cb695c0 100644
--- a/pym/gentoolkit/eclean/search.py
+++ b/pym/gentoolkit/eclean/search.py
@@ -14,8 +14,12 @@ from portage.dep import Atom, use_reduce
from portage.dep._slot_operator import strip_slots
import gentoolkit.pprinter as pp
-from gentoolkit.eclean.exclude import (exclDictMatchCP, exclDictExpand,
- exclDictExpandPkgname, exclMatchFilename)
+from gentoolkit.eclean.exclude import (
+ exclDictMatchCP,
+ exclDictExpand,
+ exclDictExpandPkgname,
+ exclMatchFilename,
+)
# Misc. shortcuts to some portage stuff:
@@ -23,7 +27,7 @@ port_settings = portage.settings
pkgdir = port_settings["PKGDIR"]
err = sys.stderr
-deprecated_message=""""Deprecation Warning: Installed package: %s
+deprecated_message = """"Deprecation Warning: Installed package: %s
Is no longer in the tree or an installed overlay"""
DEPRECATED = pp.warn(deprecated_message)
@@ -31,574 +35,580 @@ debug_modules = []
def dprint(module, message):
- if module in debug_modules:
- print(message)
+ if module in debug_modules:
+ print(message)
def get_distdir():
- """Returns DISTDIR if sane, else barfs."""
+ """Returns DISTDIR if sane, else barfs."""
+
+ d = portage.settings["DISTDIR"]
+ if not os.path.isdir(d):
+ e = pp.error("%s does not appear to be a directory.\n" % d)
+ e += pp.error("Please set DISTDIR to a sane value.\n")
+ e += pp.error("(Check your make.conf file and environment).")
+ print(e, file=sys.stderr)
+ exit(1)
+ return d
- d = portage.settings["DISTDIR"]
- if not os.path.isdir(d):
- e = pp.error("%s does not appear to be a directory.\n" % d)
- e += pp.error("Please set DISTDIR to a sane value.\n")
- e += pp.error("(Check your make.conf file and environment).")
- print( e, file=sys.stderr)
- exit(1)
- return d
distdir = get_distdir()
class DistfilesSearch:
- """
-
- @param output: verbose output method or (lambda x: None) to turn off
- @param vardb: defaults to portage.db[portage.root]["vartree"].dbapi
- is overridden for testing.
- @param portdb: defaults to portage.portdb and is overriden for testing.
-"""
-
- def __init__(self,
- output,
- portdb=portage.portdb,
- vardb=portage.db[portage.root]["vartree"].dbapi,
- ):
- self.vardb =vardb
- self.portdb = portdb
- self.output = output
- self.installed_cpvs = None
-
- def findDistfiles(self,
- exclude=None,
- destructive=False,
- fetch_restricted=False,
- package_names=False,
- time_limit=0,
- size_limit=0,
- _distdir=distdir,
- deprecate=False,
- extra_checks=()
- ):
- """Find all obsolete distfiles.
-
- XXX: what about cvs ebuilds?
- I should install some to see where it goes...
-
- @param exclude: an exclusion dict as defined in
- exclude.parseExcludeFile class.
- @param destructive: boolean, defaults to False
- @param fetch_restricted: boolean, defaults to False
- @param package_names: boolean, defaults to False.
- @param time_limit: integer time value as returned by parseTime()
- @param size_limit: integer value of max. file size to keep or 0 to ignore.
- @param _distdir: path to the distfiles dir being checked, defaults to portage.
- @param deprecate: bool to control checking the clean dict. files for exclusion
-
- @rtype: dict
- @return dict. of package files to clean i.e. {'cat/pkg-ver.tbz2': [filename],}
- """
- if exclude is None:
- exclude = {}
- clean_me = {}
- pkgs = {}
- saved = {}
- deprecated = {}
- installed_included = False
- # create a big CPV->SRC_URI dict of packages
- # whose distfiles should be kept
- if (not destructive) or fetch_restricted:
- self.output("...non-destructive type search")
- pkgs, _deprecated = self._non_destructive(destructive, fetch_restricted)
- deprecated.update(_deprecated)
- installed_included = True
- if destructive:
- self.output("...destructive type search: %d packages already found" %len(pkgs))
- pkgs, _deprecated = self._destructive(package_names,
- exclude, pkgs, installed_included)
- deprecated.update(_deprecated)
- # gather the files to be cleaned
- self.output("...checking limits for %d ebuild sources"
- %len(pkgs))
-
- checks = self._get_default_checks(size_limit, time_limit, exclude, destructive)
- checks.extend(extra_checks)
- clean_me = self._check_limits(_distdir, checks, clean_me)
- # remove any protected files from the list
- self.output("...removing protected sources from %s candidates to clean"
- %len(clean_me))
- clean_me = self._remove_protected(pkgs, clean_me)
- if not deprecate and len(exclude) and len(clean_me):
- self.output("...checking final for exclusion from " +\
- "%s remaining candidates to clean" %len(clean_me))
- clean_me, saved = self._check_excludes(exclude, clean_me)
- return clean_me, saved, deprecated
-
-
-####################### begin _check_limits code block
-
- def _get_default_checks(self, size_limit, time_limit, excludes, destructive):
- #checks =[(self._isreg_check_, "is_reg_check")]
- checks =[self._isreg_check_]
- if 'filenames' in excludes:
- #checks.append((partial(self._filenames_check_, excludes), "Filenames_check"))
- checks.append(partial(self._filenames_check_, excludes))
- else:
- self.output(" - skipping exclude filenames check")
- if size_limit:
- #checks.append((partial(self._size_check_, size_limit), "size_check"))
- checks.append(partial(self._size_check_, size_limit))
- else:
- self.output(" - skipping size limit check")
- if time_limit:
- #print("time_limit = ", time_limit/1000000,"M sec")
- #checks.append((partial(self._time_check_, time_limit), "time_check"))
- checks.append(partial(self._time_check_, time_limit))
- else:
- self.output(" - skipping time limit check")
- if destructive:
- self.output(" - skipping dot files check")
- else:
- checks.append(self._dotfile_check_)
- return checks
-
-
- def _check_limits(self,
- _distdir,
- checks,
- clean_me=None
- ):
- """Checks files if they exceed size and/or time_limits, etc.
-
- To start with everything is considered dirty and is excluded
- only if it matches some condition.
- """
- if clean_me is None:
- clean_me = {}
- for file in os.listdir(_distdir):
- filepath = os.path.join(_distdir, file)
- try:
- file_stat = os.lstat(filepath)
- except EnvironmentError:
- continue
- is_dirty = False
- #for check, check_name in checks:
- for check in checks:
- should_break, is_dirty = check(file_stat, file)
- if should_break:
- break
-
- if is_dirty:
- #print( "%s Adding file to clean_list:" %check_name, file)
- clean_me[file]=[filepath]
- return clean_me
-
- @staticmethod
- def _isreg_check_(file_stat, file):
- """check if file is a regular file."""
- is_reg_file = stat.S_ISREG(file_stat[stat.ST_MODE])
- return not is_reg_file, is_reg_file
-
- @staticmethod
- def _size_check_(size_limit, file_stat, file):
- """checks if the file size exceeds the size_limit"""
- if (file_stat[stat.ST_SIZE] >= size_limit):
- #print( "size mismatch ", file, file_stat[stat.ST_SIZE])
- return True, False
- return False, True
-
- @staticmethod
- def _time_check_(time_limit, file_stat, file):
- """checks if the file exceeds the time_limit
- (think forward, not back, time keeps increasing)"""
- if (file_stat[stat.ST_MTIME] >= time_limit):
- #print( "time match too young ", file, file_stat[stat.ST_MTIME]/1000000,"M sec.")
- return True, False
- #print( "time match too old", file, file_stat[stat.ST_MTIME]/1000000,"M sec.")
- return False, True
-
- @staticmethod
- def _filenames_check_(exclude, file_stat, file):
- """checks if the file matches an exclusion file listing"""
- # Try to match file name directly
- if file in exclude['filenames']:
- return True, False
- # See if file matches via regular expression matching
- else:
- file_match = False
- for file_entry in exclude['filenames']:
- if exclude['filenames'][file_entry].match(file):
- file_match = True
- break
- if file_match:
- #print( "filename match ", file)
- return True, False
- return False, True
-
- @staticmethod
- def _dotfile_check_(file_stat, file):
- """check if file is a regular file."""
- head, tail = os.path.split(file)
- if tail:
- is_dot_file = tail.startswith('.')
- return is_dot_file, not is_dot_file
-
-####################### end _check_limits code block
-
- @staticmethod
- def _remove_protected(
- pkgs,
- clean_me
- ):
- """Remove files owned by some protected packages.
-
- @returns packages to clean
- @rtype: dictionary
- """
- for cpv in pkgs:
- uris = pkgs[cpv].split()
- uris.reverse()
- while uris:
- uri = uris.pop()
- if uris and uris[-1] == "->":
- operator = uris.pop() # noqa
- file = uris.pop()
- else:
- file = os.path.basename(uri)
- if file in clean_me:
- del clean_me[file]
- # no need to waste IO time if there is nothing left to clean
- if not len(clean_me):
- return clean_me
- return clean_me
-
- def _non_destructive(self,
- destructive,
- fetch_restricted,
- pkgs_ = None,
- hosts_cpvs=None
- ):
- """performs the non-destructive checks
-
- @param destructive: boolean
- @param pkgs_: starting dictionary to add to
- defaults to {}.
-
- @returns packages and thier SRC_URI's: {cpv: src_uri,}
- @rtype: dictionary
- """
- if pkgs_ is None:
- pkgs = {}
- else:
- pkgs = pkgs_.copy()
- deprecated = {}
- # the following code block was split to optimize for speed
- # list all CPV from portree (yeah, that takes time...)
- self.output(" - getting complete ebuild list")
- cpvs = set(self.portdb.cpv_all())
- installed_cpvs = set(self.vardb.cpv_all())
- # now add any installed cpv's that are not in the tree or overlays
- cpvs.update(installed_cpvs)
- # Add any installed cpvs from hosts on the network, if any
- if hosts_cpvs:
- cpvs.update(hosts_cpvs)
- installed_cpvs.update(hosts_cpvs)
- if fetch_restricted and destructive:
- self.output(" - getting source file names " +
- "for %d installed ebuilds" %len(installed_cpvs))
- pkgs, _deprecated = self._unrestricted(pkgs, installed_cpvs)
- deprecated.update(_deprecated)
- # remove the installed cpvs then check the remaining for fetch restiction
- cpvs.difference_update(installed_cpvs)
- self.output(" - getting fetch-restricted source file names " +
- "for %d remaining ebuilds" %len(cpvs))
- pkgs, _deprecated = self._fetch_restricted(pkgs, cpvs)
- deprecated.update(_deprecated)
- # save the installed cpv list to re-use in _destructive()
- self.installed_cpvs = installed_cpvs.copy()
- else:
- self.output(" - getting source file names " +
- "for %d ebuilds" %len(cpvs))
- pkgs, _deprecated = self._unrestricted(pkgs, cpvs)
- deprecated.update(_deprecated)
- return pkgs, deprecated
-
- def _fetch_restricted(self, pkgs_, cpvs):
- """perform fetch restricted non-destructive source
- filename lookups
-
- @param pkgs_: starting dictionary to add to
- @param cpvs: set of (cat/pkg-ver, ...) identifiers
-
- @return a new pkg dictionary
- @rtype: dictionary
- """
- if pkgs_ is None:
- pkgs = {}
- else:
- pkgs = pkgs_.copy()
- deprecated = {}
- for cpv in cpvs:
- # get SRC_URI and RESTRICT from aux_get
- try: # main portdb
- (src_uri,restrict) = \
- self.portdb.aux_get(cpv,["SRC_URI","RESTRICT"])
- # keep fetch-restricted check
- # inside try so it is bypassed on KeyError
- if 'fetch' in restrict:
- pkgs[cpv] = src_uri
- except KeyError:
- try: # installed vardb
- (src_uri,restrict) = \
- self.vardb.aux_get(cpv,["SRC_URI","RESTRICT"])
- deprecated[cpv] = src_uri
- self.output(DEPRECATED %cpv)
- # keep fetch-restricted check
- # inside try so it is bypassed on KeyError
- if 'fetch' in restrict:
- pkgs[cpv] = src_uri
- except KeyError:
- self.output(" - Key Error looking up: " + cpv)
- return pkgs, deprecated
-
- def _unrestricted(self, pkgs_, cpvs):
- """Perform unrestricted source filenames lookups
-
- @param pkgs_: starting packages dictionary
- @param cpvs: set of (cat/pkg-ver, ...) identifiers
-
- @return a new pkg dictionary
- @rtype: dictionary
- """
- if pkgs_ is None:
- pkgs = {}
- else:
- pkgs = pkgs_.copy()
- deprecated = {}
- for cpv in cpvs:
- # get SRC_URI from aux_get
- try:
- pkgs[cpv] = self.portdb.aux_get(cpv,["SRC_URI"])[0]
- except KeyError:
- try: # installed vardb
- pkgs[cpv] = self.vardb.aux_get(cpv,["SRC_URI"])[0]
- deprecated[cpv] = pkgs[cpv]
- self.output(DEPRECATED %cpv)
- except KeyError:
- self.output(" - Key Error looking up: " + cpv)
- return pkgs, deprecated
-
- def _destructive(self,
- package_names,
- exclude,
- pkgs_=None,
- installed_included=False
- ):
- """Builds on pkgs according to input options
-
- @param package_names: boolean
- @param exclude: an exclusion dict as defined in
- exclude.parseExcludeFile class.
- @param pkgs: starting dictionary to add to
- defaults to {}.
- @param installed_included: bool. pkgs already
- has the installed cpv's added.
-
- @returns pkgs: {cpv: src_uri,}
- """
- if pkgs_ is None:
- pkgs = {}
- else:
- pkgs = pkgs_.copy()
- deprecated = {}
- pkgset = set()
- if not installed_included:
- if not package_names:
- # list all installed CPV's from vartree
- #print( "_destructive: getting vardb.cpv_all")
- if not self.installed_cpvs:
- pkgset.update(self.vardb.cpv_all())
- else:
- pkgset.update(self.installed_cpvs)
- self.output(" - processing %s installed ebuilds" % len(pkgset))
- elif package_names:
- # list all CPV's from portree for CP's in vartree
- #print( "_destructive: getting vardb.cp_all")
- cps = self.vardb.cp_all()
- self.output(" - processing %s installed packages" % len(cps))
- for package in cps:
- pkgset.update(self.portdb.cp_list(package))
- self.output(" - processing excluded")
- excludes = self._get_excludes(exclude)
- excludes_length = len(excludes)
- dprint("excludes", "EXCLUDES LENGTH =%d" %excludes_length)
- pkgset.update(excludes)
- pkgs_done = set(list(pkgs))
- pkgset.difference_update(pkgs_done)
- self.output(
- " - (%d of %d total) additional excluded packages to get source filenames for"
- %(len(pkgset), excludes_length))
- #self.output(" - processing %d ebuilds for filenames" %len(pkgset))
- pkgs, _deprecated = self._unrestricted(pkgs, pkgset)
- deprecated.update(_deprecated)
- #self.output(" - done...")
- return pkgs, deprecated
-
- def _get_excludes(self, exclude):
- """Expands the exclude dictionary into a set of
- CPV's
-
- @param exclude: dictionary of exclusion categories,
- packages to exclude from the cleaning
-
- @rtype: set
- @return set of package cpv's
- """
- pkgset = set()
- for cp in exclDictExpand(exclude):
- # add packages from the exclude file
- dprint("excludes", "_GET_EXCLUDES, cp=" + \
- cp+", "+str(self.portdb.cp_list(cp)))
- pkgset.update(self.portdb.cp_list(cp))
- return pkgset
-
- def _check_excludes(self, exclude, clean_me):
- """Performs a last minute check on remaining filenames
- to see if they should be protected. Since if the pkg-version
- was deprecated it would not have been matched to a
- source filename and removed.
-
- @param exclude: an exclusion dictionary
- @param clean_me: the list of filenames for cleaning
-
- @rtype: dict of packages to clean
- """
- saved = {}
- pn_excludes = exclDictExpandPkgname(exclude)
- dprint("excludes", "_check_excludes: made it here ;)")
- if not pn_excludes:
- return clean_me, saved
- dprint("excludes", pn_excludes)
- for key in list(clean_me):
- if exclMatchFilename(pn_excludes, key):
- saved[key] = clean_me[key]
- del clean_me[key]
- self.output(" ...Saved excluded package filename: " + key)
- return clean_me, saved
+ """
+
+ @param output: verbose output method or (lambda x: None) to turn off
+ @param vardb: defaults to portage.db[portage.root]["vartree"].dbapi
+ is overridden for testing.
+ @param portdb: defaults to portage.portdb and is overriden for testing."""
+
+ def __init__(
+ self,
+ output,
+ portdb=portage.portdb,
+ vardb=portage.db[portage.root]["vartree"].dbapi,
+ ):
+ self.vardb = vardb
+ self.portdb = portdb
+ self.output = output
+ self.installed_cpvs = None
+
+ def findDistfiles(
+ self,
+ exclude=None,
+ destructive=False,
+ fetch_restricted=False,
+ package_names=False,
+ time_limit=0,
+ size_limit=0,
+ _distdir=distdir,
+ deprecate=False,
+ extra_checks=(),
+ ):
+ """Find all obsolete distfiles.
+
+ XXX: what about cvs ebuilds?
+ I should install some to see where it goes...
+
+ @param exclude: an exclusion dict as defined in
+ exclude.parseExcludeFile class.
+ @param destructive: boolean, defaults to False
+ @param fetch_restricted: boolean, defaults to False
+ @param package_names: boolean, defaults to False.
+ @param time_limit: integer time value as returned by parseTime()
+ @param size_limit: integer value of max. file size to keep or 0 to ignore.
+ @param _distdir: path to the distfiles dir being checked, defaults to portage.
+ @param deprecate: bool to control checking the clean dict. files for exclusion
+
+ @rtype: dict
+ @return dict. of package files to clean i.e. {'cat/pkg-ver.tbz2': [filename],}
+ """
+ if exclude is None:
+ exclude = {}
+ clean_me = {}
+ pkgs = {}
+ saved = {}
+ deprecated = {}
+ installed_included = False
+ # create a big CPV->SRC_URI dict of packages
+ # whose distfiles should be kept
+ if (not destructive) or fetch_restricted:
+ self.output("...non-destructive type search")
+ pkgs, _deprecated = self._non_destructive(destructive, fetch_restricted)
+ deprecated.update(_deprecated)
+ installed_included = True
+ if destructive:
+ self.output(
+ "...destructive type search: %d packages already found" % len(pkgs)
+ )
+ pkgs, _deprecated = self._destructive(
+ package_names, exclude, pkgs, installed_included
+ )
+ deprecated.update(_deprecated)
+ # gather the files to be cleaned
+ self.output("...checking limits for %d ebuild sources" % len(pkgs))
+
+ checks = self._get_default_checks(size_limit, time_limit, exclude, destructive)
+ checks.extend(extra_checks)
+ clean_me = self._check_limits(_distdir, checks, clean_me)
+ # remove any protected files from the list
+ self.output(
+ "...removing protected sources from %s candidates to clean" % len(clean_me)
+ )
+ clean_me = self._remove_protected(pkgs, clean_me)
+ if not deprecate and len(exclude) and len(clean_me):
+ self.output(
+ "...checking final for exclusion from "
+ + "%s remaining candidates to clean" % len(clean_me)
+ )
+ clean_me, saved = self._check_excludes(exclude, clean_me)
+ return clean_me, saved, deprecated
+
+ # begin _check_limits code block
+
+ def _get_default_checks(self, size_limit, time_limit, excludes, destructive):
+ # checks =[(self._isreg_check_, "is_reg_check")]
+ checks = [self._isreg_check_]
+ if "filenames" in excludes:
+ # checks.append((partial(self._filenames_check_, excludes), "Filenames_check"))
+ checks.append(partial(self._filenames_check_, excludes))
+ else:
+ self.output(" - skipping exclude filenames check")
+ if size_limit:
+ # checks.append((partial(self._size_check_, size_limit), "size_check"))
+ checks.append(partial(self._size_check_, size_limit))
+ else:
+ self.output(" - skipping size limit check")
+ if time_limit:
+ # print("time_limit = ", time_limit/1000000,"M sec")
+ # checks.append((partial(self._time_check_, time_limit), "time_check"))
+ checks.append(partial(self._time_check_, time_limit))
+ else:
+ self.output(" - skipping time limit check")
+ if destructive:
+ self.output(" - skipping dot files check")
+ else:
+ checks.append(self._dotfile_check_)
+ return checks
+
+ def _check_limits(self, _distdir, checks, clean_me=None):
+ """Checks files if they exceed size and/or time_limits, etc.
+
+ To start with everything is considered dirty and is excluded
+ only if it matches some condition.
+ """
+ if clean_me is None:
+ clean_me = {}
+ for file in os.listdir(_distdir):
+ filepath = os.path.join(_distdir, file)
+ try:
+ file_stat = os.lstat(filepath)
+ except EnvironmentError:
+ continue
+ is_dirty = False
+ # for check, check_name in checks:
+ for check in checks:
+ should_break, is_dirty = check(file_stat, file)
+ if should_break:
+ break
+
+ if is_dirty:
+ # print( "%s Adding file to clean_list:" %check_name, file)
+ clean_me[file] = [filepath]
+ return clean_me
+
+ @staticmethod
+ def _isreg_check_(file_stat, file):
+ """check if file is a regular file."""
+ is_reg_file = stat.S_ISREG(file_stat[stat.ST_MODE])
+ return not is_reg_file, is_reg_file
+
+ @staticmethod
+ def _size_check_(size_limit, file_stat, file):
+ """checks if the file size exceeds the size_limit"""
+ if file_stat[stat.ST_SIZE] >= size_limit:
+ # print( "size mismatch ", file, file_stat[stat.ST_SIZE])
+ return True, False
+ return False, True
+
+ @staticmethod
+ def _time_check_(time_limit, file_stat, file):
+ """checks if the file exceeds the time_limit
+ (think forward, not back, time keeps increasing)"""
+ if file_stat[stat.ST_MTIME] >= time_limit:
+ # print( "time match too young ", file, file_stat[stat.ST_MTIME]/1000000,"M sec.")
+ return True, False
+ # print( "time match too old", file, file_stat[stat.ST_MTIME]/1000000,"M sec.")
+ return False, True
+
+ @staticmethod
+ def _filenames_check_(exclude, file_stat, file):
+ """checks if the file matches an exclusion file listing"""
+ # Try to match file name directly
+ if file in exclude["filenames"]:
+ return True, False
+ # See if file matches via regular expression matching
+ else:
+ file_match = False
+ for file_entry in exclude["filenames"]:
+ if exclude["filenames"][file_entry].match(file):
+ file_match = True
+ break
+ if file_match:
+ # print( "filename match ", file)
+ return True, False
+ return False, True
+
+ @staticmethod
+ def _dotfile_check_(file_stat, file):
+ """check if file is a regular file."""
+ head, tail = os.path.split(file)
+ if tail:
+ is_dot_file = tail.startswith(".")
+ return is_dot_file, not is_dot_file
+
+ # end _check_limits code block
+
+ @staticmethod
+ def _remove_protected(pkgs, clean_me):
+ """Remove files owned by some protected packages.
+
+ @returns packages to clean
+ @rtype: dictionary
+ """
+ for cpv in pkgs:
+ uris = pkgs[cpv].split()
+ uris.reverse()
+ while uris:
+ uri = uris.pop()
+ if uris and uris[-1] == "->":
+ operator = uris.pop() # noqa
+ file = uris.pop()
+ else:
+ file = os.path.basename(uri)
+ if file in clean_me:
+ del clean_me[file]
+ # no need to waste IO time if there is nothing left to clean
+ if not len(clean_me):
+ return clean_me
+ return clean_me
+
+ def _non_destructive(
+ self, destructive, fetch_restricted, pkgs_=None, hosts_cpvs=None
+ ):
+ """performs the non-destructive checks
+
+ @param destructive: boolean
+ @param pkgs_: starting dictionary to add to
+ defaults to {}.
+
+ @returns packages and thier SRC_URI's: {cpv: src_uri,}
+ @rtype: dictionary
+ """
+ if pkgs_ is None:
+ pkgs = {}
+ else:
+ pkgs = pkgs_.copy()
+ deprecated = {}
+ # the following code block was split to optimize for speed
+ # list all CPV from portree (yeah, that takes time...)
+ self.output(" - getting complete ebuild list")
+ cpvs = set(self.portdb.cpv_all())
+ installed_cpvs = set(self.vardb.cpv_all())
+ # now add any installed cpv's that are not in the tree or overlays
+ cpvs.update(installed_cpvs)
+ # Add any installed cpvs from hosts on the network, if any
+ if hosts_cpvs:
+ cpvs.update(hosts_cpvs)
+ installed_cpvs.update(hosts_cpvs)
+ if fetch_restricted and destructive:
+ self.output(
+ " - getting source file names "
+ + "for %d installed ebuilds" % len(installed_cpvs)
+ )
+ pkgs, _deprecated = self._unrestricted(pkgs, installed_cpvs)
+ deprecated.update(_deprecated)
+ # remove the installed cpvs then check the remaining for fetch restiction
+ cpvs.difference_update(installed_cpvs)
+ self.output(
+ " - getting fetch-restricted source file names "
+ + "for %d remaining ebuilds" % len(cpvs)
+ )
+ pkgs, _deprecated = self._fetch_restricted(pkgs, cpvs)
+ deprecated.update(_deprecated)
+ # save the installed cpv list to re-use in _destructive()
+ self.installed_cpvs = installed_cpvs.copy()
+ else:
+ self.output(
+ " - getting source file names " + "for %d ebuilds" % len(cpvs)
+ )
+ pkgs, _deprecated = self._unrestricted(pkgs, cpvs)
+ deprecated.update(_deprecated)
+ return pkgs, deprecated
+
+ def _fetch_restricted(self, pkgs_, cpvs):
+ """perform fetch restricted non-destructive source
+ filename lookups
+
+ @param pkgs_: starting dictionary to add to
+ @param cpvs: set of (cat/pkg-ver, ...) identifiers
+
+ @return a new pkg dictionary
+ @rtype: dictionary
+ """
+ if pkgs_ is None:
+ pkgs = {}
+ else:
+ pkgs = pkgs_.copy()
+ deprecated = {}
+ for cpv in cpvs:
+ # get SRC_URI and RESTRICT from aux_get
+ try: # main portdb
+ (src_uri, restrict) = self.portdb.aux_get(cpv, ["SRC_URI", "RESTRICT"])
+ # keep fetch-restricted check
+ # inside try so it is bypassed on KeyError
+ if "fetch" in restrict:
+ pkgs[cpv] = src_uri
+ except KeyError:
+ try: # installed vardb
+ (src_uri, restrict) = self.vardb.aux_get(
+ cpv, ["SRC_URI", "RESTRICT"]
+ )
+ deprecated[cpv] = src_uri
+ self.output(DEPRECATED % cpv)
+ # keep fetch-restricted check
+ # inside try so it is bypassed on KeyError
+ if "fetch" in restrict:
+ pkgs[cpv] = src_uri
+ except KeyError:
+ self.output(" - Key Error looking up: " + cpv)
+ return pkgs, deprecated
+
+ def _unrestricted(self, pkgs_, cpvs):
+ """Perform unrestricted source filenames lookups
+
+ @param pkgs_: starting packages dictionary
+ @param cpvs: set of (cat/pkg-ver, ...) identifiers
+
+ @return a new pkg dictionary
+ @rtype: dictionary
+ """
+ if pkgs_ is None:
+ pkgs = {}
+ else:
+ pkgs = pkgs_.copy()
+ deprecated = {}
+ for cpv in cpvs:
+ # get SRC_URI from aux_get
+ try:
+ pkgs[cpv] = self.portdb.aux_get(cpv, ["SRC_URI"])[0]
+ except KeyError:
+ try: # installed vardb
+ pkgs[cpv] = self.vardb.aux_get(cpv, ["SRC_URI"])[0]
+ deprecated[cpv] = pkgs[cpv]
+ self.output(DEPRECATED % cpv)
+ except KeyError:
+ self.output(" - Key Error looking up: " + cpv)
+ return pkgs, deprecated
+
+ def _destructive(
+ self, package_names, exclude, pkgs_=None, installed_included=False
+ ):
+ """Builds on pkgs according to input options
+
+ @param package_names: boolean
+ @param exclude: an exclusion dict as defined in
+ exclude.parseExcludeFile class.
+ @param pkgs: starting dictionary to add to
+ defaults to {}.
+ @param installed_included: bool. pkgs already
+ has the installed cpv's added.
+
+ @returns pkgs: {cpv: src_uri,}
+ """
+ if pkgs_ is None:
+ pkgs = {}
+ else:
+ pkgs = pkgs_.copy()
+ deprecated = {}
+ pkgset = set()
+ if not installed_included:
+ if not package_names:
+ # list all installed CPV's from vartree
+ # print( "_destructive: getting vardb.cpv_all")
+ if not self.installed_cpvs:
+ pkgset.update(self.vardb.cpv_all())
+ else:
+ pkgset.update(self.installed_cpvs)
+ self.output(" - processing %s installed ebuilds" % len(pkgset))
+ elif package_names:
+ # list all CPV's from portree for CP's in vartree
+ # print( "_destructive: getting vardb.cp_all")
+ cps = self.vardb.cp_all()
+ self.output(" - processing %s installed packages" % len(cps))
+ for package in cps:
+ pkgset.update(self.portdb.cp_list(package))
+ self.output(" - processing excluded")
+ excludes = self._get_excludes(exclude)
+ excludes_length = len(excludes)
+ dprint("excludes", "EXCLUDES LENGTH =%d" % excludes_length)
+ pkgset.update(excludes)
+ pkgs_done = set(list(pkgs))
+ pkgset.difference_update(pkgs_done)
+ self.output(
+ " - (%d of %d total) additional excluded packages to get source filenames for"
+ % (len(pkgset), excludes_length)
+ )
+ # self.output(" - processing %d ebuilds for filenames" %len(pkgset))
+ pkgs, _deprecated = self._unrestricted(pkgs, pkgset)
+ deprecated.update(_deprecated)
+ # self.output(" - done...")
+ return pkgs, deprecated
+
+ def _get_excludes(self, exclude):
+ """Expands the exclude dictionary into a set of
+ CPV's
+
+ @param exclude: dictionary of exclusion categories,
+ packages to exclude from the cleaning
+
+ @rtype: set
+ @return set of package cpv's
+ """
+ pkgset = set()
+ for cp in exclDictExpand(exclude):
+ # add packages from the exclude file
+ dprint(
+ "excludes",
+ "_GET_EXCLUDES, cp=" + cp + ", " + str(self.portdb.cp_list(cp)),
+ )
+ pkgset.update(self.portdb.cp_list(cp))
+ return pkgset
+
+ def _check_excludes(self, exclude, clean_me):
+ """Performs a last minute check on remaining filenames
+ to see if they should be protected. Since if the pkg-version
+ was deprecated it would not have been matched to a
+ source filename and removed.
+
+ @param exclude: an exclusion dictionary
+ @param clean_me: the list of filenames for cleaning
+
+ @rtype: dict of packages to clean
+ """
+ saved = {}
+ pn_excludes = exclDictExpandPkgname(exclude)
+ dprint("excludes", "_check_excludes: made it here ;)")
+ if not pn_excludes:
+ return clean_me, saved
+ dprint("excludes", pn_excludes)
+ for key in list(clean_me):
+ if exclMatchFilename(pn_excludes, key):
+ saved[key] = clean_me[key]
+ del clean_me[key]
+ self.output(" ...Saved excluded package filename: " + key)
+ return clean_me, saved
def _deps_equal(deps_a, eapi_a, deps_b, eapi_b, uselist=None):
- """Compare two dependency lists given a set of USE flags"""
- if deps_a == deps_b: return True
+ """Compare two dependency lists given a set of USE flags"""
+ if deps_a == deps_b:
+ return True
- deps_a = use_reduce(deps_a, uselist=uselist, eapi=eapi_a, token_class=Atom)
- deps_b = use_reduce(deps_b, uselist=uselist, eapi=eapi_b, token_class=Atom)
- strip_slots(deps_a)
- strip_slots(deps_b)
- return deps_a == deps_b
+ deps_a = use_reduce(deps_a, uselist=uselist, eapi=eapi_a, token_class=Atom)
+ deps_b = use_reduce(deps_b, uselist=uselist, eapi=eapi_b, token_class=Atom)
+ strip_slots(deps_a)
+ strip_slots(deps_b)
+ return deps_a == deps_b
def findPackages(
- options,
- exclude=None,
- destructive=False,
- time_limit=0,
- package_names=False,
- pkgdir=None,
- port_dbapi=portage.db[portage.root]["porttree"].dbapi,
- var_dbapi=portage.db[portage.root]["vartree"].dbapi
- ):
- """Find obsolete binary packages.
-
- @param options: dict of options determined at runtime
- @type options: dict
- @param exclude: exclusion dict (as defined in the exclude.parseExcludeFile class)
- @type exclude: dict, optional
- @param destructive: binpkg is obsolete if not installed (default: `False`)
- @type destructive: bool, optional
- @param time_limit: exclude binpkg if newer than time value as returned by parseTime()
- @type time_limit: int, optional
- @param package_names: exclude all binpkg versions if package is installed
- (used with `destructive=True`) (default: `False`)
- @type package_names: bool, optional
- @param pkgdir: path to the binpkg cache (PKGDIR)
- @type pkgdir: str
- @param port_dbapi: defaults to portage.db[portage.root]["porttree"].dbapi
- Can be overridden for tests.
- @param var_dbapi: defaults to portage.db[portage.root]["vartree"].dbapi
- Can be overridden for tests.
-
- @return binary packages to remove. e.g. {'cat/pkg-ver': [filepath]}
- @rtype: dict
- """
- if exclude is None:
- exclude = {}
-
- # Access test, os.walk does not error for "no read permission"
- try:
- test = os.listdir(pkgdir)
- del test
- except EnvironmentError as er:
- if options['ignore-failure']:
- exit(0)
- print(pp.error("Error accessing PKGDIR."), file=sys.stderr)
- print(pp.error("(Check your make.conf file and environment)."), file=sys.stderr)
- print(pp.error("Error: %s" % str(er)), file=sys.stderr)
- exit(1)
-
- # Create a dictionary of all installed packages
- if destructive and package_names:
- installed = dict.fromkeys(var_dbapi.cp_all())
- else:
- installed = {}
-
- # Dictionary of binary packages to clean. Organized as cpv->[pkgs] in order
- # to support FEATURES=binpkg-multi-instance.
- dead_binpkgs = {}
-
- bin_dbapi = portage.binarytree(pkgdir=pkgdir, settings=var_dbapi.settings).dbapi
- for cpv in bin_dbapi.cpv_all():
- cp = portage.cpv_getkey(cpv)
-
- # Exclude per --exclude-file=...
- if exclDictMatchCP(exclude, cp):
- continue
-
- # Exclude if binpkg is newer than --time-limit=...
- if time_limit:
- mtime = int(bin_dbapi.aux_get(cpv, ['_mtime_'])[0])
- if mtime >= time_limit:
- continue
-
- # Exclude if binpkg exists in the porttree and not --deep
- if not destructive and port_dbapi.cpv_exists(cpv):
- if not options['changed-deps']:
- continue
-
- dep_keys = ('RDEPEND', 'PDEPEND')
- keys = ('EAPI', 'USE') + dep_keys
- binpkg_metadata = dict(zip(keys, bin_dbapi.aux_get(cpv, keys)))
- ebuild_metadata = dict(zip(keys, port_dbapi.aux_get(cpv, keys)))
-
- if _deps_equal(' '.join(binpkg_metadata[key] for key in dep_keys), binpkg_metadata['EAPI'],
- ' '.join(ebuild_metadata[key] for key in dep_keys), ebuild_metadata['EAPI'],
- frozenset(binpkg_metadata['USE'].split())):
- continue
-
- if destructive and var_dbapi.cpv_exists(cpv):
- # Exclude if an instance of the package is installed due to
- # the --package-names option.
- if cp in installed and port_dbapi.cpv_exists(cpv):
- continue
-
- # Exclude if BUILD_TIME of binpkg is same as vartree
- buildtime = var_dbapi.aux_get(cpv, ['BUILD_TIME'])[0]
- if buildtime == bin_dbapi.aux_get(cpv, ['BUILD_TIME'])[0]:
- continue
-
- binpkg_path = bin_dbapi.bintree.getname(cpv)
- dead_binpkgs.setdefault(cpv, []).append(binpkg_path)
-
- return dead_binpkgs
+ options,
+ exclude=None,
+ destructive=False,
+ time_limit=0,
+ package_names=False,
+ pkgdir=None,
+ port_dbapi=portage.db[portage.root]["porttree"].dbapi,
+ var_dbapi=portage.db[portage.root]["vartree"].dbapi,
+):
+ """Find obsolete binary packages.
+
+ @param options: dict of options determined at runtime
+ @type options: dict
+ @param exclude: exclusion dict (as defined in the exclude.parseExcludeFile class)
+ @type exclude: dict, optional
+ @param destructive: binpkg is obsolete if not installed (default: `False`)
+ @type destructive: bool, optional
+ @param time_limit: exclude binpkg if newer than time value as returned by parseTime()
+ @type time_limit: int, optional
+ @param package_names: exclude all binpkg versions if package is installed
+ (used with `destructive=True`) (default: `False`)
+ @type package_names: bool, optional
+ @param pkgdir: path to the binpkg cache (PKGDIR)
+ @type pkgdir: str
+ @param port_dbapi: defaults to portage.db[portage.root]["porttree"].dbapi
+ Can be overridden for tests.
+ @param var_dbapi: defaults to portage.db[portage.root]["vartree"].dbapi
+ Can be overridden for tests.
+
+ @return binary packages to remove. e.g. {'cat/pkg-ver': [filepath]}
+ @rtype: dict
+ """
+ if exclude is None:
+ exclude = {}
+
+ # Access test, os.walk does not error for "no read permission"
+ try:
+ test = os.listdir(pkgdir)
+ del test
+ except EnvironmentError as er:
+ if options["ignore-failure"]:
+ exit(0)
+ print(pp.error("Error accessing PKGDIR."), file=sys.stderr)
+ print(pp.error("(Check your make.conf file and environment)."), file=sys.stderr)
+ print(pp.error("Error: %s" % str(er)), file=sys.stderr)
+ exit(1)
+
+ # Create a dictionary of all installed packages
+ if destructive and package_names:
+ installed = dict.fromkeys(var_dbapi.cp_all())
+ else:
+ installed = {}
+
+ # Dictionary of binary packages to clean. Organized as cpv->[pkgs] in order
+ # to support FEATURES=binpkg-multi-instance.
+ dead_binpkgs = {}
+
+ bin_dbapi = portage.binarytree(pkgdir=pkgdir, settings=var_dbapi.settings).dbapi
+ for cpv in bin_dbapi.cpv_all():
+ cp = portage.cpv_getkey(cpv)
+
+ # Exclude per --exclude-file=...
+ if exclDictMatchCP(exclude, cp):
+ continue
+
+ # Exclude if binpkg is newer than --time-limit=...
+ if time_limit:
+ mtime = int(bin_dbapi.aux_get(cpv, ["_mtime_"])[0])
+ if mtime >= time_limit:
+ continue
+
+ # Exclude if binpkg exists in the porttree and not --deep
+ if not destructive and port_dbapi.cpv_exists(cpv):
+ if not options["changed-deps"]:
+ continue
+
+ dep_keys = ("RDEPEND", "PDEPEND")
+ keys = ("EAPI", "USE") + dep_keys
+ binpkg_metadata = dict(zip(keys, bin_dbapi.aux_get(cpv, keys)))
+ ebuild_metadata = dict(zip(keys, port_dbapi.aux_get(cpv, keys)))
+
+ if _deps_equal(
+ " ".join(binpkg_metadata[key] for key in dep_keys),
+ binpkg_metadata["EAPI"],
+ " ".join(ebuild_metadata[key] for key in dep_keys),
+ ebuild_metadata["EAPI"],
+ frozenset(binpkg_metadata["USE"].split()),
+ ):
+ continue
+
+ if destructive and var_dbapi.cpv_exists(cpv):
+ # Exclude if an instance of the package is installed due to
+ # the --package-names option.
+ if cp in installed and port_dbapi.cpv_exists(cpv):
+ continue
+
+ # Exclude if BUILD_TIME of binpkg is same as vartree
+ buildtime = var_dbapi.aux_get(cpv, ["BUILD_TIME"])[0]
+ if buildtime == bin_dbapi.aux_get(cpv, ["BUILD_TIME"])[0]:
+ continue
+
+ binpkg_path = bin_dbapi.bintree.getname(cpv)
+ dead_binpkgs.setdefault(cpv, []).append(binpkg_path)
+
+ return dead_binpkgs
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/ekeyword/ekeyword.py b/pym/gentoolkit/ekeyword/ekeyword.py
index da0fd58..13b93ad 100755
--- a/pym/gentoolkit/ekeyword/ekeyword.py
+++ b/pym/gentoolkit/ekeyword/ekeyword.py
@@ -51,7 +51,7 @@ import portage
from portage.output import colorize, nocolor
-__version__ = 'git'
+__version__ = "git"
# Operation object that describes how to perform a change.
# Args:
@@ -62,432 +62,507 @@ __version__ = 'git'
# '^': Delete |arch| so it isn't listed at all
# arch: The required arch to update
# ref_arch: Set |arch| status to this arch (ignoring |op|)
-Op = collections.namedtuple('Op', ('op', 'arch', 'ref_arch'))
+Op = collections.namedtuple("Op", ("op", "arch", "ref_arch"))
def warning(msg):
- """Write |msg| as a warning to stderr"""
- print('warning: %s' % msg, file=sys.stderr)
+ """Write |msg| as a warning to stderr"""
+ print("warning: %s" % msg, file=sys.stderr)
def keyword_to_arch(keyword):
- """Given a keyword, strip it down to its arch value
+ """Given a keyword, strip it down to its arch value
- When an ARCH shows up in KEYWORDS, it may have prefixes like ~ or -.
- Strip all that cruft off to get back to the ARCH.
- """
- return keyword.lstrip('-~')
+ When an ARCH shows up in KEYWORDS, it may have prefixes like ~ or -.
+ Strip all that cruft off to get back to the ARCH.
+ """
+ return keyword.lstrip("-~")
def sort_keywords(arches):
- """Sort |arches| list in the order developers expect
+ """Sort |arches| list in the order developers expect
- This is vaguely defined because it is kind of vaguely defined once you get
- past the basic (Linux-only) keywords.
+ This is vaguely defined because it is kind of vaguely defined once you get
+ past the basic (Linux-only) keywords.
- Args:
- arches: An iterable of ARCH values.
+ Args:
+ arches: An iterable of ARCH values.
- Returns:
- A sorted list of |arches|
- """
- keywords = []
+ Returns:
+ A sorted list of |arches|
+ """
+ keywords = []
- # Globs always come first.
- for g in ('-*', '*', '~*'):
- if g in arches:
- arches.remove(g)
- keywords.append(g)
+ # Globs always come first.
+ for g in ("-*", "*", "~*"):
+ if g in arches:
+ arches.remove(g)
+ keywords.append(g)
- def arch_key(keyword):
- """Callback for python sorting functions
+ def arch_key(keyword):
+ """Callback for python sorting functions
- Used to turn a Gentoo keyword into a sortable form.
- """
- # Sort independent of leading marker (~ or -).
- arch = keyword_to_arch(keyword)
+ Used to turn a Gentoo keyword into a sortable form.
+ """
+ # Sort independent of leading marker (~ or -).
+ arch = keyword_to_arch(keyword)
- # A keyword may have a "-" in it. We split on that and sort
- # by the two resulting items. The part after the hyphen is
- # the primary key.
- if '-' in arch:
- arch, plat = arch.split('-', 1)
- else:
- arch, plat = arch, ''
+ # A keyword may have a "-" in it. We split on that and sort
+ # by the two resulting items. The part after the hyphen is
+ # the primary key.
+ if "-" in arch:
+ arch, plat = arch.split("-", 1)
+ else:
+ arch, plat = arch, ""
- return (plat, arch)
+ return (plat, arch)
- keywords += sorted(arches, key=arch_key)
+ keywords += sorted(arches, key=arch_key)
- return keywords
+ return keywords
-def diff_keywords(old_keywords, new_keywords, style='color-inline'):
- """Show pretty diff between list of keywords
+def diff_keywords(old_keywords, new_keywords, style="color-inline"):
+ """Show pretty diff between list of keywords
- Args:
- old_keywords: The old set of KEYWORDS
- new_keywords: The new set of KEYWORDS
- style: The diff style
+ Args:
+ old_keywords: The old set of KEYWORDS
+ new_keywords: The new set of KEYWORDS
+ style: The diff style
- Returns:
- A string containing the diff output ready to shown to the user
- """
- def show_diff(s):
- output = ''
+ Returns:
+ A string containing the diff output ready to shown to the user
+ """
- for tag, i0, i1, j0, j1 in s.get_opcodes():
+ def show_diff(s):
+ output = ""
- if tag == 'equal':
- output += s.a[i0:i1]
+ for tag, i0, i1, j0, j1 in s.get_opcodes():
- if tag in ('delete', 'replace'):
- o = s.a[i0:i1]
- if style == 'color-inline':
- o = colorize('bg_darkred', o)
- else:
- o = '-{%s}' % o
- output += o
+ if tag == "equal":
+ output += s.a[i0:i1]
- if tag in ('insert', 'replace'):
- o = s.b[j0:j1]
- if style == 'color-inline':
- o = colorize('bg_darkgreen', o)
- else:
- o = '+{%s}' % o
- output += o
+ if tag in ("delete", "replace"):
+ o = s.a[i0:i1]
+ if style == "color-inline":
+ o = colorize("bg_darkred", o)
+ else:
+ o = "-{%s}" % o
+ output += o
- return output
+ if tag in ("insert", "replace"):
+ o = s.b[j0:j1]
+ if style == "color-inline":
+ o = colorize("bg_darkgreen", o)
+ else:
+ o = "+{%s}" % o
+ output += o
- sold = str(' '.join(old_keywords))
- snew = str(' '.join(new_keywords))
- s = difflib.SequenceMatcher(str.isspace, sold, snew, autojunk=False)
- return show_diff(s)
+ return output
+
+ sold = str(" ".join(old_keywords))
+ snew = str(" ".join(new_keywords))
+ s = difflib.SequenceMatcher(str.isspace, sold, snew, autojunk=False)
+ return show_diff(s)
def process_keywords(keywords, ops, arch_status=None):
- """Process |ops| for |keywords|"""
- new_keywords = set(keywords).copy()
-
- # Process each op one at a time.
- for op, oarch, refarch in ops:
- # Figure out which keywords we need to modify.
- if oarch == 'all':
- if arch_status is None:
- raise ValueError('unable to process "all" w/out profiles.desc')
- old_arches = set([keyword_to_arch(a) for a in new_keywords])
- if op is None:
- # Process just stable keywords.
- arches = [k for k, v in arch_status.items()
- if v[1] == 'arch' and k in old_arches]
- else:
- # Process all possible keywords. We use the arch_status as a
- # master list. If it lacks some keywords, then we might miss
- # somethings here, but not much we can do.
- arches = list(old_arches)
-
- # We ignore the glob arch as we never want to tweak it.
- if '*' in arches:
- arches.remove('*')
-
- # For keywords that are explicitly disabled, do not update. When
- # people use `ekeyword ~all ...` or `ekeyword all ...`, they rarely
- # (if ever) want to change a '-sparc' to 'sparc' or '-sparc' to
- # '~sparc'. We force people to explicitly do `ekeyword sparc ...`
- # in these cases.
- arches = [x for x in arches if '-' + x not in new_keywords]
- else:
- arches = [oarch]
-
- if refarch:
- # Figure out the state for this arch based on the reference arch.
- # TODO: Add support for "all" keywords.
- # XXX: Should this ignore the '-' state ? Does it make sense to
- # sync e.g. "s390" to "-ppc" ?
- refkeyword = [x for x in new_keywords if refarch == keyword_to_arch(x)]
- if not refkeyword:
- op = '^'
- elif refkeyword[0].startswith('~'):
- op = '~'
- elif refkeyword[0].startswith('-'):
- op = '-'
- else:
- op = None
-
- # Finally do the actual update of the keywords list.
- for arch in arches:
- new_keywords -= set(['%s%s' % (x, arch) for x in ('', '~', '-')])
-
- if op is None:
- new_keywords.add(arch)
- elif op in ('~', '-'):
- new_keywords.add('%s%s' % (op, arch))
- elif op == '^':
- # Already deleted. Whee.
- pass
- else:
- raise ValueError('unknown operation %s' % op)
-
- return new_keywords
-
-
-def process_content(ebuild, data, ops, arch_status=None, verbose=0,
- quiet=0, style='color-inline'):
- """Process |ops| for |data|"""
- # Set up the user display style based on verbose/quiet settings.
- if verbose > 1:
- disp_name = ebuild
- def logit(msg):
- print('%s: %s' % (disp_name, msg))
- elif quiet > 1:
- def logit(_msg):
- pass
- else:
- # Chop the full path and the .ebuild suffix.
- disp_name = os.path.basename(ebuild)[:-7]
- def logit(msg):
- print('%s: %s' % (disp_name, msg))
-
- # Match any KEYWORDS= entry that isn't commented out.
- keywords_re = re.compile(r'^([^#]*\bKEYWORDS=)([\'"])(.*)(\2)(.*)')
- updated = False
- content = []
-
- # Walk each line of the ebuild looking for KEYWORDS to process.
- for line in data:
- m = keywords_re.match(line)
- if not m:
- content.append(line)
- continue
-
- # Ok, we've got it, now let's process things.
- old_keywords_original = m.group(3).split() # preserve original order
- old_keywords = set(old_keywords_original)
- new_keywords = process_keywords(
- old_keywords, ops, arch_status=arch_status)
-
- were_sorted_already = (
- old_keywords_original == sort_keywords(old_keywords_original))
-
- # Finally let's present the results to the user.
- if (new_keywords != old_keywords) or \
- (not ops and not were_sorted_already) or verbose:
- # Only do the diff work if something actually changed.
- updated = True
-
- if not ops:
- # We're sorting only so we want to compare with the
- # unsorted original (or changes in order will not show)
- old_keywords = old_keywords_original
- else:
- # We changed keywords so let's diff sorted versions
- # so that keywords changes are easy to spot
- old_keywords = sort_keywords(old_keywords)
-
- new_keywords = sort_keywords(new_keywords)
- line = '%s"%s"%s\n' % (m.group(1), ' '.join(new_keywords),
- m.group(5))
- if style in ('color-inline', 'inline'):
- logit(diff_keywords(old_keywords, new_keywords, style=style))
- else:
- if style == 'long-multi':
- logit(' '.join(['%*s' % (len(keyword_to_arch(x)) + 1, x)
- for x in old_keywords]))
- logit(' '.join(['%*s' % (len(keyword_to_arch(x)) + 1, x)
- for x in new_keywords]))
- else:
- deleted_keywords = [x for x in old_keywords
- if x not in new_keywords]
- logit('--- %s' % ' '.join(deleted_keywords))
- added_keywords = [x for x in new_keywords
- if x not in old_keywords]
- logit('+++ %s' % ' '.join(added_keywords))
-
- content.append(line)
-
- if not updated:
- logit('no updates')
-
- return updated, content
-
-
-def process_ebuild(ebuild, ops, arch_status=None, verbose=0, quiet=0,
- dry_run=False, style='color-inline', manifest=False):
- """Process |ops| for |ebuild|
-
- Args:
- ebuild: The ebuild file to operate on & update in place
- ops: An iterable of operations (Op objects) to perform on |ebuild|
- arch_status: A dict mapping default arches to their stability; see the
- load_profile_data function for more details
- verbose: Be verbose; show various status messages
- quiet: Be quiet; only show errors
- dry_run: Do not make any changes to |ebuild|; show what would be done
- style: The diff style
-
- Returns:
- Whether any updates were processed
- """
- with io.open(ebuild, encoding='utf8') as f:
- updated, content = process_content(
- ebuild, f, ops, arch_status=arch_status,
- verbose=verbose, quiet=quiet, style=style)
- if updated and not dry_run:
- with io.open(ebuild, 'w', encoding='utf8') as f:
- f.writelines(content)
- if manifest:
- subprocess.check_call(['ebuild', ebuild, 'manifest'])
- return updated
+ """Process |ops| for |keywords|"""
+ new_keywords = set(keywords).copy()
+
+ # Process each op one at a time.
+ for op, oarch, refarch in ops:
+ # Figure out which keywords we need to modify.
+ if oarch == "all":
+ if arch_status is None:
+ raise ValueError('unable to process "all" w/out profiles.desc')
+ old_arches = set([keyword_to_arch(a) for a in new_keywords])
+ if op is None:
+ # Process just stable keywords.
+ arches = [
+ k
+ for k, v in arch_status.items()
+ if v[1] == "arch" and k in old_arches
+ ]
+ else:
+ # Process all possible keywords. We use the arch_status as a
+ # master list. If it lacks some keywords, then we might miss
+ # somethings here, but not much we can do.
+ arches = list(old_arches)
+
+ # We ignore the glob arch as we never want to tweak it.
+ if "*" in arches:
+ arches.remove("*")
+
+ # For keywords that are explicitly disabled, do not update. When
+ # people use `ekeyword ~all ...` or `ekeyword all ...`, they rarely
+ # (if ever) want to change a '-sparc' to 'sparc' or '-sparc' to
+ # '~sparc'. We force people to explicitly do `ekeyword sparc ...`
+ # in these cases.
+ arches = [x for x in arches if "-" + x not in new_keywords]
+ else:
+ arches = [oarch]
+
+ if refarch:
+ # Figure out the state for this arch based on the reference arch.
+ # TODO: Add support for "all" keywords.
+ # XXX: Should this ignore the '-' state ? Does it make sense to
+ # sync e.g. "s390" to "-ppc" ?
+ refkeyword = [x for x in new_keywords if refarch == keyword_to_arch(x)]
+ if not refkeyword:
+ op = "^"
+ elif refkeyword[0].startswith("~"):
+ op = "~"
+ elif refkeyword[0].startswith("-"):
+ op = "-"
+ else:
+ op = None
+
+ # Finally do the actual update of the keywords list.
+ for arch in arches:
+ new_keywords -= set(["%s%s" % (x, arch) for x in ("", "~", "-")])
+
+ if op is None:
+ new_keywords.add(arch)
+ elif op in ("~", "-"):
+ new_keywords.add("%s%s" % (op, arch))
+ elif op == "^":
+ # Already deleted. Whee.
+ pass
+ else:
+ raise ValueError("unknown operation %s" % op)
+
+ return new_keywords
+
+
+def process_content(
+ ebuild, data, ops, arch_status=None, verbose=0, quiet=0, style="color-inline"
+):
+ """Process |ops| for |data|"""
+ # Set up the user display style based on verbose/quiet settings.
+ if verbose > 1:
+ disp_name = ebuild
+
+ def logit(msg):
+ print("%s: %s" % (disp_name, msg))
+
+ elif quiet > 1:
+
+ def logit(_msg):
+ pass
+
+ else:
+ # Chop the full path and the .ebuild suffix.
+ disp_name = os.path.basename(ebuild)[:-7]
+
+ def logit(msg):
+ print("%s: %s" % (disp_name, msg))
+
+ # Match any KEYWORDS= entry that isn't commented out.
+ keywords_re = re.compile(r'^([^#]*\bKEYWORDS=)([\'"])(.*)(\2)(.*)')
+ updated = False
+ content = []
+
+ # Walk each line of the ebuild looking for KEYWORDS to process.
+ for line in data:
+ m = keywords_re.match(line)
+ if not m:
+ content.append(line)
+ continue
+
+ # Ok, we've got it, now let's process things.
+ old_keywords_original = m.group(3).split() # preserve original order
+ old_keywords = set(old_keywords_original)
+ new_keywords = process_keywords(old_keywords, ops, arch_status=arch_status)
+
+ were_sorted_already = old_keywords_original == sort_keywords(
+ old_keywords_original
+ )
+
+ # Finally let's present the results to the user.
+ if (
+ (new_keywords != old_keywords)
+ or (not ops and not were_sorted_already)
+ or verbose
+ ):
+ # Only do the diff work if something actually changed.
+ updated = True
+
+ if not ops:
+ # We're sorting only so we want to compare with the
+ # unsorted original (or changes in order will not show)
+ old_keywords = old_keywords_original
+ else:
+ # We changed keywords so let's diff sorted versions
+ # so that keywords changes are easy to spot
+ old_keywords = sort_keywords(old_keywords)
+
+ new_keywords = sort_keywords(new_keywords)
+ line = '%s"%s"%s\n' % (m.group(1), " ".join(new_keywords), m.group(5))
+ if style in ("color-inline", "inline"):
+ logit(diff_keywords(old_keywords, new_keywords, style=style))
+ else:
+ if style == "long-multi":
+ logit(
+ " ".join(
+ [
+ "%*s" % (len(keyword_to_arch(x)) + 1, x)
+ for x in old_keywords
+ ]
+ )
+ )
+ logit(
+ " ".join(
+ [
+ "%*s" % (len(keyword_to_arch(x)) + 1, x)
+ for x in new_keywords
+ ]
+ )
+ )
+ else:
+ deleted_keywords = [
+ x for x in old_keywords if x not in new_keywords
+ ]
+ logit("--- %s" % " ".join(deleted_keywords))
+ added_keywords = [x for x in new_keywords if x not in old_keywords]
+ logit("+++ %s" % " ".join(added_keywords))
+
+ content.append(line)
+
+ if not updated:
+ logit("no updates")
+
+ return updated, content
+
+
+def process_ebuild(
+ ebuild,
+ ops,
+ arch_status=None,
+ verbose=0,
+ quiet=0,
+ dry_run=False,
+ style="color-inline",
+ manifest=False,
+):
+ """Process |ops| for |ebuild|
+
+ Args:
+ ebuild: The ebuild file to operate on & update in place
+ ops: An iterable of operations (Op objects) to perform on |ebuild|
+ arch_status: A dict mapping default arches to their stability; see the
+ load_profile_data function for more details
+ verbose: Be verbose; show various status messages
+ quiet: Be quiet; only show errors
+ dry_run: Do not make any changes to |ebuild|; show what would be done
+ style: The diff style
+
+ Returns:
+ Whether any updates were processed
+ """
+ with io.open(ebuild, encoding="utf8") as f:
+ updated, content = process_content(
+ ebuild,
+ f,
+ ops,
+ arch_status=arch_status,
+ verbose=verbose,
+ quiet=quiet,
+ style=style,
+ )
+ if updated and not dry_run:
+ with io.open(ebuild, "w", encoding="utf8") as f:
+ f.writelines(content)
+ if manifest:
+ subprocess.check_call(["ebuild", ebuild, "manifest"])
+ return updated
def portage_settings():
- """Return the portage settings we care about."""
- # Portage creates the db member on the fly which confuses the linter.
- return portage.db[portage.root]['vartree'].settings
+ """Return the portage settings we care about."""
+ # Portage creates the db member on the fly which confuses the linter.
+ return portage.db[portage.root]["vartree"].settings
def arg_to_op(arg):
- """Convert a command line |arg| to an Op"""
- arch_prefixes = ('-', '~', '^')
+ """Convert a command line |arg| to an Op"""
+ arch_prefixes = ("-", "~", "^")
- op = None
- arch = arg
- refarch = None
+ op = None
+ arch = arg
+ refarch = None
- if arg and arg[0] in arch_prefixes:
- op, arch = arg[0], arg[1:]
+ if arg and arg[0] in arch_prefixes:
+ op, arch = arg[0], arg[1:]
- if '=' in arch:
- if not op is None:
- raise ValueError('Cannot use an op and a refarch')
- arch, refarch = arch.split('=', 1)
+ if "=" in arch:
+ if not op is None:
+ raise ValueError("Cannot use an op and a refarch")
+ arch, refarch = arch.split("=", 1)
- return Op(op, arch, refarch)
+ return Op(op, arch, refarch)
def ignorable_arg(arg, quiet=0):
- """Whether it's ok to ignore this argument"""
- if os.path.isdir(arg):
- if not quiet:
- warning('ignoring directory %s' % arg)
- return True
-
- WHITELIST = (
- 'Manifest',
- 'metadata.xml',
- )
- base = os.path.basename(arg)
- if (base.startswith('ChangeLog') or
- base in WHITELIST or
- base.startswith('.') or
- base.endswith('~')):
- if not quiet:
- warning('ignoring file: %s' % arg)
- return True
-
- return False
+ """Whether it's ok to ignore this argument"""
+ if os.path.isdir(arg):
+ if not quiet:
+ warning("ignoring directory %s" % arg)
+ return True
+
+ WHITELIST = (
+ "Manifest",
+ "metadata.xml",
+ )
+ base = os.path.basename(arg)
+ if (
+ base.startswith("ChangeLog")
+ or base in WHITELIST
+ or base.startswith(".")
+ or base.endswith("~")
+ ):
+ if not quiet:
+ warning("ignoring file: %s" % arg)
+ return True
+
+ return False
def args_to_work(args, arch_status=None, _repo=None, quiet=0):
- """Process |args| into a list of work itmes (ebuild/arches to update)"""
- work = []
- todo_arches = []
- last_todo_arches = []
-
- for arg in args:
- if arg.endswith('.ebuild'):
- if not todo_arches:
- todo_arches = last_todo_arches
- work.append([arg, todo_arches])
- last_todo_arches = todo_arches
- todo_arches = []
- else:
- op = arg_to_op(arg)
- if not arch_status or op.arch in arch_status:
- todo_arches.append(op)
- elif not ignorable_arg(arg, quiet=quiet):
- raise ValueError('unknown arch/argument: %s' % arg)
-
- if todo_arches:
- raise ValueError('missing ebuilds to process!')
-
- return work
+ """Process |args| into a list of work itmes (ebuild/arches to update)"""
+ work = []
+ todo_arches = []
+ last_todo_arches = []
+
+ for arg in args:
+ if arg.endswith(".ebuild"):
+ if not todo_arches:
+ todo_arches = last_todo_arches
+ work.append([arg, todo_arches])
+ last_todo_arches = todo_arches
+ todo_arches = []
+ else:
+ op = arg_to_op(arg)
+ if not arch_status or op.arch in arch_status:
+ todo_arches.append(op)
+ elif not ignorable_arg(arg, quiet=quiet):
+ raise ValueError("unknown arch/argument: %s" % arg)
+
+ if todo_arches:
+ raise ValueError("missing ebuilds to process!")
+
+ return work
def get_parser():
- """Return an argument parser for ekeyword"""
- parser = argparse.ArgumentParser(
- description=__doc__,
- formatter_class=argparse.RawDescriptionHelpFormatter)
- parser.add_argument('-m', '--manifest', default=False, action='store_true',
- help='Run `ebuild manifest` on the ebuild after modifying it')
- parser.add_argument('-n', '--dry-run', default=False, action='store_true',
- help='Show what would be changed, but do not commit')
- parser.add_argument('-v', '--verbose', action='count', default=0,
- help='Be verbose while processing things')
- parser.add_argument('-q', '--quiet', action='count', default=0,
- help='Be quiet while processing things (only show errors)')
- parser.add_argument('--format', default='auto', dest='style',
- choices=('auto', 'color-inline', 'inline', 'short-multi', 'long-multi'),
- help='Select output format for showing differences')
- parser.add_argument('-V', '--version', action='version', version=__version__,
- help='Show version information')
- return parser
+ """Return an argument parser for ekeyword"""
+ parser = argparse.ArgumentParser(
+ description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
+ )
+ parser.add_argument(
+ "-m",
+ "--manifest",
+ default=False,
+ action="store_true",
+ help="Run `ebuild manifest` on the ebuild after modifying it",
+ )
+ parser.add_argument(
+ "-n",
+ "--dry-run",
+ default=False,
+ action="store_true",
+ help="Show what would be changed, but do not commit",
+ )
+ parser.add_argument(
+ "-v",
+ "--verbose",
+ action="count",
+ default=0,
+ help="Be verbose while processing things",
+ )
+ parser.add_argument(
+ "-q",
+ "--quiet",
+ action="count",
+ default=0,
+ help="Be quiet while processing things (only show errors)",
+ )
+ parser.add_argument(
+ "--format",
+ default="auto",
+ dest="style",
+ choices=("auto", "color-inline", "inline", "short-multi", "long-multi"),
+ help="Select output format for showing differences",
+ )
+ parser.add_argument(
+ "-V",
+ "--version",
+ action="version",
+ version=__version__,
+ help="Show version information",
+ )
+ return parser
def main(argv):
- if argv is None:
- argv = sys.argv[1:]
-
- # Extract the args ourselves. This is to allow things like -hppa
- # without tripping over the -h/--help flags. We can't use the
- # parse_known_args function either.
- # This sucks and really wish we didn't need to do this ...
- parse_args = []
- work_args = []
- while argv:
- arg = argv.pop(0)
- if arg.startswith('--'):
- if arg == '--':
- work_args += argv
- break
- else:
- parse_args.append(arg)
- # Handle flags that take arguments.
- if arg in ('--format',):
- if argv:
- parse_args.append(argv.pop(0))
- elif len(arg) == 2 and arg[0] == '-':
- parse_args.append(arg)
- else:
- work_args.append(arg)
-
- parser = get_parser()
- opts = parser.parse_args(parse_args)
- if not work_args:
- parser.error('need ebuilds to process')
-
- if opts.style == 'auto':
- if not portage_settings().get('NOCOLOR', 'false').lower() in ('no', 'false'):
- nocolor()
- opts.style = 'short'
- else:
- opts.style = 'color-inline'
-
- arch_status = load_profile_data()
- try:
- work = args_to_work(work_args, arch_status=arch_status, quiet=opts.quiet)
- except ValueError as e:
- parser.error(e)
-
- for ebuild, ops in work:
- process_ebuild(ebuild, ops, arch_status=arch_status,
- verbose=opts.verbose, quiet=opts.quiet,
- dry_run=opts.dry_run, style=opts.style,
- manifest=opts.manifest)
-
- return os.EX_OK
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
+ if argv is None:
+ argv = sys.argv[1:]
+
+ # Extract the args ourselves. This is to allow things like -hppa
+ # without tripping over the -h/--help flags. We can't use the
+ # parse_known_args function either.
+ # This sucks and really wish we didn't need to do this ...
+ parse_args = []
+ work_args = []
+ while argv:
+ arg = argv.pop(0)
+ if arg.startswith("--"):
+ if arg == "--":
+ work_args += argv
+ break
+ else:
+ parse_args.append(arg)
+ # Handle flags that take arguments.
+ if arg in ("--format",):
+ if argv:
+ parse_args.append(argv.pop(0))
+ elif len(arg) == 2 and arg[0] == "-":
+ parse_args.append(arg)
+ else:
+ work_args.append(arg)
+
+ parser = get_parser()
+ opts = parser.parse_args(parse_args)
+ if not work_args:
+ parser.error("need ebuilds to process")
+
+ if opts.style == "auto":
+ if not portage_settings().get("NOCOLOR", "false").lower() in ("no", "false"):
+ nocolor()
+ opts.style = "short"
+ else:
+ opts.style = "color-inline"
+
+ arch_status = load_profile_data()
+ try:
+ work = args_to_work(work_args, arch_status=arch_status, quiet=opts.quiet)
+ except ValueError as e:
+ parser.error(e)
+
+ for ebuild, ops in work:
+ process_ebuild(
+ ebuild,
+ ops,
+ arch_status=arch_status,
+ verbose=opts.verbose,
+ quiet=opts.quiet,
+ dry_run=opts.dry_run,
+ style=opts.style,
+ manifest=opts.manifest,
+ )
+
+ return os.EX_OK
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv[1:]))
diff --git a/pym/gentoolkit/ekeyword/test_ekeyword.py b/pym/gentoolkit/ekeyword/test_ekeyword.py
index 0763783..3495aff 100755
--- a/pym/gentoolkit/ekeyword/test_ekeyword.py
+++ b/pym/gentoolkit/ekeyword/test_ekeyword.py
@@ -15,368 +15,368 @@ from unittest import mock
from gentoolkit.ekeyword import ekeyword
-TESTDIR = os.path.join(os.path.dirname(__file__), 'tests')
+TESTDIR = os.path.join(os.path.dirname(__file__), "tests")
class TestSortKeywords(unittest.TestCase):
- """Tests for sort_keywords"""
+ """Tests for sort_keywords"""
- def _test(self, input_data, exp_data):
- """Sort |input_data| and make sure it matches |exp_data|"""
- output_data = ekeyword.sort_keywords(input_data.split())
- self.assertEqual(exp_data.split(), output_data)
+ def _test(self, input_data, exp_data):
+ """Sort |input_data| and make sure it matches |exp_data|"""
+ output_data = ekeyword.sort_keywords(input_data.split())
+ self.assertEqual(exp_data.split(), output_data)
- def testNull(self):
- """Verify whitespace is collapsed"""
- self._test('', '')
- self._test(' ', '')
+ def testNull(self):
+ """Verify whitespace is collapsed"""
+ self._test("", "")
+ self._test(" ", "")
- def testGlob(self):
- """Verify globs get sorted before all others"""
- self._test('* arm', '* arm')
- self._test('arm -* x86', '-* arm x86')
- self._test('hppa ~* amd64', '~* amd64 hppa')
+ def testGlob(self):
+ """Verify globs get sorted before all others"""
+ self._test("* arm", "* arm")
+ self._test("arm -* x86", "-* arm x86")
+ self._test("hppa ~* amd64", "~* amd64 hppa")
- def testMixedPlatform(self):
- """Verify core arches get sorted before all w/suffix"""
- self._test('arm-linux alpha amd64-fbsd hppa',
- 'alpha hppa amd64-fbsd arm-linux')
+ def testMixedPlatform(self):
+ """Verify core arches get sorted before all w/suffix"""
+ self._test("arm-linux alpha amd64-fbsd hppa", "alpha hppa amd64-fbsd arm-linux")
- def testPrefixes(self):
- """Verify -/~ and such get ignored for sorting"""
- self._test('-hppa arm ~alpha -* ~arm-linux',
- '-* ~alpha arm -hppa ~arm-linux')
+ def testPrefixes(self):
+ """Verify -/~ and such get ignored for sorting"""
+ self._test("-hppa arm ~alpha -* ~arm-linux", "-* ~alpha arm -hppa ~arm-linux")
- def testPlatform(self):
- """Verify we sort based on platform first"""
- self._test('x86-linux ppc-macos x86-fbsd amd64-linux amd64-fbsd',
- 'amd64-fbsd x86-fbsd amd64-linux x86-linux ppc-macos')
+ def testPlatform(self):
+ """Verify we sort based on platform first"""
+ self._test(
+ "x86-linux ppc-macos x86-fbsd amd64-linux amd64-fbsd",
+ "amd64-fbsd x86-fbsd amd64-linux x86-linux ppc-macos",
+ )
class TestDiffKeywords(unittest.TestCase):
- """Tests for diff_keywords"""
+ """Tests for diff_keywords"""
- def testEmpty(self):
- """Test when there is no content to diff"""
- ret = ekeyword.diff_keywords([], [])
- self.assertEqual(ret, '')
+ def testEmpty(self):
+ """Test when there is no content to diff"""
+ ret = ekeyword.diff_keywords([], [])
+ self.assertEqual(ret, "")
- def testSame(self):
- """Test when there is no difference"""
- ret = ekeyword.diff_keywords(['a b c'], ['a b c'])
- self.assertEqual(ret, 'a b c')
+ def testSame(self):
+ """Test when there is no difference"""
+ ret = ekeyword.diff_keywords(["a b c"], ["a b c"])
+ self.assertEqual(ret, "a b c")
- def testInsert(self):
- """Test when content is simply added"""
- ret = ekeyword.diff_keywords(['a'], ['~a'])
- self.assertNotEqual(ret, '')
+ def testInsert(self):
+ """Test when content is simply added"""
+ ret = ekeyword.diff_keywords(["a"], ["~a"])
+ self.assertNotEqual(ret, "")
- def testDelete(self):
- """Test when content is simply deleted"""
- ret = ekeyword.diff_keywords(['~a'], ['a'])
- self.assertNotEqual(ret, '')
+ def testDelete(self):
+ """Test when content is simply deleted"""
+ ret = ekeyword.diff_keywords(["~a"], ["a"])
+ self.assertNotEqual(ret, "")
- def testReplace(self):
- """Test when some content replaces another"""
- ret = ekeyword.diff_keywords(['~a'], ['-a'])
- self.assertNotEqual(ret, '')
+ def testReplace(self):
+ """Test when some content replaces another"""
+ ret = ekeyword.diff_keywords(["~a"], ["-a"])
+ self.assertNotEqual(ret, "")
- def _testSmokeStyle(self, style):
- return ekeyword.diff_keywords(
- ['~a', 'b', '-abcde'],
- ['a', '-b', '-abxde'], style=style)
+ def _testSmokeStyle(self, style):
+ return ekeyword.diff_keywords(
+ ["~a", "b", "-abcde"], ["a", "-b", "-abxde"], style=style
+ )
- def testSmokeStyleColor(self):
- """Run a full smoke test for color-inline style"""
- ret = self._testSmokeStyle('color-inline')
- self.assertNotEqual(ret, '')
+ def testSmokeStyleColor(self):
+ """Run a full smoke test for color-inline style"""
+ ret = self._testSmokeStyle("color-inline")
+ self.assertNotEqual(ret, "")
- def testSmokeStyleNoColor(self):
- """Run a full smoke test for non-color-inline style"""
- self._testSmokeStyle('nocolor')
+ def testSmokeStyleNoColor(self):
+ """Run a full smoke test for non-color-inline style"""
+ self._testSmokeStyle("nocolor")
class TestProcessKeywords(unittest.TestCase):
- """Tests for process_keywords"""
-
- def _test(self, keywords, ops, exp, arch_status=None):
- # This func doesn't return sorted results (which is fine),
- # so do so ourselves to get stable tests.
- ret = ekeyword.process_keywords(
- keywords.split(), ops, arch_status=arch_status)
- self.assertEqual(sorted(ret), sorted(exp.split()))
-
- def testAdd(self):
- ops = (
- ekeyword.Op(None, 'arm', None),
- ekeyword.Op('~', 's390', None),
- ekeyword.Op('-', 'sh', None),
- )
- self._test('moo', ops, 'arm ~s390 -sh moo')
-
- def testModify(self):
- ops = (
- ekeyword.Op(None, 'arm', None),
- ekeyword.Op('~', 's390', None),
- ekeyword.Op('-', 'sh', None),
- )
- self._test('~arm s390 ~sh moo', ops, 'arm ~s390 -sh moo')
-
- def testDelete(self):
- ops = (
- ekeyword.Op('^', 'arm', None),
- ekeyword.Op('^', 's390', None),
- ekeyword.Op('^', 'x86', None),
- )
- self._test('arm -s390 ~x86 bar', ops, 'bar')
-
- def testSync(self):
- ops = (
- ekeyword.Op('=', 'arm64', 'arm'),
- ekeyword.Op('=', 'ppc64', 'ppc'),
- ekeyword.Op('=', 'amd64', 'x86'),
- ekeyword.Op('=', 'm68k', 'mips'),
- ekeyword.Op('=', 'ia64', 'alpha'),
- ekeyword.Op('=', 'sh', 'sparc'),
- ekeyword.Op('=', 's390', 's390x'),
- ekeyword.Op('=', 'boo', 'moo'),
- )
- self._test(
- 'arm64 arm '
- '~ppc64 ~ppc '
- '~amd64 x86 '
- 'm68k ~mips '
- '-ia64 alpha '
- 'sh -sparc '
- 's390 '
- 'moo ',
- ops,
- 'arm64 arm ~ppc64 ~ppc amd64 x86 ~m68k ~mips ia64 alpha '
- '-sh -sparc boo moo')
-
- def testAllNoStatus(self):
- ops = (
- ekeyword.Op(None, 'all', None),
- )
- self.assertRaises(ValueError, self._test, '', ops, '')
-
- def testAllStable(self):
- ops = (
- ekeyword.Op(None, 'all', None),
- )
- arch_status = {
- 'alpha': ('stable', '~arch'),
- 'arm': ('stable', 'arch'),
- 'm68k': ('exp', '~arch'),
- 's390': ('exp', 'arch'),
- }
- self._test('* ~alpha ~arm ~m68k ~mips ~s390 ~arm-linux', ops,
- '* ~alpha arm ~m68k ~mips s390 ~arm-linux', arch_status)
-
- def testAllUnstable(self):
- ops = (
- ekeyword.Op('~', 'all', None),
- )
- arch_status = {
- 'alpha': ('stable', '~arch'),
- 'arm': ('stable', 'arch'),
- 'm68k': ('exp', '~arch'),
- 's390': ('exp', 'arch'),
- }
- self._test('-* ~* * alpha arm m68k s390 arm-linux', ops,
- '-* ~* * ~alpha ~arm ~m68k ~s390 ~arm-linux', arch_status)
-
- def testAllMultiUnstableStable(self):
- ops = (
- ekeyword.Op('~', 'all', None),
- ekeyword.Op(None, 'all', None),
- )
- arch_status = {
- 'alpha': ('stable', '~arch'),
- 'arm': ('stable', 'arch'),
- 'm68k': ('exp', '~arch'),
- 's390': ('exp', 'arch'),
- }
- self._test('-* ~* * alpha arm m68k s390', ops,
- '-* ~* * ~alpha arm ~m68k s390', arch_status)
-
- def testAllDisabled(self):
- """Make sure ~all does not change -arch to ~arch"""
- ops = (
- ekeyword.Op('~', 'all', None),
- )
- self._test('alpha -sparc ~x86', ops,
- '~alpha -sparc ~x86', {})
+ """Tests for process_keywords"""
+
+ def _test(self, keywords, ops, exp, arch_status=None):
+ # This func doesn't return sorted results (which is fine),
+ # so do so ourselves to get stable tests.
+ ret = ekeyword.process_keywords(keywords.split(), ops, arch_status=arch_status)
+ self.assertEqual(sorted(ret), sorted(exp.split()))
+
+ def testAdd(self):
+ ops = (
+ ekeyword.Op(None, "arm", None),
+ ekeyword.Op("~", "s390", None),
+ ekeyword.Op("-", "sh", None),
+ )
+ self._test("moo", ops, "arm ~s390 -sh moo")
+
+ def testModify(self):
+ ops = (
+ ekeyword.Op(None, "arm", None),
+ ekeyword.Op("~", "s390", None),
+ ekeyword.Op("-", "sh", None),
+ )
+ self._test("~arm s390 ~sh moo", ops, "arm ~s390 -sh moo")
+
+ def testDelete(self):
+ ops = (
+ ekeyword.Op("^", "arm", None),
+ ekeyword.Op("^", "s390", None),
+ ekeyword.Op("^", "x86", None),
+ )
+ self._test("arm -s390 ~x86 bar", ops, "bar")
+
+ def testSync(self):
+ ops = (
+ ekeyword.Op("=", "arm64", "arm"),
+ ekeyword.Op("=", "ppc64", "ppc"),
+ ekeyword.Op("=", "amd64", "x86"),
+ ekeyword.Op("=", "m68k", "mips"),
+ ekeyword.Op("=", "ia64", "alpha"),
+ ekeyword.Op("=", "sh", "sparc"),
+ ekeyword.Op("=", "s390", "s390x"),
+ ekeyword.Op("=", "boo", "moo"),
+ )
+ self._test(
+ "arm64 arm "
+ "~ppc64 ~ppc "
+ "~amd64 x86 "
+ "m68k ~mips "
+ "-ia64 alpha "
+ "sh -sparc "
+ "s390 "
+ "moo ",
+ ops,
+ "arm64 arm ~ppc64 ~ppc amd64 x86 ~m68k ~mips ia64 alpha "
+ "-sh -sparc boo moo",
+ )
+
+ def testAllNoStatus(self):
+ ops = (ekeyword.Op(None, "all", None),)
+ self.assertRaises(ValueError, self._test, "", ops, "")
+
+ def testAllStable(self):
+ ops = (ekeyword.Op(None, "all", None),)
+ arch_status = {
+ "alpha": ("stable", "~arch"),
+ "arm": ("stable", "arch"),
+ "m68k": ("exp", "~arch"),
+ "s390": ("exp", "arch"),
+ }
+ self._test(
+ "* ~alpha ~arm ~m68k ~mips ~s390 ~arm-linux",
+ ops,
+ "* ~alpha arm ~m68k ~mips s390 ~arm-linux",
+ arch_status,
+ )
+
+ def testAllUnstable(self):
+ ops = (ekeyword.Op("~", "all", None),)
+ arch_status = {
+ "alpha": ("stable", "~arch"),
+ "arm": ("stable", "arch"),
+ "m68k": ("exp", "~arch"),
+ "s390": ("exp", "arch"),
+ }
+ self._test(
+ "-* ~* * alpha arm m68k s390 arm-linux",
+ ops,
+ "-* ~* * ~alpha ~arm ~m68k ~s390 ~arm-linux",
+ arch_status,
+ )
+
+ def testAllMultiUnstableStable(self):
+ ops = (
+ ekeyword.Op("~", "all", None),
+ ekeyword.Op(None, "all", None),
+ )
+ arch_status = {
+ "alpha": ("stable", "~arch"),
+ "arm": ("stable", "arch"),
+ "m68k": ("exp", "~arch"),
+ "s390": ("exp", "arch"),
+ }
+ self._test(
+ "-* ~* * alpha arm m68k s390",
+ ops,
+ "-* ~* * ~alpha arm ~m68k s390",
+ arch_status,
+ )
+
+ def testAllDisabled(self):
+ """Make sure ~all does not change -arch to ~arch"""
+ ops = (ekeyword.Op("~", "all", None),)
+ self._test("alpha -sparc ~x86", ops, "~alpha -sparc ~x86", {})
class TestProcessContent(unittest.TestCase):
- """Tests for process_content"""
-
- def _testKeywords(self, line):
- ops = (
- ekeyword.Op(None, 'arm', None),
- ekeyword.Op('~', 'sparc', None),
- )
- return ekeyword.process_content(
- 'file', ['%s\n' % line], ops, quiet=True)
-
- def testKeywords(self):
- """Basic KEYWORDS mod"""
- updated, ret = self._testKeywords('KEYWORDS=""')
- self.assertTrue(updated)
- self.assertEqual(ret, ['KEYWORDS="arm ~sparc"\n'])
-
- def testKeywordsIndented(self):
- """Test KEYWORDS indented by space"""
- updated, ret = self._testKeywords(' KEYWORDS=""')
- self.assertTrue(updated)
- self.assertEqual(ret, [' KEYWORDS="arm ~sparc"\n'])
-
- def testKeywordsSingleQuote(self):
- """Test single quoted KEYWORDS"""
- updated, ret = self._testKeywords("KEYWORDS=' '")
- self.assertTrue(updated)
- self.assertEqual(ret, ['KEYWORDS="arm ~sparc"\n'])
-
- def testKeywordsComment(self):
- """Test commented out KEYWORDS"""
- updated, ret = self._testKeywords('# KEYWORDS=""')
- self.assertFalse(updated)
- self.assertEqual(ret, ['# KEYWORDS=""\n'])
-
- def testKeywordsCode(self):
- """Test code leading KEYWORDS"""
- updated, ret = self._testKeywords('[[ ${PV} ]] && KEYWORDS=""')
- self.assertTrue(updated)
- self.assertEqual(ret, ['[[ ${PV} ]] && KEYWORDS="arm ~sparc"\n'])
-
- def testKeywordsEmpty(self):
- """Test KEYWORDS not set at all"""
- updated, ret = self._testKeywords(' KEYWORDS=')
- self.assertFalse(updated)
- self.assertEqual(ret, [' KEYWORDS=\n'])
-
- def _testSmoke(self, style='color-inline', verbose=0, quiet=0):
- ops = (
- ekeyword.Op(None, 'arm', None),
- ekeyword.Op('~', 'sparc', None),
- )
- ekeyword.process_content(
- 'asdf', ['KEYWORDS="arm"'], ops, verbose=verbose,
- quiet=quiet, style=style)
-
- def testSmokeQuiet(self):
- """Smoke test for quiet mode"""
- self._testSmoke(quiet=10)
-
- def testSmokeVerbose(self):
- """Smoke test for verbose mode"""
- self._testSmoke(verbose=10)
-
- def testSmokeStyleColor(self):
- """Smoke test for color-inline style"""
- self._testSmoke('color-inline')
-
- def testSmokeStyleInline(self):
- """Smoke test for inline style"""
- self._testSmoke('inline')
-
- def testSmokeStyleShortMulti(self):
- """Smoke test for short-multi style"""
- self._testSmoke('short-multi')
-
- def testSmokeStyleLongMulti(self):
- """Smoke test for long-multi style"""
- self._testSmoke('long-multi')
+ """Tests for process_content"""
+
+ def _testKeywords(self, line):
+ ops = (
+ ekeyword.Op(None, "arm", None),
+ ekeyword.Op("~", "sparc", None),
+ )
+ return ekeyword.process_content("file", ["%s\n" % line], ops, quiet=True)
+
+ def testKeywords(self):
+ """Basic KEYWORDS mod"""
+ updated, ret = self._testKeywords('KEYWORDS=""')
+ self.assertTrue(updated)
+ self.assertEqual(ret, ['KEYWORDS="arm ~sparc"\n'])
+
+ def testKeywordsIndented(self):
+ """Test KEYWORDS indented by space"""
+ updated, ret = self._testKeywords(' KEYWORDS=""')
+ self.assertTrue(updated)
+ self.assertEqual(ret, [' KEYWORDS="arm ~sparc"\n'])
+
+ def testKeywordsSingleQuote(self):
+ """Test single quoted KEYWORDS"""
+ updated, ret = self._testKeywords("KEYWORDS=' '")
+ self.assertTrue(updated)
+ self.assertEqual(ret, ['KEYWORDS="arm ~sparc"\n'])
+
+ def testKeywordsComment(self):
+ """Test commented out KEYWORDS"""
+ updated, ret = self._testKeywords('# KEYWORDS=""')
+ self.assertFalse(updated)
+ self.assertEqual(ret, ['# KEYWORDS=""\n'])
+
+ def testKeywordsCode(self):
+ """Test code leading KEYWORDS"""
+ updated, ret = self._testKeywords('[[ ${PV} ]] && KEYWORDS=""')
+ self.assertTrue(updated)
+ self.assertEqual(ret, ['[[ ${PV} ]] && KEYWORDS="arm ~sparc"\n'])
+
+ def testKeywordsEmpty(self):
+ """Test KEYWORDS not set at all"""
+ updated, ret = self._testKeywords(" KEYWORDS=")
+ self.assertFalse(updated)
+ self.assertEqual(ret, [" KEYWORDS=\n"])
+
+ def _testSmoke(self, style="color-inline", verbose=0, quiet=0):
+ ops = (
+ ekeyword.Op(None, "arm", None),
+ ekeyword.Op("~", "sparc", None),
+ )
+ ekeyword.process_content(
+ "asdf", ['KEYWORDS="arm"'], ops, verbose=verbose, quiet=quiet, style=style
+ )
+
+ def testSmokeQuiet(self):
+ """Smoke test for quiet mode"""
+ self._testSmoke(quiet=10)
+
+ def testSmokeVerbose(self):
+ """Smoke test for verbose mode"""
+ self._testSmoke(verbose=10)
+
+ def testSmokeStyleColor(self):
+ """Smoke test for color-inline style"""
+ self._testSmoke("color-inline")
+
+ def testSmokeStyleInline(self):
+ """Smoke test for inline style"""
+ self._testSmoke("inline")
+
+ def testSmokeStyleShortMulti(self):
+ """Smoke test for short-multi style"""
+ self._testSmoke("short-multi")
+
+ def testSmokeStyleLongMulti(self):
+ """Smoke test for long-multi style"""
+ self._testSmoke("long-multi")
class TestProcessEbuild(unittest.TestCase):
- """Tests for process_ebuild
-
- This is fairly light as most code is in process_content.
- """
-
- def _process_ebuild(self, *args, **kwargs):
- """Set up a writable copy of an ebuild for process_ebuild()"""
- with tempfile.NamedTemporaryFile() as tmp:
- with open(tmp.name, 'wb') as fw:
- with open(os.path.join(TESTDIR, 'process-1.ebuild'), 'rb') as f:
- orig_content = f.read()
- fw.write(orig_content)
- ekeyword.process_ebuild(tmp.name, *args, **kwargs)
- with open(tmp.name, 'rb') as f:
- return (orig_content, f.read())
-
- def _testSmoke(self, dry_run):
- ops = (
- ekeyword.Op(None, 'arm', None),
- ekeyword.Op('~', 'sparc', None),
- )
- orig_content, new_content = self._process_ebuild(ops, dry_run=dry_run)
- if dry_run:
- self.assertEqual(orig_content, new_content)
- else:
- self.assertNotEqual(orig_content, new_content)
-
- def testSmokeNotDry(self):
- self._testSmoke(False)
-
- def testSmokeDry(self):
- self._testSmoke(True)
-
- def testManifestUpdated(self):
- """Verify `ebuild ... manifest` runs on updated files"""
- with mock.patch.object(subprocess, 'check_call') as m:
- self._process_ebuild((ekeyword.Op('~', 'arm', None),),
- manifest=True)
- m.assert_called_once_with(['ebuild', mock.ANY, 'manifest'])
-
- def testManifestNotUpdated(self):
- """Verify we don't run `ebuild ... manifest` on unmodified files"""
- with mock.patch.object(subprocess, 'check_call') as m:
- self._process_ebuild((ekeyword.Op(None, 'arm', None),),
- manifest=True)
- self.assertEqual(m.call_count, 0)
+ """Tests for process_ebuild
+
+ This is fairly light as most code is in process_content.
+ """
+
+ def _process_ebuild(self, *args, **kwargs):
+ """Set up a writable copy of an ebuild for process_ebuild()"""
+ with tempfile.NamedTemporaryFile() as tmp:
+ with open(tmp.name, "wb") as fw:
+ with open(os.path.join(TESTDIR, "process-1.ebuild"), "rb") as f:
+ orig_content = f.read()
+ fw.write(orig_content)
+ ekeyword.process_ebuild(tmp.name, *args, **kwargs)
+ with open(tmp.name, "rb") as f:
+ return (orig_content, f.read())
+
+ def _testSmoke(self, dry_run):
+ ops = (
+ ekeyword.Op(None, "arm", None),
+ ekeyword.Op("~", "sparc", None),
+ )
+ orig_content, new_content = self._process_ebuild(ops, dry_run=dry_run)
+ if dry_run:
+ self.assertEqual(orig_content, new_content)
+ else:
+ self.assertNotEqual(orig_content, new_content)
+
+ def testSmokeNotDry(self):
+ self._testSmoke(False)
+
+ def testSmokeDry(self):
+ self._testSmoke(True)
+
+ def testManifestUpdated(self):
+ """Verify `ebuild ... manifest` runs on updated files"""
+ with mock.patch.object(subprocess, "check_call") as m:
+ self._process_ebuild((ekeyword.Op("~", "arm", None),), manifest=True)
+ m.assert_called_once_with(["ebuild", mock.ANY, "manifest"])
+
+ def testManifestNotUpdated(self):
+ """Verify we don't run `ebuild ... manifest` on unmodified files"""
+ with mock.patch.object(subprocess, "check_call") as m:
+ self._process_ebuild((ekeyword.Op(None, "arm", None),), manifest=True)
+ self.assertEqual(m.call_count, 0)
class TestArgToOps(unittest.TestCase):
- """Tests for arg_to_op()"""
+ """Tests for arg_to_op()"""
- def _test(self, arg, op):
- self.assertEqual(ekeyword.arg_to_op(arg), ekeyword.Op(*op))
+ def _test(self, arg, op):
+ self.assertEqual(ekeyword.arg_to_op(arg), ekeyword.Op(*op))
- def testStable(self):
- self._test('arm', (None, 'arm', None))
+ def testStable(self):
+ self._test("arm", (None, "arm", None))
- def testUnstable(self):
- self._test('~ppc64', ('~', 'ppc64', None))
+ def testUnstable(self):
+ self._test("~ppc64", ("~", "ppc64", None))
- def testDisabled(self):
- self._test('-sparc', ('-', 'sparc', None))
+ def testDisabled(self):
+ self._test("-sparc", ("-", "sparc", None))
- def testDeleted(self):
- self._test('^x86-fbsd', ('^', 'x86-fbsd', None))
+ def testDeleted(self):
+ self._test("^x86-fbsd", ("^", "x86-fbsd", None))
- def testSync(self):
- self._test('s390=x86', (None, 's390', 'x86'))
+ def testSync(self):
+ self._test("s390=x86", (None, "s390", "x86"))
class TestMain(unittest.TestCase):
- """Tests for the main entry point"""
+ """Tests for the main entry point"""
- def testSmoke(self):
- ekeyword.main(['arm', '--dry-run', os.path.join(TESTDIR, 'process-1.ebuild')])
+ def testSmoke(self):
+ ekeyword.main(["arm", "--dry-run", os.path.join(TESTDIR, "process-1.ebuild")])
- def testVersion(self):
- with self.assertRaises(SystemExit) as e:
- ekeyword.main(['--version', '--dry-run'])
- self.assertEqual(e.exception.code, os.EX_OK)
+ def testVersion(self):
+ with self.assertRaises(SystemExit) as e:
+ ekeyword.main(["--version", "--dry-run"])
+ self.assertEqual(e.exception.code, os.EX_OK)
- def testEmptyString(self):
- with self.assertRaises(SystemExit) as e:
- ekeyword.main(['', os.path.join(TESTDIR, 'process-1.ebuild')])
- self.assertNotEqual(e.exception.code, os.EX_OK)
+ def testEmptyString(self):
+ with self.assertRaises(SystemExit) as e:
+ ekeyword.main(["", os.path.join(TESTDIR, "process-1.ebuild")])
+ self.assertNotEqual(e.exception.code, os.EX_OK)
-if __name__ == '__main__':
- unittest.main()
+if __name__ == "__main__":
+ unittest.main()
diff --git a/pym/gentoolkit/enalyze/__init__.py b/pym/gentoolkit/enalyze/__init__.py
index 6a40215..f884dcf 100644
--- a/pym/gentoolkit/enalyze/__init__.py
+++ b/pym/gentoolkit/enalyze/__init__.py
@@ -11,23 +11,19 @@
# Move to Imports section after Python 2.6 is stable
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
# version is dynamically set by distutils sdist
__version__ = "git"
__productname__ = "enalyze"
-__authors__ = (
- 'Brian Dolbec, <brian.dolbec@gmail.com>'
-
-)
+__authors__ = "Brian Dolbec, <brian.dolbec@gmail.com>"
# make an exportable copy of the info for help output
MODULE_INFO = {
- "__docformat__": __docformat__,
- "__doc__": __doc__,
- "__version__": __version__,
- "__productname__": __productname__,
- "__authors__": __authors__
-
+ "__docformat__": __docformat__,
+ "__doc__": __doc__,
+ "__version__": __version__,
+ "__productname__": __productname__,
+ "__authors__": __authors__,
}
import errno
@@ -39,86 +35,85 @@ import portage
import gentoolkit as gen
from gentoolkit import errors
from gentoolkit import pprinter as pp
-from gentoolkit.base import (initialize_configuration, split_arguments,
- parse_global_options, print_help)
+from gentoolkit.base import (
+ initialize_configuration,
+ split_arguments,
+ parse_global_options,
+ print_help,
+)
-NAME_MAP = {
- 'a': 'analyze',
- 'r': 'rebuild'
-}
+NAME_MAP = {"a": "analyze", "r": "rebuild"}
FORMATTED_OPTIONS = (
- (" (a)nalyze",
- "analyzes the installed PKG database USE flag or keyword useage"),
- (" (r)ebuild",
- "analyzes the Installed PKG database and generates files suitable"),
- (" ",
- "to replace corrupted or missing /etc/portage/package.* files")
- )
+ (" (a)nalyze", "analyzes the installed PKG database USE flag or keyword useage"),
+ (
+ " (r)ebuild",
+ "analyzes the Installed PKG database and generates files suitable",
+ ),
+ (" ", "to replace corrupted or missing /etc/portage/package.* files"),
+)
+
def expand_module_name(module_name):
- """Returns one of the values of NAME_MAP or raises KeyError"""
+ """Returns one of the values of NAME_MAP or raises KeyError"""
- if module_name == 'list':
- # list is a Python builtin type, so we must rename our module
- return 'list_'
- elif module_name in NAME_MAP.values():
- return module_name
- else:
- return NAME_MAP[module_name]
+ if module_name == "list":
+ # list is a Python builtin type, so we must rename our module
+ return "list_"
+ elif module_name in NAME_MAP.values():
+ return module_name
+ else:
+ return NAME_MAP[module_name]
def main():
- """Parse input and run the program."""
-
- short_opts = "hqCNV"
- long_opts = (
- 'help', 'quiet', 'nocolor', 'no-color', 'no-pipe', 'version', 'debug'
- )
-
- initialize_configuration()
-
- try:
- global_opts, args = getopt(sys.argv[1:], short_opts, long_opts)
- except GetoptError as err:
- sys.stderr.write(" \n")
- sys.stderr.write(pp.error("Global %s\n" % err))
- print_help(MODULE_INFO, FORMATTED_OPTIONS, with_description=False)
- sys.exit(2)
-
- # Parse global options
- need_help = parse_global_options(global_opts, args, MODULE_INFO, FORMATTED_OPTIONS)
-
- if gen.CONFIG['quiet']:
- gen.CONFIG['verbose'] = False
-
- try:
- module_name, module_args = split_arguments(args)
- except IndexError:
- print_help(MODULE_INFO, FORMATTED_OPTIONS)
- sys.exit(2)
-
- if need_help:
- module_args.append('--help')
-
- try:
- expanded_module_name = expand_module_name(module_name)
- except KeyError:
- sys.stderr.write(pp.error("Unknown module '%s'" % module_name))
- print_help(MODULE_INFO, FORMATTED_OPTIONS, with_description=False)
- sys.exit(2)
-
- try:
- loaded_module = __import__(
- expanded_module_name, globals(), locals(), [], 1
- )
- loaded_module.main(module_args)
- except portage.exception.AmbiguousPackageName as err:
- raise errors.GentoolkitAmbiguousPackage(err.args[0])
- except IOError as err:
- if err.errno != errno.EPIPE:
- raise
-
-if __name__ == '__main__':
- main()
+ """Parse input and run the program."""
+
+ short_opts = "hqCNV"
+ long_opts = ("help", "quiet", "nocolor", "no-color", "no-pipe", "version", "debug")
+
+ initialize_configuration()
+
+ try:
+ global_opts, args = getopt(sys.argv[1:], short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(" \n")
+ sys.stderr.write(pp.error("Global %s\n" % err))
+ print_help(MODULE_INFO, FORMATTED_OPTIONS, with_description=False)
+ sys.exit(2)
+
+ # Parse global options
+ need_help = parse_global_options(global_opts, args, MODULE_INFO, FORMATTED_OPTIONS)
+
+ if gen.CONFIG["quiet"]:
+ gen.CONFIG["verbose"] = False
+
+ try:
+ module_name, module_args = split_arguments(args)
+ except IndexError:
+ print_help(MODULE_INFO, FORMATTED_OPTIONS)
+ sys.exit(2)
+
+ if need_help:
+ module_args.append("--help")
+
+ try:
+ expanded_module_name = expand_module_name(module_name)
+ except KeyError:
+ sys.stderr.write(pp.error("Unknown module '%s'" % module_name))
+ print_help(MODULE_INFO, FORMATTED_OPTIONS, with_description=False)
+ sys.exit(2)
+
+ try:
+ loaded_module = __import__(expanded_module_name, globals(), locals(), [], 1)
+ loaded_module.main(module_args)
+ except portage.exception.AmbiguousPackageName as err:
+ raise errors.GentoolkitAmbiguousPackage(err.args[0])
+ except IOError as err:
+ if err.errno != errno.EPIPE:
+ raise
+
+
+if __name__ == "__main__":
+ main()
diff --git a/pym/gentoolkit/enalyze/analyze.py b/pym/gentoolkit/enalyze/analyze.py
index 30ffa93..3a09145 100644
--- a/pym/gentoolkit/enalyze/analyze.py
+++ b/pym/gentoolkit/enalyze/analyze.py
@@ -21,456 +21,502 @@ import portage
def gather_flags_info(
- cpvs=None,
- system_flags=None,
- include_unset=False,
- target="USE",
- use_portage=False,
- # override-able for testing
- _get_flags=get_flags,
- _get_used=get_installed_use
- ):
- """Analyze the installed pkgs USE flags for frequency of use
-
- @type cpvs: list
- @param cpvs: optional list of [cat/pkg-ver,...] to analyze or
- defaults to entire installed pkg db
- @type: system_flags: list
- @param system_flags: the current default USE flags as defined
- by portage.settings["USE"].split()
- @type include_unset: bool
- @param include_unset: controls the inclusion of unset USE flags in the report.
- @type target: string
- @param target: the environment variable being analyzed
- one of ["USE", "PKGUSE"]
- @type _get_flags: function
- @param _get_flags: ovride-able for testing,
- defaults to gentoolkit.enalyze.lib.get_flags
- @param _get_used: ovride-able for testing,
- defaults to gentoolkit.enalyze.lib.get_installed_use
- @rtype dict. {flag:{"+":[cat/pkg-ver,...], "-":[cat/pkg-ver,...], "unset":[]}
- """
- if cpvs is None:
- cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
- # pass them in to override for tests
- flags = FlagAnalyzer(system_flags,
- filter_defaults=False,
- target=target,
- _get_flags=_get_flags,
- _get_used=get_installed_use
- )
- flag_users = {}
- for cpv in cpvs:
- if cpv.startswith("virtual"):
- continue
- if use_portage:
- plus, minus, unset = flags.analyse_cpv(cpv)
- else:
- pkg = Package(cpv)
- plus, minus, unset = flags.analyse_pkg(pkg)
- for flag in plus:
- if flag in flag_users:
- flag_users[flag]["+"].append(cpv)
- else:
- flag_users[flag] = {"+": [cpv], "-": []}
- for flag in minus:
- if flag in flag_users:
- flag_users[flag]["-"].append(cpv)
- else:
- flag_users[flag] = {"+":[], "-": [cpv]}
- if include_unset:
- for flag in unset:
- if flag in flag_users:
- if "unset" in flag_users[flag]:
- flag_users[flag]["unset"].append(cpv)
- else:
- flag_users[flag]["unset"] = [cpv]
- else:
- flag_users[flag] = {"+": [], "-": [], "unset": [cpv]}
- return flag_users
+ cpvs=None,
+ system_flags=None,
+ include_unset=False,
+ target="USE",
+ use_portage=False,
+ # override-able for testing
+ _get_flags=get_flags,
+ _get_used=get_installed_use,
+):
+ """Analyze the installed pkgs USE flags for frequency of use
+
+ @type cpvs: list
+ @param cpvs: optional list of [cat/pkg-ver,...] to analyze or
+ defaults to entire installed pkg db
+ @type: system_flags: list
+ @param system_flags: the current default USE flags as defined
+ by portage.settings["USE"].split()
+ @type include_unset: bool
+ @param include_unset: controls the inclusion of unset USE flags in the report.
+ @type target: string
+ @param target: the environment variable being analyzed
+ one of ["USE", "PKGUSE"]
+ @type _get_flags: function
+ @param _get_flags: ovride-able for testing,
+ defaults to gentoolkit.enalyze.lib.get_flags
+ @param _get_used: ovride-able for testing,
+ defaults to gentoolkit.enalyze.lib.get_installed_use
+ @rtype dict. {flag:{"+":[cat/pkg-ver,...], "-":[cat/pkg-ver,...], "unset":[]}
+ """
+ if cpvs is None:
+ cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
+ # pass them in to override for tests
+ flags = FlagAnalyzer(
+ system_flags,
+ filter_defaults=False,
+ target=target,
+ _get_flags=_get_flags,
+ _get_used=get_installed_use,
+ )
+ flag_users = {}
+ for cpv in cpvs:
+ if cpv.startswith("virtual"):
+ continue
+ if use_portage:
+ plus, minus, unset = flags.analyse_cpv(cpv)
+ else:
+ pkg = Package(cpv)
+ plus, minus, unset = flags.analyse_pkg(pkg)
+ for flag in plus:
+ if flag in flag_users:
+ flag_users[flag]["+"].append(cpv)
+ else:
+ flag_users[flag] = {"+": [cpv], "-": []}
+ for flag in minus:
+ if flag in flag_users:
+ flag_users[flag]["-"].append(cpv)
+ else:
+ flag_users[flag] = {"+": [], "-": [cpv]}
+ if include_unset:
+ for flag in unset:
+ if flag in flag_users:
+ if "unset" in flag_users[flag]:
+ flag_users[flag]["unset"].append(cpv)
+ else:
+ flag_users[flag]["unset"] = [cpv]
+ else:
+ flag_users[flag] = {"+": [], "-": [], "unset": [cpv]}
+ return flag_users
def gather_keywords_info(
- cpvs=None,
- system_keywords=None,
- use_portage=False,
- # override-able for testing
- keywords=portage.settings["ACCEPT_KEYWORDS"],
- analyser = None
- ):
- """Analyze the installed pkgs 'keywords' for frequency of use
-
- @param cpvs: optional list of [cat/pkg-ver,...] to analyze or
- defaults to entire installed pkg db
- @param system_keywords: list of the system keywords
- @param keywords: user defined list of keywords to check and report on
- or reports on all relevant keywords found to have been used.
- @param _get_kwds: overridable function for testing
- @param _get_used: overridable function for testing
- @rtype dict. {keyword:{"stable":[cat/pkg-ver,...], "testing":[cat/pkg-ver,...]}
- """
- if cpvs is None:
- cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
- keyword_users = {}
- for cpv in cpvs:
- if cpv.startswith("virtual"):
- continue
- if use_portage:
- keyword = analyser.get_inst_keyword_cpv(cpv)
- else:
- pkg = Package(cpv)
- keyword = analyser.get_inst_keyword_pkg(pkg)
- #print "returned keyword =", cpv, keyword, keyword[0]
- key = keyword[0]
- if key in ["~", "-"]:
- _kwd = keyword[1:]
- if _kwd in keyword_users:
- if key in ["~"]:
- keyword_users[_kwd]["testing"].append(cpv)
- elif key in ["-"]:
- #print "adding cpv to missing:", cpv
- keyword_users[_kwd]["missing"].append(cpv)
- else:
- if key in ["~"]:
- keyword_users[_kwd] = {"stable": [],
- "testing": [cpv], "missing": []}
- elif key in ["-"]:
- keyword_users[_kwd] = {"stable": [],
- "testing": [], "missing": [cpv]}
- else:
- keyword_users[_kwd] = {"stable": [cpv],
- "testing": [], "missing": []}
- elif keyword in keyword_users:
- keyword_users[keyword]["stable"].append(cpv)
- else:
- keyword_users[keyword] = {
- "stable": [cpv],
- "testing": [],
- "missing": []
- }
- return keyword_users
+ cpvs=None,
+ system_keywords=None,
+ use_portage=False,
+ # override-able for testing
+ keywords=portage.settings["ACCEPT_KEYWORDS"],
+ analyser=None,
+):
+ """Analyze the installed pkgs 'keywords' for frequency of use
+
+ @param cpvs: optional list of [cat/pkg-ver,...] to analyze or
+ defaults to entire installed pkg db
+ @param system_keywords: list of the system keywords
+ @param keywords: user defined list of keywords to check and report on
+ or reports on all relevant keywords found to have been used.
+ @param _get_kwds: overridable function for testing
+ @param _get_used: overridable function for testing
+ @rtype dict. {keyword:{"stable":[cat/pkg-ver,...], "testing":[cat/pkg-ver,...]}
+ """
+ if cpvs is None:
+ cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
+ keyword_users = {}
+ for cpv in cpvs:
+ if cpv.startswith("virtual"):
+ continue
+ if use_portage:
+ keyword = analyser.get_inst_keyword_cpv(cpv)
+ else:
+ pkg = Package(cpv)
+ keyword = analyser.get_inst_keyword_pkg(pkg)
+ # print "returned keyword =", cpv, keyword, keyword[0]
+ key = keyword[0]
+ if key in ["~", "-"]:
+ _kwd = keyword[1:]
+ if _kwd in keyword_users:
+ if key in ["~"]:
+ keyword_users[_kwd]["testing"].append(cpv)
+ elif key in ["-"]:
+ # print "adding cpv to missing:", cpv
+ keyword_users[_kwd]["missing"].append(cpv)
+ else:
+ if key in ["~"]:
+ keyword_users[_kwd] = {
+ "stable": [],
+ "testing": [cpv],
+ "missing": [],
+ }
+ elif key in ["-"]:
+ keyword_users[_kwd] = {
+ "stable": [],
+ "testing": [],
+ "missing": [cpv],
+ }
+ else:
+ keyword_users[_kwd] = {
+ "stable": [cpv],
+ "testing": [],
+ "missing": [],
+ }
+ elif keyword in keyword_users:
+ keyword_users[keyword]["stable"].append(cpv)
+ else:
+ keyword_users[keyword] = {"stable": [cpv], "testing": [], "missing": []}
+ return keyword_users
class Analyse(ModuleBase):
- """Installed db analysis tool to query the installed databse
- and produce/output stats for USE flags or keywords/mask.
- The 'rebuild' action output is in the form suitable for file type output
- to create a new package.use, package.keywords, package.unmask
- type files in the event of needing to rebuild the
- /etc/portage/* user configs
- """
- def __init__(self):
- ModuleBase.__init__(self)
- self.command_name = "enalyze"
- self.module_name = "analyze"
- self.options = {
- "flags": False,
- "keywords": False,
- "packages": False,
- "unset": False,
- "verbose": False,
- "quiet": False,
- 'prefix': False,
- 'portage': True,
- "width": 80,
- "prepend": "",
- }
- self.module_opts = {
- "-f": ("flags", "boolean", True),
- "--flags": ("flags", "boolean", True),
- "-k": ("keywords", "boolean", True),
- "--keywords": ("keywords", "boolean", True),
- "-u": ("unset", "boolean", True),
- "--unset": ("unset", "boolean", True),
- "-v": ("verbose", "boolean", True),
- "--verbose": ("verbose", "boolean", True),
- "-p": ("prefix", "boolean", True),
- "--prefix": ("prefix", "boolean", True),
- "-P": ("prepend", "char", None),
- "--prepend": ("prepend", "char", None),
- "-G": ("portage", "boolean", False),
- "--portage": ("portage", "boolean", False),
- "-W": ("width", "int", 80),
- "--width": ("width", "int", 80),
- }
- self.formatted_options = [
- (" -h, --help", "Outputs this useage message"),
- (" -u, --unset",
- "Additionally include any unset USE flags and the packages"),
- ("", "that could use them"),
- (" -v, --verbose",
- "Used in the analyze action to output more detailed information"),
- (" -p, --prefix",
- "Used for testing purposes only, runs report using " +
- "a prefix keyword and 'prefix' USE flag"),
- (" -P, --prepend",
- "Prepend the string to any list output. " +
- "ie: prepend '* ' to the ""front of each package being listed."
- "This is useful for generating preformatted wiki text."),
- #(" -G, --portage",
- #"Use portage directly instead of gentoolkit's Package " +
- #"object for some operations. Usually a little faster."),
- (" -W, --width",
- "Format the output to wrap at 'WIDTH' ie: long line output"),
- ]
- self.formatted_args = [
- (" use",
- "Causes the action to analyze the installed packages USE flags"),
- (" pkguse",
- "Causes the action to analyze the installed packages PKGUSE flags"),
- (" ",
- "These are flags that have been set in /etc/portage/package.use"),
- (" keywords",
- "Causes the action to analyze the installed packages keywords"),
- (" packages",
- "Causes the action to analyze the installed packages and the"),
- (" ",
- "USE flags they were installed with"),
- (" unmask",
- "Causes the action to analyze the installed packages"),
- (" ",
- "for those that need to be unmasked")
- ]
- self.short_opts = "huvpGP:W:"
- self.long_opts = ("help", "unset", "verbose", "prefix", "prepend=",
- "width=") #, "portage")
- self.need_queries = True
- self.arg_spec = "Target"
- self.arg_options = ['use', 'pkguse','keywords', 'packages', 'unmask']
- self.arg_option = False
- self.warning = (
- " CAUTION",
- "This is beta software and some features/options are incomplete,",
- "some features may change in future releases includig its name.",
- "Feedback will be appreciated, http://bugs.gentoo.org")
-
-
- def run(self, input_args, quiet=False):
- """runs the module
-
- @param input_args: input arguments to be parsed
- """
- query = self.main_setup(input_args)
- query = self.validate_query(query)
- self.set_quiet(quiet)
- if query in ["use", "pkguse"]:
- self.analyse_flags(query)
- elif query in ["keywords"]:
- self.analyse_keywords()
- elif query in ["packages"]:
- self.analyse_packages()
- elif query in ["unmask"]:
- self.analyse_unmask()
-
- def analyse_flags(self, target):
- """This will scan the installed packages db and analyze the
- USE flags used for installation and produce a report on how
- they were used.
-
- @type target: string
- @param target: the target to be analyzed, one of ["use", "pkguse"]
- """
- system_use = portage.settings["USE"].split()
-
- self.printer = AnalysisPrinter(
- "use",
- self.options["verbose"],
- system_use,
- width=self.options["width"],
- prepend=self.options["prepend"])
- if self.options["verbose"]:
- cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
- #cpvs = get_installed_cpvs()
- #print "Total number of installed ebuilds =", len(cpvs)
- flag_users = gather_flags_info(cpvs, system_use,
- self.options["unset"], target=target.upper(),
- use_portage=self.options['portage'])
- else:
- cpvs = get_installed_cpvs()
- flag_users = gather_flags_info(cpvs, system_flags=system_use,
- include_unset=self.options["unset"], target=target.upper(),
- use_portage=self.options['portage'])
- #print flag_users
- flag_keys = sorted(flag_users)
- if self.options["verbose"]:
- print(" Flag System #pkgs cat/pkg-ver")
- #blankline = nl
- elif not self.options['quiet']:
- print(" Flag System #pkgs")
- #blankline = lambda: None
- for flag in flag_keys:
- flag_pos = flag_users[flag]["+"]
- if len(flag_pos):
- self.printer(flag, "+", flag_pos)
- #blankline()
- flag_neg = flag_users[flag]["-"]
- if len(flag_neg):
- self.printer(flag, "-", flag_neg)
- #blankline()
- if "unset" in flag_users[flag] and flag_users[flag]["unset"]:
- flag_unset = flag_users[flag]["unset"]
- self.printer(flag, "unset", flag_unset)
- #blankline()
- if not self.options['quiet']:
- print("===================================================")
- print("Total number of flags in report =",
- pp.output.red(str(len(flag_keys))))
- if self.options["verbose"]:
- print("Total number of installed ebuilds =",
- pp.output.red(str(len([x for x in cpvs]))))
- print()
-
-
- def analyse_keywords(self, keywords=None):
- """This will scan the installed packages db and analyze the
- keywords used for installation and produce a report on them.
- """
- print()
- system_keywords = portage.settings["ACCEPT_KEYWORDS"]
- arch = portage.settings["ARCH"]
- if self.options["prefix"]:
- # build a new keyword for testing
- system_keywords = "~" + arch + "-linux"
- if self.options["verbose"] or self.options["prefix"]:
- print("Current system ARCH =", arch)
- print("Current system ACCEPT_KEYWORDS =", system_keywords)
- system_keywords = system_keywords.split()
- self.printer = AnalysisPrinter(
- "keywords",
- self.options["verbose"],
- system_keywords,
- width=self.options["width"],
- prepend=self.options["prepend"])
- self.analyser = KeywordAnalyser( arch, system_keywords, portage.db[portage.root]["vartree"].dbapi)
- #self.analyser.set_order(portage.settings["USE"].split())
- # only for testing
- test_use = portage.settings["USE"].split()
- if self.options['prefix'] and 'prefix' not in test_use:
- print("ANALYSE_KEYWORDS() 'prefix' flag not found in system",
- "USE flags!!! appending for testing")
- print()
- test_use.append('prefix')
- self.analyser.set_order(test_use)
- # /end testing
-
- if self.options["verbose"]:
- cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
- #print "Total number of installed ebuilds =", len(cpvs)
- keyword_users = gather_keywords_info(
- cpvs=cpvs,
- system_keywords=system_keywords,
- use_portage=self.options['portage'],
- keywords=keywords, analyser = self.analyser
- )
- blankline = nl
- else:
- keyword_users = gather_keywords_info(
- system_keywords=system_keywords,
- use_portage=self.options['portage'],
- keywords=keywords,
- analyser = self.analyser
- )
- blankline = lambda: None
- #print keyword_users
- keyword_keys = sorted(keyword_users)
- if self.options["verbose"]:
- print(" Keyword System #pkgs cat/pkg-ver")
- elif not self.options['quiet']:
- print(" Keyword System #pkgs")
- for keyword in keyword_keys:
- kwd_stable = keyword_users[keyword]["stable"]
- if len(kwd_stable):
- self.printer(keyword, " ", kwd_stable)
- blankline()
- kwd_testing = keyword_users[keyword]["testing"]
- if len(kwd_testing):
- self.printer(keyword, "~", kwd_testing)
- blankline()
- kwd_missing = keyword_users[keyword]["missing"]
- if len(kwd_missing):
- self.printer(keyword, "-", kwd_missing)
- blankline
- if not self.options['quiet']:
- if self.analyser.mismatched:
- print("_________________________________________________")
- print(("The following packages were found to have a \n" +
- "different recorded ARCH than the current system ARCH"))
- for cpv in self.analyser.mismatched:
- print("\t", pp.cpv(cpv))
- print("===================================================")
- print("Total number of keywords in report =",
- pp.output.red(str(len(keyword_keys))))
- if self.options["verbose"]:
- print("Total number of installed ebuilds =",
- pp.output.red(str(len(cpvs))))
- print()
-
-
- def analyse_packages(self):
- """This will scan the installed packages db and analyze the
- USE flags used for installation and produce a report.
-
- @type target: string
- @param target: the target to be analyzed, one of ["use", "pkguse"]
- """
- system_use = portage.settings["USE"].split()
- if self.options["verbose"]:
- cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
- key_width = 45
- else:
- cpvs = get_installed_cpvs()
- key_width = 1
-
- self.printer = AnalysisPrinter(
- "packages",
- self.options["verbose"],
- key_width=key_width,
- width=self.options["width"],
- prepend=self.options["prepend"])
-
- cpvs = sorted(cpvs)
- flags = FlagAnalyzer(
- system=system_use,
- filter_defaults=False,
- target="USE"
- )
-
- if self.options["verbose"]:
- print(" cat/pkg-ver USE Flags")
- # "app-emulation/emul-linux-x86-sdl-20100915 ...."
- #blankline = nl
- elif not self.options['quiet']:
- print(" cat/pkg-ver USE Flags")
- #blankline = lambda: None
- for cpv in cpvs:
- (flag_plus, flag_neg, unset) = flags.analyse_cpv(cpv)
- if self.options["unset"]:
- self.printer(cpv, "", (sorted(flag_plus), sorted(flag_neg),
- sorted(unset)))
- else:
- self.printer(cpv, "", (sorted(flag_plus), sorted(flag_neg), []))
- if not self.options['quiet']:
- print("===================================================")
- print("Total number of installed ebuilds =",
- pp.output.red(str(len([x for x in cpvs]))))
- print()
-
-
- def analyse_unmask(self):
- """This will scan the installed packages db and analyze the
- unmasking used for installation and produce a report on them.
- """
- self.not_implemented("unmask")
-
+ """Installed db analysis tool to query the installed databse
+ and produce/output stats for USE flags or keywords/mask.
+ The 'rebuild' action output is in the form suitable for file type output
+ to create a new package.use, package.keywords, package.unmask
+ type files in the event of needing to rebuild the
+ /etc/portage/* user configs
+ """
+
+ def __init__(self):
+ ModuleBase.__init__(self)
+ self.command_name = "enalyze"
+ self.module_name = "analyze"
+ self.options = {
+ "flags": False,
+ "keywords": False,
+ "packages": False,
+ "unset": False,
+ "verbose": False,
+ "quiet": False,
+ "prefix": False,
+ "portage": True,
+ "width": 80,
+ "prepend": "",
+ }
+ self.module_opts = {
+ "-f": ("flags", "boolean", True),
+ "--flags": ("flags", "boolean", True),
+ "-k": ("keywords", "boolean", True),
+ "--keywords": ("keywords", "boolean", True),
+ "-u": ("unset", "boolean", True),
+ "--unset": ("unset", "boolean", True),
+ "-v": ("verbose", "boolean", True),
+ "--verbose": ("verbose", "boolean", True),
+ "-p": ("prefix", "boolean", True),
+ "--prefix": ("prefix", "boolean", True),
+ "-P": ("prepend", "char", None),
+ "--prepend": ("prepend", "char", None),
+ "-G": ("portage", "boolean", False),
+ "--portage": ("portage", "boolean", False),
+ "-W": ("width", "int", 80),
+ "--width": ("width", "int", 80),
+ }
+ self.formatted_options = [
+ (" -h, --help", "Outputs this useage message"),
+ (
+ " -u, --unset",
+ "Additionally include any unset USE flags and the packages",
+ ),
+ ("", "that could use them"),
+ (
+ " -v, --verbose",
+ "Used in the analyze action to output more detailed information",
+ ),
+ (
+ " -p, --prefix",
+ "Used for testing purposes only, runs report using "
+ + "a prefix keyword and 'prefix' USE flag",
+ ),
+ (
+ " -P, --prepend",
+ "Prepend the string to any list output. " + "ie: prepend '* ' to the "
+ "front of each package being listed."
+ "This is useful for generating preformatted wiki text.",
+ ),
+ # (" -G, --portage",
+ # "Use portage directly instead of gentoolkit's Package " +
+ # "object for some operations. Usually a little faster."),
+ (
+ " -W, --width",
+ "Format the output to wrap at 'WIDTH' ie: long line output",
+ ),
+ ]
+ self.formatted_args = [
+ (" use", "Causes the action to analyze the installed packages USE flags"),
+ (
+ " pkguse",
+ "Causes the action to analyze the installed packages PKGUSE flags",
+ ),
+ (" ", "These are flags that have been set in /etc/portage/package.use"),
+ (
+ " keywords",
+ "Causes the action to analyze the installed packages keywords",
+ ),
+ (
+ " packages",
+ "Causes the action to analyze the installed packages and the",
+ ),
+ (" ", "USE flags they were installed with"),
+ (" unmask", "Causes the action to analyze the installed packages"),
+ (" ", "for those that need to be unmasked"),
+ ]
+ self.short_opts = "huvpGP:W:"
+ self.long_opts = (
+ "help",
+ "unset",
+ "verbose",
+ "prefix",
+ "prepend=",
+ "width=",
+ ) # , "portage")
+ self.need_queries = True
+ self.arg_spec = "Target"
+ self.arg_options = ["use", "pkguse", "keywords", "packages", "unmask"]
+ self.arg_option = False
+ self.warning = (
+ " CAUTION",
+ "This is beta software and some features/options are incomplete,",
+ "some features may change in future releases includig its name.",
+ "Feedback will be appreciated, http://bugs.gentoo.org",
+ )
+
+ def run(self, input_args, quiet=False):
+ """runs the module
+
+ @param input_args: input arguments to be parsed
+ """
+ query = self.main_setup(input_args)
+ query = self.validate_query(query)
+ self.set_quiet(quiet)
+ if query in ["use", "pkguse"]:
+ self.analyse_flags(query)
+ elif query in ["keywords"]:
+ self.analyse_keywords()
+ elif query in ["packages"]:
+ self.analyse_packages()
+ elif query in ["unmask"]:
+ self.analyse_unmask()
+
+ def analyse_flags(self, target):
+ """This will scan the installed packages db and analyze the
+ USE flags used for installation and produce a report on how
+ they were used.
+
+ @type target: string
+ @param target: the target to be analyzed, one of ["use", "pkguse"]
+ """
+ system_use = portage.settings["USE"].split()
+
+ self.printer = AnalysisPrinter(
+ "use",
+ self.options["verbose"],
+ system_use,
+ width=self.options["width"],
+ prepend=self.options["prepend"],
+ )
+ if self.options["verbose"]:
+ cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
+ # cpvs = get_installed_cpvs()
+ # print "Total number of installed ebuilds =", len(cpvs)
+ flag_users = gather_flags_info(
+ cpvs,
+ system_use,
+ self.options["unset"],
+ target=target.upper(),
+ use_portage=self.options["portage"],
+ )
+ else:
+ cpvs = get_installed_cpvs()
+ flag_users = gather_flags_info(
+ cpvs,
+ system_flags=system_use,
+ include_unset=self.options["unset"],
+ target=target.upper(),
+ use_portage=self.options["portage"],
+ )
+ # print flag_users
+ flag_keys = sorted(flag_users)
+ if self.options["verbose"]:
+ print(" Flag System #pkgs cat/pkg-ver")
+ # blankline = nl
+ elif not self.options["quiet"]:
+ print(" Flag System #pkgs")
+ # blankline = lambda: None
+ for flag in flag_keys:
+ flag_pos = flag_users[flag]["+"]
+ if len(flag_pos):
+ self.printer(flag, "+", flag_pos)
+ # blankline()
+ flag_neg = flag_users[flag]["-"]
+ if len(flag_neg):
+ self.printer(flag, "-", flag_neg)
+ # blankline()
+ if "unset" in flag_users[flag] and flag_users[flag]["unset"]:
+ flag_unset = flag_users[flag]["unset"]
+ self.printer(flag, "unset", flag_unset)
+ # blankline()
+ if not self.options["quiet"]:
+ print("===================================================")
+ print(
+ "Total number of flags in report =", pp.output.red(str(len(flag_keys)))
+ )
+ if self.options["verbose"]:
+ print(
+ "Total number of installed ebuilds =",
+ pp.output.red(str(len([x for x in cpvs]))),
+ )
+ print()
+
+ def analyse_keywords(self, keywords=None):
+ """This will scan the installed packages db and analyze the
+ keywords used for installation and produce a report on them.
+ """
+ print()
+ system_keywords = portage.settings["ACCEPT_KEYWORDS"]
+ arch = portage.settings["ARCH"]
+ if self.options["prefix"]:
+ # build a new keyword for testing
+ system_keywords = "~" + arch + "-linux"
+ if self.options["verbose"] or self.options["prefix"]:
+ print("Current system ARCH =", arch)
+ print("Current system ACCEPT_KEYWORDS =", system_keywords)
+ system_keywords = system_keywords.split()
+ self.printer = AnalysisPrinter(
+ "keywords",
+ self.options["verbose"],
+ system_keywords,
+ width=self.options["width"],
+ prepend=self.options["prepend"],
+ )
+ self.analyser = KeywordAnalyser(
+ arch, system_keywords, portage.db[portage.root]["vartree"].dbapi
+ )
+ # self.analyser.set_order(portage.settings["USE"].split())
+ # only for testing
+ test_use = portage.settings["USE"].split()
+ if self.options["prefix"] and "prefix" not in test_use:
+ print(
+ "ANALYSE_KEYWORDS() 'prefix' flag not found in system",
+ "USE flags!!! appending for testing",
+ )
+ print()
+ test_use.append("prefix")
+ self.analyser.set_order(test_use)
+ # /end testing
+
+ if self.options["verbose"]:
+ cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
+ # print "Total number of installed ebuilds =", len(cpvs)
+ keyword_users = gather_keywords_info(
+ cpvs=cpvs,
+ system_keywords=system_keywords,
+ use_portage=self.options["portage"],
+ keywords=keywords,
+ analyser=self.analyser,
+ )
+ blankline = nl
+ else:
+ keyword_users = gather_keywords_info(
+ system_keywords=system_keywords,
+ use_portage=self.options["portage"],
+ keywords=keywords,
+ analyser=self.analyser,
+ )
+ blankline = lambda: None
+ # print keyword_users
+ keyword_keys = sorted(keyword_users)
+ if self.options["verbose"]:
+ print(" Keyword System #pkgs cat/pkg-ver")
+ elif not self.options["quiet"]:
+ print(" Keyword System #pkgs")
+ for keyword in keyword_keys:
+ kwd_stable = keyword_users[keyword]["stable"]
+ if len(kwd_stable):
+ self.printer(keyword, " ", kwd_stable)
+ blankline()
+ kwd_testing = keyword_users[keyword]["testing"]
+ if len(kwd_testing):
+ self.printer(keyword, "~", kwd_testing)
+ blankline()
+ kwd_missing = keyword_users[keyword]["missing"]
+ if len(kwd_missing):
+ self.printer(keyword, "-", kwd_missing)
+ blankline
+ if not self.options["quiet"]:
+ if self.analyser.mismatched:
+ print("_________________________________________________")
+ print(
+ (
+ "The following packages were found to have a \n"
+ + "different recorded ARCH than the current system ARCH"
+ )
+ )
+ for cpv in self.analyser.mismatched:
+ print("\t", pp.cpv(cpv))
+ print("===================================================")
+ print(
+ "Total number of keywords in report =",
+ pp.output.red(str(len(keyword_keys))),
+ )
+ if self.options["verbose"]:
+ print(
+ "Total number of installed ebuilds =", pp.output.red(str(len(cpvs)))
+ )
+ print()
+
+ def analyse_packages(self):
+ """This will scan the installed packages db and analyze the
+ USE flags used for installation and produce a report.
+
+ @type target: string
+ @param target: the target to be analyzed, one of ["use", "pkguse"]
+ """
+ system_use = portage.settings["USE"].split()
+ if self.options["verbose"]:
+ cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
+ key_width = 45
+ else:
+ cpvs = get_installed_cpvs()
+ key_width = 1
+
+ self.printer = AnalysisPrinter(
+ "packages",
+ self.options["verbose"],
+ key_width=key_width,
+ width=self.options["width"],
+ prepend=self.options["prepend"],
+ )
+
+ cpvs = sorted(cpvs)
+ flags = FlagAnalyzer(system=system_use, filter_defaults=False, target="USE")
+
+ if self.options["verbose"]:
+ print(" cat/pkg-ver USE Flags")
+ # "app-emulation/emul-linux-x86-sdl-20100915 ...."
+ # blankline = nl
+ elif not self.options["quiet"]:
+ print(" cat/pkg-ver USE Flags")
+ # blankline = lambda: None
+ for cpv in cpvs:
+ (flag_plus, flag_neg, unset) = flags.analyse_cpv(cpv)
+ if self.options["unset"]:
+ self.printer(
+ cpv, "", (sorted(flag_plus), sorted(flag_neg), sorted(unset))
+ )
+ else:
+ self.printer(cpv, "", (sorted(flag_plus), sorted(flag_neg), []))
+ if not self.options["quiet"]:
+ print("===================================================")
+ print(
+ "Total number of installed ebuilds =",
+ pp.output.red(str(len([x for x in cpvs]))),
+ )
+ print()
+
+ def analyse_unmask(self):
+ """This will scan the installed packages db and analyze the
+ unmasking used for installation and produce a report on them.
+ """
+ self.not_implemented("unmask")
def main(input_args):
- """Common starting method by the analyze master
- unless all modules are converted to this class method.
+ """Common starting method by the analyze master
+ unless all modules are converted to this class method.
+
+ @param input_args: input args as supplied by equery master module.
+ """
+ query_module = Analyse()
+ query_module.run(input_args, gentoolkit.CONFIG["quiet"])
- @param input_args: input args as supplied by equery master module.
- """
- query_module = Analyse()
- query_module.run(input_args, gentoolkit.CONFIG['quiet'])
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/enalyze/lib.py b/pym/gentoolkit/enalyze/lib.py
index 50c7d11..6d7cb4e 100644
--- a/pym/gentoolkit/enalyze/lib.py
+++ b/pym/gentoolkit/enalyze/lib.py
@@ -10,349 +10,358 @@
from gentoolkit import errors
from gentoolkit.keyword import reduce_keywords
-from gentoolkit.flag import (reduce_flags, get_flags, get_all_cpv_use,
- filter_flags, get_installed_use, defaulted_flags)
-#from gentoolkit.package import Package
+from gentoolkit.flag import (
+ reduce_flags,
+ get_flags,
+ get_all_cpv_use,
+ filter_flags,
+ get_installed_use,
+ defaulted_flags,
+)
+
+# from gentoolkit.package import Package
import portage
class FlagAnalyzer:
- """Specialty functions for analysing an installed package's
- USE flags. Can be used for single or mulitple use without
- needing to be reset unless the system USE flags are changed.
-
- @type system: list or set
- @param system: the default system USE flags.
- @type _get_flags: function
- @param _get_flags: Normally defaulted, can be overriden for testing
- @type _get_used: function
- @param _get_used: Normally defaulted, can be overriden for testing
- """
- def __init__(self,
- system,
- filter_defaults=False,
- target="USE",
- _get_flags=get_flags,
- _get_used=get_installed_use
- ):
- self.get_flags = _get_flags
- self.get_used = _get_used
- self.filter_defaults = filter_defaults
- self.target = target
- self.reset(system)
-
- def reset(self, system):
- """Resets the internal system USE flags and use_expand variables
- to the new setting. The use_expand variable is handled internally.
-
- @type system: list or set
- @param system: the default system USE flags.
- """
- self.system = set(system)
- self.use_expand = portage.settings['USE_EXPAND'].lower().split()
-
- def analyse_cpv(self, cpv):
- """Gets all relavent USE flag info for a cpv and breaks them down
- into 3 sets, plus (package.use enabled), minus ( package.use disabled),
- unset.
-
- @param cpv: string. 'cat/pkg-ver'
- @rtype tuple of sets
- @return (plus, minus, unset) sets of USE flags
- """
- installed = set(self.get_used(cpv, self.target))
- _iuse = self.get_flags(cpv)
- iuse = set(reduce_flags(_iuse))
- iuse_defaults = defaulted_flags(_iuse)
- return self._analyse(installed, iuse, iuse_defaults)
-
- def _analyse(self, installed, iuse, iuse_defaults):
- """Analyzes the supplied info and returns the flag settings
- that differ from the defaults
-
- @type installed: set
- @param installed: the installed with use flags
- @type iuse: set
- @param iuse: the current ebuilds IUSE
- """
- defaults = self.system.intersection(iuse)
- # update defaults with iuse_defaults
- defaults.update(iuse_defaults['+'])
- defaults = defaults.difference(iuse_defaults['-'])
- usedflags = iuse.intersection(set(installed))
- if self.filter_defaults:
- plus = usedflags.difference(defaults)
- else:
- plus = usedflags
- minus = defaults.difference(usedflags)
- unset = iuse.difference(defaults, plus, minus)
- cleaned_unset = self.remove_expanding(unset)
- return (plus, minus, cleaned_unset)
-
- def analyse_pkg(self, pkg):
- """Gets all relevent USE flag info for a pkg and breaks them down
- into 3 sets, plus (package.use enabled), minus ( package.use disabled),
- unset.
-
- @param pkg: gentoolkit.package.Package object
- @rtype tuple of sets
- @return (plus, minus, unset) sets of USE flags
- """
- installed = set(self.pkg_used(pkg))
- #print("installed =", installed)
- _iuse = self.pkg_flags(pkg)
- iuse = set(reduce_flags(_iuse))
- iuse_defaults = defaulted_flags(_iuse)
- #print("iuse =", iuse)
- return self._analyse(installed, iuse, iuse_defaults)
-
- def pkg_used(self, pkg):
- if self.target == "USE":
- return pkg.use().split()
- return pkg.environment(self.target).split()
-
- def pkg_flags(self, pkg):
- final_use, use_expand_hidden, usemasked, useforced = \
- get_all_cpv_use(pkg.cpv)
- flags = pkg.environment("IUSE", prefer_vdb=False).split()
- return filter_flags(flags, use_expand_hidden, usemasked, useforced)
-
- def redundant(self, cpv, iuse):
- """Checks for redundant settings.
- future function. Not yet implemented.
- """
- pass
-
- def remove_expanding(self, flags):
- """Remove unwanted USE_EXPAND flags
- from unset IUSE sets
-
- @param flags: short list or set of USE flags
- @rtype set
- @return USE flags
- """
- _flags = set(flags)
- for expander in self.use_expand:
- for flag in flags:
- if expander in flag:
- _flags.remove(flag)
- if not _flags:
- break
- return _flags
+ """Specialty functions for analysing an installed package's
+ USE flags. Can be used for single or mulitple use without
+ needing to be reset unless the system USE flags are changed.
+
+ @type system: list or set
+ @param system: the default system USE flags.
+ @type _get_flags: function
+ @param _get_flags: Normally defaulted, can be overriden for testing
+ @type _get_used: function
+ @param _get_used: Normally defaulted, can be overriden for testing
+ """
+
+ def __init__(
+ self,
+ system,
+ filter_defaults=False,
+ target="USE",
+ _get_flags=get_flags,
+ _get_used=get_installed_use,
+ ):
+ self.get_flags = _get_flags
+ self.get_used = _get_used
+ self.filter_defaults = filter_defaults
+ self.target = target
+ self.reset(system)
+
+ def reset(self, system):
+ """Resets the internal system USE flags and use_expand variables
+ to the new setting. The use_expand variable is handled internally.
+
+ @type system: list or set
+ @param system: the default system USE flags.
+ """
+ self.system = set(system)
+ self.use_expand = portage.settings["USE_EXPAND"].lower().split()
+
+ def analyse_cpv(self, cpv):
+ """Gets all relavent USE flag info for a cpv and breaks them down
+ into 3 sets, plus (package.use enabled), minus ( package.use disabled),
+ unset.
+
+ @param cpv: string. 'cat/pkg-ver'
+ @rtype tuple of sets
+ @return (plus, minus, unset) sets of USE flags
+ """
+ installed = set(self.get_used(cpv, self.target))
+ _iuse = self.get_flags(cpv)
+ iuse = set(reduce_flags(_iuse))
+ iuse_defaults = defaulted_flags(_iuse)
+ return self._analyse(installed, iuse, iuse_defaults)
+
+ def _analyse(self, installed, iuse, iuse_defaults):
+ """Analyzes the supplied info and returns the flag settings
+ that differ from the defaults
+
+ @type installed: set
+ @param installed: the installed with use flags
+ @type iuse: set
+ @param iuse: the current ebuilds IUSE
+ """
+ defaults = self.system.intersection(iuse)
+ # update defaults with iuse_defaults
+ defaults.update(iuse_defaults["+"])
+ defaults = defaults.difference(iuse_defaults["-"])
+ usedflags = iuse.intersection(set(installed))
+ if self.filter_defaults:
+ plus = usedflags.difference(defaults)
+ else:
+ plus = usedflags
+ minus = defaults.difference(usedflags)
+ unset = iuse.difference(defaults, plus, minus)
+ cleaned_unset = self.remove_expanding(unset)
+ return (plus, minus, cleaned_unset)
+
+ def analyse_pkg(self, pkg):
+ """Gets all relevent USE flag info for a pkg and breaks them down
+ into 3 sets, plus (package.use enabled), minus ( package.use disabled),
+ unset.
+
+ @param pkg: gentoolkit.package.Package object
+ @rtype tuple of sets
+ @return (plus, minus, unset) sets of USE flags
+ """
+ installed = set(self.pkg_used(pkg))
+ # print("installed =", installed)
+ _iuse = self.pkg_flags(pkg)
+ iuse = set(reduce_flags(_iuse))
+ iuse_defaults = defaulted_flags(_iuse)
+ # print("iuse =", iuse)
+ return self._analyse(installed, iuse, iuse_defaults)
+
+ def pkg_used(self, pkg):
+ if self.target == "USE":
+ return pkg.use().split()
+ return pkg.environment(self.target).split()
+
+ def pkg_flags(self, pkg):
+ final_use, use_expand_hidden, usemasked, useforced = get_all_cpv_use(pkg.cpv)
+ flags = pkg.environment("IUSE", prefer_vdb=False).split()
+ return filter_flags(flags, use_expand_hidden, usemasked, useforced)
+
+ def redundant(self, cpv, iuse):
+ """Checks for redundant settings.
+ future function. Not yet implemented.
+ """
+ pass
+
+ def remove_expanding(self, flags):
+ """Remove unwanted USE_EXPAND flags
+ from unset IUSE sets
+
+ @param flags: short list or set of USE flags
+ @rtype set
+ @return USE flags
+ """
+ _flags = set(flags)
+ for expander in self.use_expand:
+ for flag in flags:
+ if expander in flag:
+ _flags.remove(flag)
+ if not _flags:
+ break
+ return _flags
class KeywordAnalyser:
- """Specialty functions for analysing the installed package db for
- keyword useage and the packages that used them.
-
- Note: should be initialized with the internal set_order() before use.
- See internal set_order() for more details.
- This class of functions can be used for single cpv checks or
- used repeatedly for an entire package db.
-
- @type arch: string
- @param arch: the system ARCH setting
- @type accept_keywords: list
- @param accept_keywords: eg. ['x86', '~x86']
- @type get_aux: function, defaults to: portage.db[portage.root]["vartree"].dbapi.aux_get
- @param vardb: vardb class of functions, needed=aux_get()
- to return => KEYWORDS & USE flags for a cpv
- = aux_get(cpv, ["KEYWORDS", "USE"])
- """
-
- # parsing order to determine appropriate keyword used for installation
- normal_order = ['stable', 'testing', 'prefix', 'testing_prefix', 'missing']
- prefix_order = ['prefix', 'testing_prefix', 'stable', 'testing', 'missing']
- parse_range = list(range(len(normal_order)))
-
-
- def __init__(self, arch, accept_keywords, vardb=portage.db[portage.root]["vartree"].dbapi):
- self.arch = arch
- self.accept_keywords = accept_keywords
- self.vardb = vardb
- self.prefix = ''
- self.parse_order = None
- self.check_key = {
- 'stable': self._stable,
- 'testing': self._testing,
- 'prefix': self._prefix,
- 'testing_prefix': self._testing_prefix,
- 'missing': self._missing
- }
- self.mismatched = []
-
- def determine_keyword(self, keywords, used, cpv):
- """Determine the keyword from the installed USE flags and
- the KEYWORDS that was used to install a package.
-
- @param keywords: list of keywords available to install a pkg
- @param used: list of USE flalgs recorded for the installed pkg
- @rtype: string
- @return a keyword or null string
- """
- used = set(used)
- kwd = None
- result = ''
- if keywords:
- absolute_kwds = reduce_keywords(keywords)
- kwd = list(used.intersection(absolute_kwds))
- #if keywords == ['~ppc64']:
- #print "Checked keywords for kwd", keywords, used, "kwd =", kwd
- if not kwd:
- #print "Checking for kwd against portage.archlist"
- absolute_kwds = reduce_keywords(keywords)
- # check for one against archlist then re-check
- kwd = list(absolute_kwds.intersection(portage.archlist))
- #print "determined keyword =", kwd
- if len(kwd) == 1:
- key = kwd[0]
- #print "determined keyword =", key
- elif not kwd:
- #print "kwd != 1", kwd, cpv
- result = self._missing(self.keyword, keywords)
- else: # too many, try to narrow them dowm
- #print "too many kwd's, trying to match against arch"
- _kwd = list(set(kwd).intersection(self.arch))
- key = ''
- if _kwd:
- #print "found one! :)", _kwd
- key = _kwd
- else: # try re-running the short list against archlist
- #print "Checking kwd for _kwd against portage.archlist"
- _kwd = list(set(kwd).intersection(portage.archlist))
- if _kwd and len(_kwd) == 1:
- #print "found one! :)", _kwd
- key = _kwd[0]
- else:
- #print " :( didn't work, _kwd =", _kwd, "giving up on:", cpv
- result = self._missing(self.keyword, keywords)
- i = 0
- while not result and i in self.parse_range:
- parsekey = self.parse_order[i]
- result = self.check_key[parsekey](key, keywords)
- i += 1
- return result
-
- def _stable(self, key, keywords):
- """test for a normal stable keyword"""
- if key in keywords:
- return key
- return ''
-
- def _testing(self, key, keywords):
- """test for a normal testing keyword"""
- if ("~" + key) in keywords:
- return "~" + key
- return ''
-
- def _prefix(self, key, keywords):
- """test for a stable prefix keyword"""
- if not self.prefix:
- return ''
- _key = '-'.join([key, self.prefix])
- if _key in keywords:
- #print key, "is in", keywords
- return _key
- return ''
-
- def _testing_prefix(self, key, keywords):
- """test for a testing prefix keyword"""
- if not self.prefix:
- return ''
- _key = "~" +'-'.join([key, self.prefix])
- if _key in keywords:
- #print key, "is in", keywords
- return _key
- return ''
-
- def _missing(self, key, keywords):
- """generates a missing keyword to return"""
- if self.prefix and key != self.keyword:
- _key = '-'.join([key, self.prefix])
- else:
- _key = '-' + key
- #print "_missisng :( _key =", _key
- return _key
-
- def get_inst_keyword_cpv(self, cpv):
- """Determines the installed with keyword for cpv
-
- @type cpv: string
- @param cpv: an installed CAT/PKG-VER
- @rtype: string
- @returns a keyword determined to have been used to install cpv
- """
- keywords, used = self.vardb.aux_get(cpv, ["KEYWORDS", "USE"])
- keywords = keywords.split()
- used = used.split()
- return self._parse(keywords, used, cpv=cpv)
-
- def get_inst_keyword_pkg(self, pkg):
- """Determines the installed with keyword for cpv
-
- @param pkg: gentoolkit.package.Package object
- @rtype: string
- @returns a keyword determined to have been used to install cpv
- """
- keywords, used = pkg.environment(["KEYWORDS", "USE"],
- prefer_vdb=True, fallback=False)
- keywords = keywords.split()
- used = used.split()
- return self._parse(keywords, used, pkg=pkg)
-
- def _parse(self, keywords, used, pkg=None, cpv=None):
- if pkg:
- _cpv = pkg.cpv
- else:
- _cpv = cpv
- if not self.parse_order:
- self.set_order(used)
- keyword = self.keyword
- # sanity check
- if self.arch not in used:
- #print "Found a mismatch = ", cpv, self.arch, used
- self.mismatched.append(_cpv)
- if keyword in keywords:
- #print "keyword", keyword, "is in", keywords
- return keyword
- elif "~"+keyword in keywords:
- #print "~keyword", keyword, "is in", keywords
- return "~"+keyword
- else:
- keyword = self.determine_keyword(keywords, used, _cpv)
- if not keyword:
- raise errors.GentoolkitUnknownKeyword(_cpv, ' '.join(keywords), used)
- return keyword
-
- def set_order(self, used):
- """Used to set the parsing order to determine a keyword
- used for installation.
-
- This is needed due to the way prefix arch's and keywords
- work with portage. It looks for the 'prefix' flag. A positive result
- sets it to the prefix order and keyword.
-
- @type used: list
- @param used: a list of pkg USE flags or the system USE flags"""
- if 'prefix' in used:
- #print "SET_ORDER() Setting parse order to prefix"
- prefix = None
- self.parse_order = self.prefix_order
- for key in self.accept_keywords:
- #print "SET_ORDER() '"+key+"'"
- if '-' in key:
- #print "SET_ORDER()found prefix keyword :", key
- if self.arch in key:
- prefix = key.split('-')[1]
- #print "prefix =", prefix
- self.prefix = prefix
- self.keyword = '-'.join([self.arch, prefix])
- else:
- #print "SET_ORDER() Setting parse order to normal"
- self.parse_order = self.normal_order
- self.keyword = self.arch
- #print "SET_ORDER() completed: prefix =", self.prefix, ", keyword =", \
- # self.keyword, "parse order =",self.parse_order
- #print
-
+ """Specialty functions for analysing the installed package db for
+ keyword useage and the packages that used them.
+
+ Note: should be initialized with the internal set_order() before use.
+ See internal set_order() for more details.
+ This class of functions can be used for single cpv checks or
+ used repeatedly for an entire package db.
+
+ @type arch: string
+ @param arch: the system ARCH setting
+ @type accept_keywords: list
+ @param accept_keywords: eg. ['x86', '~x86']
+ @type get_aux: function, defaults to: portage.db[portage.root]["vartree"].dbapi.aux_get
+ @param vardb: vardb class of functions, needed=aux_get()
+ to return => KEYWORDS & USE flags for a cpv
+ = aux_get(cpv, ["KEYWORDS", "USE"])
+ """
+
+ # parsing order to determine appropriate keyword used for installation
+ normal_order = ["stable", "testing", "prefix", "testing_prefix", "missing"]
+ prefix_order = ["prefix", "testing_prefix", "stable", "testing", "missing"]
+ parse_range = list(range(len(normal_order)))
+
+ def __init__(
+ self, arch, accept_keywords, vardb=portage.db[portage.root]["vartree"].dbapi
+ ):
+ self.arch = arch
+ self.accept_keywords = accept_keywords
+ self.vardb = vardb
+ self.prefix = ""
+ self.parse_order = None
+ self.check_key = {
+ "stable": self._stable,
+ "testing": self._testing,
+ "prefix": self._prefix,
+ "testing_prefix": self._testing_prefix,
+ "missing": self._missing,
+ }
+ self.mismatched = []
+
+ def determine_keyword(self, keywords, used, cpv):
+ """Determine the keyword from the installed USE flags and
+ the KEYWORDS that was used to install a package.
+
+ @param keywords: list of keywords available to install a pkg
+ @param used: list of USE flalgs recorded for the installed pkg
+ @rtype: string
+ @return a keyword or null string
+ """
+ used = set(used)
+ kwd = None
+ result = ""
+ if keywords:
+ absolute_kwds = reduce_keywords(keywords)
+ kwd = list(used.intersection(absolute_kwds))
+ # if keywords == ['~ppc64']:
+ # print "Checked keywords for kwd", keywords, used, "kwd =", kwd
+ if not kwd:
+ # print "Checking for kwd against portage.archlist"
+ absolute_kwds = reduce_keywords(keywords)
+ # check for one against archlist then re-check
+ kwd = list(absolute_kwds.intersection(portage.archlist))
+ # print "determined keyword =", kwd
+ if len(kwd) == 1:
+ key = kwd[0]
+ # print "determined keyword =", key
+ elif not kwd:
+ # print "kwd != 1", kwd, cpv
+ result = self._missing(self.keyword, keywords)
+ else: # too many, try to narrow them dowm
+ # print "too many kwd's, trying to match against arch"
+ _kwd = list(set(kwd).intersection(self.arch))
+ key = ""
+ if _kwd:
+ # print "found one! :)", _kwd
+ key = _kwd
+ else: # try re-running the short list against archlist
+ # print "Checking kwd for _kwd against portage.archlist"
+ _kwd = list(set(kwd).intersection(portage.archlist))
+ if _kwd and len(_kwd) == 1:
+ # print "found one! :)", _kwd
+ key = _kwd[0]
+ else:
+ # print " :( didn't work, _kwd =", _kwd, "giving up on:", cpv
+ result = self._missing(self.keyword, keywords)
+ i = 0
+ while not result and i in self.parse_range:
+ parsekey = self.parse_order[i]
+ result = self.check_key[parsekey](key, keywords)
+ i += 1
+ return result
+
+ def _stable(self, key, keywords):
+ """test for a normal stable keyword"""
+ if key in keywords:
+ return key
+ return ""
+
+ def _testing(self, key, keywords):
+ """test for a normal testing keyword"""
+ if ("~" + key) in keywords:
+ return "~" + key
+ return ""
+
+ def _prefix(self, key, keywords):
+ """test for a stable prefix keyword"""
+ if not self.prefix:
+ return ""
+ _key = "-".join([key, self.prefix])
+ if _key in keywords:
+ # print key, "is in", keywords
+ return _key
+ return ""
+
+ def _testing_prefix(self, key, keywords):
+ """test for a testing prefix keyword"""
+ if not self.prefix:
+ return ""
+ _key = "~" + "-".join([key, self.prefix])
+ if _key in keywords:
+ # print key, "is in", keywords
+ return _key
+ return ""
+
+ def _missing(self, key, keywords):
+ """generates a missing keyword to return"""
+ if self.prefix and key != self.keyword:
+ _key = "-".join([key, self.prefix])
+ else:
+ _key = "-" + key
+ # print "_missisng :( _key =", _key
+ return _key
+
+ def get_inst_keyword_cpv(self, cpv):
+ """Determines the installed with keyword for cpv
+
+ @type cpv: string
+ @param cpv: an installed CAT/PKG-VER
+ @rtype: string
+ @returns a keyword determined to have been used to install cpv
+ """
+ keywords, used = self.vardb.aux_get(cpv, ["KEYWORDS", "USE"])
+ keywords = keywords.split()
+ used = used.split()
+ return self._parse(keywords, used, cpv=cpv)
+
+ def get_inst_keyword_pkg(self, pkg):
+ """Determines the installed with keyword for cpv
+
+ @param pkg: gentoolkit.package.Package object
+ @rtype: string
+ @returns a keyword determined to have been used to install cpv
+ """
+ keywords, used = pkg.environment(
+ ["KEYWORDS", "USE"], prefer_vdb=True, fallback=False
+ )
+ keywords = keywords.split()
+ used = used.split()
+ return self._parse(keywords, used, pkg=pkg)
+
+ def _parse(self, keywords, used, pkg=None, cpv=None):
+ if pkg:
+ _cpv = pkg.cpv
+ else:
+ _cpv = cpv
+ if not self.parse_order:
+ self.set_order(used)
+ keyword = self.keyword
+ # sanity check
+ if self.arch not in used:
+ # print "Found a mismatch = ", cpv, self.arch, used
+ self.mismatched.append(_cpv)
+ if keyword in keywords:
+ # print "keyword", keyword, "is in", keywords
+ return keyword
+ elif "~" + keyword in keywords:
+ # print "~keyword", keyword, "is in", keywords
+ return "~" + keyword
+ else:
+ keyword = self.determine_keyword(keywords, used, _cpv)
+ if not keyword:
+ raise errors.GentoolkitUnknownKeyword(_cpv, " ".join(keywords), used)
+ return keyword
+
+ def set_order(self, used):
+ """Used to set the parsing order to determine a keyword
+ used for installation.
+
+ This is needed due to the way prefix arch's and keywords
+ work with portage. It looks for the 'prefix' flag. A positive result
+ sets it to the prefix order and keyword.
+
+ @type used: list
+ @param used: a list of pkg USE flags or the system USE flags"""
+ if "prefix" in used:
+ # print "SET_ORDER() Setting parse order to prefix"
+ prefix = None
+ self.parse_order = self.prefix_order
+ for key in self.accept_keywords:
+ # print "SET_ORDER() '"+key+"'"
+ if "-" in key:
+ # print "SET_ORDER()found prefix keyword :", key
+ if self.arch in key:
+ prefix = key.split("-")[1]
+ # print "prefix =", prefix
+ self.prefix = prefix
+ self.keyword = "-".join([self.arch, prefix])
+ else:
+ # print "SET_ORDER() Setting parse order to normal"
+ self.parse_order = self.normal_order
+ self.keyword = self.arch
+ # print "SET_ORDER() completed: prefix =", self.prefix, ", keyword =", \
+ # self.keyword, "parse order =",self.parse_order
+ # print
diff --git a/pym/gentoolkit/enalyze/output.py b/pym/gentoolkit/enalyze/output.py
index 993565a..1778304 100644
--- a/pym/gentoolkit/enalyze/output.py
+++ b/pym/gentoolkit/enalyze/output.py
@@ -14,275 +14,282 @@ from gentoolkit import pprinter as pp
from gentoolkit.formatters import CpvValueWrapper
from gentoolkit.cpv import split_cpv
+
def nl(lines=1):
- """small utility function to print blank lines
+ """small utility function to print blank lines
+
+ @type lines: integer
+ @param lines: optional number of blank lines to print
+ default = 1
+ """
+ print(("\n" * lines))
- @type lines: integer
- @param lines: optional number of blank lines to print
- default = 1
- """
- print(('\n' * lines))
class AnalysisPrinter(CpvValueWrapper):
- """Printing functions"""
- def __init__(self, target, verbose=True, references=None, key_width=1,
- width=None, prepend=''):
- """@param references: list of accepted keywords or
- the system use flags
- """
- self.references = references
- self.key_width = key_width
- self.width = width
- self.prepend = prepend
- CpvValueWrapper.__init__(self, cpv_width=key_width, width=width)
- self.set_target(target, verbose)
-
- def set_target(self, target, verbose=True):
- if target in ["use"]:
- if verbose:
- self.print_fn = self.print_use_verbose
- else:
- self.print_fn = self.print_use_quiet
- self._format_key = self._format_use_keyword
- elif target in ["keywords"]:
- if verbose:
- self.print_fn = self.print_keyword_verbose
- else:
- self.print_fn = self.print_keyword_quiet
- self._format_key = self._format_use_keyword
- elif target in ["packages"]:
- if verbose:
- self.print_fn = self.print_pkg_verbose
- else:
- self.print_fn = self.print_pkg_quiet
- self._format_key = self._format_pkg
-
- def __call__(self, key, active, data):
- self._format_key(key, active, data)
-
- def _format_use_keyword(self, key, active, pkgs):
- """Determines the stats for key, formats it and
- calls the pre-determined print function
- """
- occurred = str(len(pkgs))
- if active in ["-", "~"]:
- _key = active + key
- else:
- _key = key
- if _key in self.references:
- default = "default"
- else:
- default = "......."
- count = ' '*(5-len(occurred)) + occurred
- pkgs.sort()
- self.print_fn(key, active, default, count, pkgs)
-
- def print_use_verbose(self, key, active, default, count, pkgs):
- """Verbosely prints a set of use flag info. including the pkgs
- using them.
- """
- _pkgs = pkgs[:]
- if active in ["+", "-"]:
- _key = pp.useflag((active+key), active=="+")
- else:
- _key = (" " + key)
- cpv = _pkgs.pop(0)
- print(self.prepend + _key,'.'*(35-len(key)), default, pp.number(count),
- pp.cpv(cpv))
- while _pkgs:
- cpv = _pkgs.pop(0)
- print(' '*52 + pp.cpv(cpv))
-
- def print_use_quiet(self, key, active, default, count, pkgs):
- """Quietly prints a subset set of USE flag info..
- """
- if active in ["+", "-"]:
- _key = pp.useflag((active+key), active=="+")
- else:
- _key = (" " + key)
- print(self.prepend + _key,'.'*(35-len(key)), default, pp.number(count))
-
- def print_keyword_verbose(self, key, stability, default, count, pkgs):
- """Verbosely prints a set of keywords info. including the pkgs
- using them.
- """
- _pkgs = pkgs[:]
- _key = (pp.keyword((stability+key),stable=(stability==" "),
- hard_masked=stability=="-"))
- cpv = _pkgs.pop(0)
- print(self.prepend + _key,'.'*(20-len(key)), default, pp.number(count),
- pp.cpv(cpv))
- while _pkgs:
- cpv = _pkgs.pop(0)
- print(' '*37 + pp.cpv(cpv))
-
- def print_keyword_quiet(self, key, stability, default, count, pkgs):
- """Quietly prints a subset set of USE flag info..
- """
- _key = (pp.keyword((stability+key), stable=(stability==" "),
- hard_masked=stability=="-"))
- print(self.prepend + _key,'.'*(20-len(key)), default, pp.number(count))
-
- def _format_pkg(self, key, active, flags):
- """Determines the stats for key, formats it and
- calls the pre-determined print function
- """
- (plus, minus, cleaned) = flags
- _plus = []
- _minus = []
- _cleaned = []
- for flag in plus:
- _flag = flag.strip()
- if _flag:
- _plus.append(_flag)
- for flag in minus:
- _flag = flag.strip()
- if _flag:
- _minus.append(_flag)
- for flag in cleaned:
- _flag = flag.strip()
- if _flag:
- _cleaned.append(_flag)
- #print("cpv=", key, "_plus=", _plus, "_minus=", _minus)
- self.print_fn(self.prepend + key, (plus, minus, cleaned))
-
- def print_pkg_verbose(self, cpv, flags):
- """Verbosely prints the pkg's use flag info.
- """
- (plus, minus, unset) = flags
- _flags = []
- for flag in plus:
- _flags.append(pp.useflag((flag), True))
- for flag in minus:
- _flags.append(pp.useflag(('-' + flag), False))
- for flag in unset:
- _flags.append(pp.globaloption('-' + flag))
-
- print(self._format_values(cpv, ", ".join(_flags)))
-
-
- def print_pkg_quiet(self, cpv, flags):
- """Verbosely prints the pkg's use flag info.
- """
- (plus, minus, unset) = flags
- _flags = []
- for flag in plus:
- _flags.append(pp.useflag((flag), True))
- for flag in minus:
- _flags.append(pp.useflag(('-'+flag), False))
- for flag in unset:
- _flags.append(pp.globaloption('-' + flag))
-
- print(self._format_values(cpv, ", ".join(_flags)))
+ """Printing functions"""
+
+ def __init__(
+ self, target, verbose=True, references=None, key_width=1, width=None, prepend=""
+ ):
+ """@param references: list of accepted keywords or
+ the system use flags
+ """
+ self.references = references
+ self.key_width = key_width
+ self.width = width
+ self.prepend = prepend
+ CpvValueWrapper.__init__(self, cpv_width=key_width, width=width)
+ self.set_target(target, verbose)
+
+ def set_target(self, target, verbose=True):
+ if target in ["use"]:
+ if verbose:
+ self.print_fn = self.print_use_verbose
+ else:
+ self.print_fn = self.print_use_quiet
+ self._format_key = self._format_use_keyword
+ elif target in ["keywords"]:
+ if verbose:
+ self.print_fn = self.print_keyword_verbose
+ else:
+ self.print_fn = self.print_keyword_quiet
+ self._format_key = self._format_use_keyword
+ elif target in ["packages"]:
+ if verbose:
+ self.print_fn = self.print_pkg_verbose
+ else:
+ self.print_fn = self.print_pkg_quiet
+ self._format_key = self._format_pkg
+
+ def __call__(self, key, active, data):
+ self._format_key(key, active, data)
+
+ def _format_use_keyword(self, key, active, pkgs):
+ """Determines the stats for key, formats it and
+ calls the pre-determined print function
+ """
+ occurred = str(len(pkgs))
+ if active in ["-", "~"]:
+ _key = active + key
+ else:
+ _key = key
+ if _key in self.references:
+ default = "default"
+ else:
+ default = "......."
+ count = " " * (5 - len(occurred)) + occurred
+ pkgs.sort()
+ self.print_fn(key, active, default, count, pkgs)
+
+ def print_use_verbose(self, key, active, default, count, pkgs):
+ """Verbosely prints a set of use flag info. including the pkgs
+ using them.
+ """
+ _pkgs = pkgs[:]
+ if active in ["+", "-"]:
+ _key = pp.useflag((active + key), active == "+")
+ else:
+ _key = " " + key
+ cpv = _pkgs.pop(0)
+ print(
+ self.prepend + _key,
+ "." * (35 - len(key)),
+ default,
+ pp.number(count),
+ pp.cpv(cpv),
+ )
+ while _pkgs:
+ cpv = _pkgs.pop(0)
+ print(" " * 52 + pp.cpv(cpv))
+
+ def print_use_quiet(self, key, active, default, count, pkgs):
+ """Quietly prints a subset set of USE flag info.."""
+ if active in ["+", "-"]:
+ _key = pp.useflag((active + key), active == "+")
+ else:
+ _key = " " + key
+ print(self.prepend + _key, "." * (35 - len(key)), default, pp.number(count))
+
+ def print_keyword_verbose(self, key, stability, default, count, pkgs):
+ """Verbosely prints a set of keywords info. including the pkgs
+ using them.
+ """
+ _pkgs = pkgs[:]
+ _key = pp.keyword(
+ (stability + key), stable=(stability == " "), hard_masked=stability == "-"
+ )
+ cpv = _pkgs.pop(0)
+ print(
+ self.prepend + _key,
+ "." * (20 - len(key)),
+ default,
+ pp.number(count),
+ pp.cpv(cpv),
+ )
+ while _pkgs:
+ cpv = _pkgs.pop(0)
+ print(" " * 37 + pp.cpv(cpv))
+
+ def print_keyword_quiet(self, key, stability, default, count, pkgs):
+ """Quietly prints a subset set of USE flag info.."""
+ _key = pp.keyword(
+ (stability + key), stable=(stability == " "), hard_masked=stability == "-"
+ )
+ print(self.prepend + _key, "." * (20 - len(key)), default, pp.number(count))
+
+ def _format_pkg(self, key, active, flags):
+ """Determines the stats for key, formats it and
+ calls the pre-determined print function
+ """
+ (plus, minus, cleaned) = flags
+ _plus = []
+ _minus = []
+ _cleaned = []
+ for flag in plus:
+ _flag = flag.strip()
+ if _flag:
+ _plus.append(_flag)
+ for flag in minus:
+ _flag = flag.strip()
+ if _flag:
+ _minus.append(_flag)
+ for flag in cleaned:
+ _flag = flag.strip()
+ if _flag:
+ _cleaned.append(_flag)
+ # print("cpv=", key, "_plus=", _plus, "_minus=", _minus)
+ self.print_fn(self.prepend + key, (plus, minus, cleaned))
+
+ def print_pkg_verbose(self, cpv, flags):
+ """Verbosely prints the pkg's use flag info."""
+ (plus, minus, unset) = flags
+ _flags = []
+ for flag in plus:
+ _flags.append(pp.useflag((flag), True))
+ for flag in minus:
+ _flags.append(pp.useflag(("-" + flag), False))
+ for flag in unset:
+ _flags.append(pp.globaloption("-" + flag))
+
+ print(self._format_values(cpv, ", ".join(_flags)))
+
+ def print_pkg_quiet(self, cpv, flags):
+ """Verbosely prints the pkg's use flag info."""
+ (plus, minus, unset) = flags
+ _flags = []
+ for flag in plus:
+ _flags.append(pp.useflag((flag), True))
+ for flag in minus:
+ _flags.append(pp.useflag(("-" + flag), False))
+ for flag in unset:
+ _flags.append(pp.globaloption("-" + flag))
+
+ print(self._format_values(cpv, ", ".join(_flags)))
class RebuildPrinter(CpvValueWrapper):
- """Output functions"""
- def __init__(self, target, pretend=True, exact=False,
- slot=False, key_width=1, width=None):
- """@param references: list of accepted keywords or
- the system use flags
- """
- self.target = target
- self.set_target(target)
- self.pretend = pretend
- CpvValueWrapper.__init__(self, cpv_width=key_width, width=width)
- if pretend:
- self.spacer = ' '
- self.init_indent = len(self.spacer)
- else:
- self.spacer = ''
- self.exact = exact
- self.slot = slot
- self.data = {}
-
-
- def set_target(self, target):
- if target in ["use"]:
- self.print_fn = self.print_use
- elif target in ["keywords"]:
- self.print_fn = self.print_keyword
- elif target in ["unmask"]:
- self.print_fn = self.print_mask
- self.lines = [self.header()]
-
-
- def __call__(self, key, values, cp_count):
- if self.target in ["keywords", "use"]:
- self._format_atoms(key, values, cp_count)
- else:
- self._format_key(key, values)
-
-
- def _format_key(self, key, values):
- """Determines the stats for key, formats it and
- calls the pre-determined print function
- """
- if self.exact:
- _key = "=" + key
- else:
- parts = split_cpv(key)
- _key = '/'.join(parts[:2])
- values.sort()
- self.data[_key] = values
- self.print_fn( _key, values)
-
- def print_use(self, key, atom=None, values=None):
- """Prints a USE flag string.
- """
- if atom and not values:
- values = atom.use
- if self.pretend:
- flags = []
- for flag in values:
- flags.append(pp.useflag(flag, (flag[0] != '-')))
- print(self._format_values(self.spacer+key, ' '.join(flags)))
- else:
- line = ' '.join([key, ' '.join(values)])
- self.lines.append(line)
-
- def _format_atoms(self, key, atoms, count):
- """Determines if there are more than one atom in the values and
- calls the predetermined print function for each atom.
- """
- #print("_format_atoms(),", key, atoms)
- if self.exact:
- for atom in atoms:
- self.print_fn(str(atom), atom=atom)
- return
- #print("_format_atoms(), count =", count)
- if self.slot or count > 1:
- for atom in atoms:
- _key = str(atom.cp) + ":" + atom.slot
- self.print_fn(_key, atom=atom)
- else:
- for atom in atoms:
- _key = str(atom.cp)
- self.print_fn(_key, atom=atom)
- return
-
- def print_keyword(self, key, atom=None, keyword=None):
- """prints a pkg key and a keyword"""
- #print("print_keyword(),", key, keyword)
- if atom and not keyword:
- keyword = atom.keyword
- if self.pretend:
- print(self._format_values(key, keyword))
- else:
- line = ' '.join([key, keyword])
- self.lines.append(line)
-
-
- def print_unmask(self):
- pass
-
- def header(self):
- """Generates a file header
- """
-
- h=("# This package.%s file was generated by "
- %self.target +
- "gentoolkit's 'enalyze rebuild' module\n"
- "# Date: " + time.asctime() + "\n"
- )
- return h
+ """Output functions"""
+
+ def __init__(
+ self, target, pretend=True, exact=False, slot=False, key_width=1, width=None
+ ):
+ """@param references: list of accepted keywords or
+ the system use flags
+ """
+ self.target = target
+ self.set_target(target)
+ self.pretend = pretend
+ CpvValueWrapper.__init__(self, cpv_width=key_width, width=width)
+ if pretend:
+ self.spacer = " "
+ self.init_indent = len(self.spacer)
+ else:
+ self.spacer = ""
+ self.exact = exact
+ self.slot = slot
+ self.data = {}
+
+ def set_target(self, target):
+ if target in ["use"]:
+ self.print_fn = self.print_use
+ elif target in ["keywords"]:
+ self.print_fn = self.print_keyword
+ elif target in ["unmask"]:
+ self.print_fn = self.print_mask
+ self.lines = [self.header()]
+
+ def __call__(self, key, values, cp_count):
+ if self.target in ["keywords", "use"]:
+ self._format_atoms(key, values, cp_count)
+ else:
+ self._format_key(key, values)
+
+ def _format_key(self, key, values):
+ """Determines the stats for key, formats it and
+ calls the pre-determined print function
+ """
+ if self.exact:
+ _key = "=" + key
+ else:
+ parts = split_cpv(key)
+ _key = "/".join(parts[:2])
+ values.sort()
+ self.data[_key] = values
+ self.print_fn(_key, values)
+
+ def print_use(self, key, atom=None, values=None):
+ """Prints a USE flag string."""
+ if atom and not values:
+ values = atom.use
+ if self.pretend:
+ flags = []
+ for flag in values:
+ flags.append(pp.useflag(flag, (flag[0] != "-")))
+ print(self._format_values(self.spacer + key, " ".join(flags)))
+ else:
+ line = " ".join([key, " ".join(values)])
+ self.lines.append(line)
+
+ def _format_atoms(self, key, atoms, count):
+ """Determines if there are more than one atom in the values and
+ calls the predetermined print function for each atom.
+ """
+ # print("_format_atoms(),", key, atoms)
+ if self.exact:
+ for atom in atoms:
+ self.print_fn(str(atom), atom=atom)
+ return
+ # print("_format_atoms(), count =", count)
+ if self.slot or count > 1:
+ for atom in atoms:
+ _key = str(atom.cp) + ":" + atom.slot
+ self.print_fn(_key, atom=atom)
+ else:
+ for atom in atoms:
+ _key = str(atom.cp)
+ self.print_fn(_key, atom=atom)
+ return
+
+ def print_keyword(self, key, atom=None, keyword=None):
+ """prints a pkg key and a keyword"""
+ # print("print_keyword(),", key, keyword)
+ if atom and not keyword:
+ keyword = atom.keyword
+ if self.pretend:
+ print(self._format_values(key, keyword))
+ else:
+ line = " ".join([key, keyword])
+ self.lines.append(line)
+
+ def print_unmask(self):
+ pass
+
+ def header(self):
+ """Generates a file header"""
+
+ h = (
+ "# This package.%s file was generated by " % self.target
+ + "gentoolkit's 'enalyze rebuild' module\n"
+ "# Date: " + time.asctime() + "\n"
+ )
+ return h
diff --git a/pym/gentoolkit/enalyze/rebuild.py b/pym/gentoolkit/enalyze/rebuild.py
index c0ac8cb..f341680 100644
--- a/pym/gentoolkit/enalyze/rebuild.py
+++ b/pym/gentoolkit/enalyze/rebuild.py
@@ -15,8 +15,12 @@ import os
import gentoolkit
from gentoolkit.module_base import ModuleBase
from gentoolkit import pprinter as pp
-from gentoolkit.enalyze.lib import (get_installed_use, get_flags, FlagAnalyzer,
- KeywordAnalyser)
+from gentoolkit.enalyze.lib import (
+ get_installed_use,
+ get_flags,
+ FlagAnalyzer,
+ KeywordAnalyser,
+)
from gentoolkit.enalyze.output import RebuildPrinter
from gentoolkit.atom import Atom
from gentoolkit.package import Package
@@ -25,343 +29,389 @@ from gentoolkit.package import Package
import portage
from portage import _encodings, _unicode_encode
-def cpv_all_diff_use(
- cpvs=None,
- system_flags=None,
- # override-able for testing
- _get_flags=get_flags,
- _get_used=get_installed_use
- ):
- """Data gathering and analysis function determines
- the difference between the current default USE flag settings
- and the currently installed pkgs recorded USE flag settings
- @type cpvs: list
- @param cpvs: optional list of [cat/pkg-ver,...] to analyze or
- defaults to entire installed pkg db
- @type: system_flags: list
- @param system_flags: the current default USE flags as defined
- by portage.settings["USE"].split()
- @type _get_flags: function
- @param _get_flags: ovride-able for testing,
- defaults to gentoolkit.enalyze.lib.get_flags
- @param _get_used: ovride-able for testing,
- defaults to gentoolkit.enalyze.lib.get_installed_use
- @rtype dict. {cpv:['flag1', '-flag2',...]}
- """
- if cpvs is None:
- cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
- cpvs.sort()
- data = {}
- cp_counts = {}
- # pass them in to override for tests
- flags = FlagAnalyzer(system_flags,
- filter_defaults=True,
- target="USE",
- _get_flags=_get_flags,
- _get_used=get_installed_use
- )
- for cpv in cpvs:
- plus, minus, unset = flags.analyse_cpv(cpv)
- atom = Atom("="+cpv)
- atom.slot = portage.db[portage.root]["vartree"].dbapi.aux_get(atom.cpv, ["SLOT"])[0]
- for flag in minus:
- plus.add("-"+flag)
- if len(plus):
- if atom.cp not in data:
- data[atom.cp] = []
- if atom.cp not in cp_counts:
- cp_counts[atom.cp] = 0
- atom.use = list(plus)
- data[atom.cp].append(atom)
- cp_counts[atom.cp] += 1
- return data, cp_counts
+def cpv_all_diff_use(
+ cpvs=None,
+ system_flags=None,
+ # override-able for testing
+ _get_flags=get_flags,
+ _get_used=get_installed_use,
+):
+ """Data gathering and analysis function determines
+ the difference between the current default USE flag settings
+ and the currently installed pkgs recorded USE flag settings
+
+ @type cpvs: list
+ @param cpvs: optional list of [cat/pkg-ver,...] to analyze or
+ defaults to entire installed pkg db
+ @type: system_flags: list
+ @param system_flags: the current default USE flags as defined
+ by portage.settings["USE"].split()
+ @type _get_flags: function
+ @param _get_flags: ovride-able for testing,
+ defaults to gentoolkit.enalyze.lib.get_flags
+ @param _get_used: ovride-able for testing,
+ defaults to gentoolkit.enalyze.lib.get_installed_use
+ @rtype dict. {cpv:['flag1', '-flag2',...]}
+ """
+ if cpvs is None:
+ cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
+ cpvs.sort()
+ data = {}
+ cp_counts = {}
+ # pass them in to override for tests
+ flags = FlagAnalyzer(
+ system_flags,
+ filter_defaults=True,
+ target="USE",
+ _get_flags=_get_flags,
+ _get_used=get_installed_use,
+ )
+ for cpv in cpvs:
+ plus, minus, unset = flags.analyse_cpv(cpv)
+ atom = Atom("=" + cpv)
+ atom.slot = portage.db[portage.root]["vartree"].dbapi.aux_get(
+ atom.cpv, ["SLOT"]
+ )[0]
+ for flag in minus:
+ plus.add("-" + flag)
+ if len(plus):
+ if atom.cp not in data:
+ data[atom.cp] = []
+ if atom.cp not in cp_counts:
+ cp_counts[atom.cp] = 0
+ atom.use = list(plus)
+ data[atom.cp].append(atom)
+ cp_counts[atom.cp] += 1
+ return data, cp_counts
def cpv_all_diff_keywords(
- cpvs=None,
- system_keywords=None,
- use_portage=False,
- # override-able for testing
- keywords=portage.settings["ACCEPT_KEYWORDS"],
- analyser = None
- ):
- """Analyze the installed pkgs 'keywords' for difference from ACCEPT_KEYWORDS
-
- @param cpvs: optional list of [cat/pkg-ver,...] to analyze or
- defaults to entire installed pkg db
- @param system_keywords: list of the system keywords
- @param keywords: user defined list of keywords to check and report on
- or reports on all relevant keywords found to have been used.
- @param _get_kwds: overridable function for testing
- @param _get_used: overridable function for testing
- @rtype dict. {keyword:{"stable":[cat/pkg-ver,...],
- "testing":[cat/pkg-ver,...]}
- """
- if cpvs is None:
- cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
- keyword_users = {}
- cp_counts = {}
- for cpv in cpvs:
- if cpv.startswith("virtual"):
- continue
- if use_portage:
- keyword = analyser.get_inst_keyword_cpv(cpv)
- else:
- pkg = Package(cpv)
- keyword = analyser.get_inst_keyword_pkg(pkg)
- #print "returned keyword =", cpv, keyword, keyword[0]
- key = keyword[0]
- if key in ["~", "-"] and keyword not in system_keywords:
- atom = Atom("="+cpv)
- if atom.cp not in keyword_users:
- keyword_users[atom.cp] = []
- if atom.cp not in cp_counts:
- cp_counts[atom.cp] = 0
- if key in ["~"]:
- atom.keyword = keyword
- atom.slot = portage.db[portage.root]["vartree"].dbapi.aux_get(atom.cpv, ["SLOT"])[0]
- keyword_users[atom.cp].append(atom)
- cp_counts[atom.cp] += 1
- elif key in ["-"]:
- #print "adding cpv to missing:", cpv
- atom.keyword = "**"
- atom.slot = portage.db[portage.root]["vartree"].dbapi.aux_get(atom.cpv, ["SLOT"])[0]
- keyword_users[atom.cp].append(atom)
- cp_counts[atom.cp] += 1
- return keyword_users, cp_counts
+ cpvs=None,
+ system_keywords=None,
+ use_portage=False,
+ # override-able for testing
+ keywords=portage.settings["ACCEPT_KEYWORDS"],
+ analyser=None,
+):
+ """Analyze the installed pkgs 'keywords' for difference from ACCEPT_KEYWORDS
+
+ @param cpvs: optional list of [cat/pkg-ver,...] to analyze or
+ defaults to entire installed pkg db
+ @param system_keywords: list of the system keywords
+ @param keywords: user defined list of keywords to check and report on
+ or reports on all relevant keywords found to have been used.
+ @param _get_kwds: overridable function for testing
+ @param _get_used: overridable function for testing
+ @rtype dict. {keyword:{"stable":[cat/pkg-ver,...],
+ "testing":[cat/pkg-ver,...]}
+ """
+ if cpvs is None:
+ cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
+ keyword_users = {}
+ cp_counts = {}
+ for cpv in cpvs:
+ if cpv.startswith("virtual"):
+ continue
+ if use_portage:
+ keyword = analyser.get_inst_keyword_cpv(cpv)
+ else:
+ pkg = Package(cpv)
+ keyword = analyser.get_inst_keyword_pkg(pkg)
+ # print "returned keyword =", cpv, keyword, keyword[0]
+ key = keyword[0]
+ if key in ["~", "-"] and keyword not in system_keywords:
+ atom = Atom("=" + cpv)
+ if atom.cp not in keyword_users:
+ keyword_users[atom.cp] = []
+ if atom.cp not in cp_counts:
+ cp_counts[atom.cp] = 0
+ if key in ["~"]:
+ atom.keyword = keyword
+ atom.slot = portage.db[portage.root]["vartree"].dbapi.aux_get(
+ atom.cpv, ["SLOT"]
+ )[0]
+ keyword_users[atom.cp].append(atom)
+ cp_counts[atom.cp] += 1
+ elif key in ["-"]:
+ # print "adding cpv to missing:", cpv
+ atom.keyword = "**"
+ atom.slot = portage.db[portage.root]["vartree"].dbapi.aux_get(
+ atom.cpv, ["SLOT"]
+ )[0]
+ keyword_users[atom.cp].append(atom)
+ cp_counts[atom.cp] += 1
+ return keyword_users, cp_counts
class Rebuild(ModuleBase):
- """Installed db analysis tool to query the installed databse
- and produce/output stats for USE flags or keywords/mask.
- The 'rebuild' action output is in the form suitable for file type output
- to create a new package.use, package.keywords, package.unmask
- type files in the event of needing to rebuild the
- /etc/portage/* user configs
- """
- def __init__(self):
- ModuleBase.__init__(self)
- self.command_name = "enalyze"
- self.module_name = "rebuild"
- self.options = {
- "use": False,
- "keywords": False,
- "unmask": False,
- "verbose": False,
- "quiet": False,
- "exact": False,
- "pretend": False,
- "prefix": False,
- "portage": True,
- "slot": False
- #"unset": False
- }
- self.module_opts = {
- "-p": ("pretend", "boolean", True),
- "--pretend": ("pretend", "boolean", True),
- "-e": ("exact", "boolean", True),
- "--exact": ("exact", "boolean", True),
- "-s": ("slot", "boolean", True),
- "--slot": ("slot", "boolean", True),
- "-v": ("verbose", "boolean", True),
- "--verbose": ("verbose", "boolean", True),
- }
- self.formatted_options = [
- (" -h, --help", "Outputs this useage message"),
- (" -p, --pretend", "Does not actually create the files."),
- (" ", "It directs the outputs to the screen"),
- (" -e, --exact", "will atomize the package with a"),
- (" ", "leading '=' and include the version"),
- (" -s, --slot", "will atomize the package with a"),
- (" ", "leading '=' and include the slot")
- ]
- self.formatted_args = [
- (" use",
- "causes the action to analyze the installed packages USE flags"),
- (" keywords",
- "causes the action to analyze the installed packages keywords"),
- (" unmask",
- "causes the action to analyze the installed packages " + \
- "current mask status")
- ]
- self.short_opts = "hepsv"
- self.long_opts = ("help", "exact", "pretend", "slot", "verbose")
- self.need_queries = True
- self.arg_spec = "TargetSpec"
- self.arg_options = ['use', 'keywords', 'unmask']
- self.arg_option = False
- self.warning = (
- " CAUTION",
- "This is beta software and some features/options are incomplete,",
- "some features may change in future releases includig its name.",
- "The file generated is saved in your home directory",
- "Feedback will be appreciated, http://bugs.gentoo.org")
-
-
-
- def run(self, input_args, quiet=False):
- """runs the module
-
- @param input_args: input arguments to be parsed
- """
- self.options['quiet'] = quiet
- query = self.main_setup(input_args)
- query = self.validate_query(query)
- if query in ["use"]:
- self.rebuild_use()
- elif query in ["keywords"]:
- self.rebuild_keywords()
- elif query in ["unmask"]:
- self.rebuild_unmask()
-
-
- def rebuild_use(self):
- if not self.options["quiet"]:
- print()
- print(" -- Scanning installed packages for USE flag settings that")
- print(" do not match the default settings")
- system_use = portage.settings["USE"].split()
- output = RebuildPrinter(
- "use", self.options["pretend"], self.options["exact"],
- self.options['slot'])
- pkgs, cp_counts = cpv_all_diff_use(system_flags=system_use)
- pkg_count = len(pkgs)
- if self.options["verbose"]:
- print()
- print((pp.emph(" -- Found ") + pp.number(str(pkg_count)) +
- pp.emph(" packages that need entries")))
- #print pp.emph(" package.use to maintain their current setting")
- pkg_keys = []
- if pkgs:
- pkg_keys = sorted(pkgs)
- #print len(pkgs)
- if self.options["pretend"] and not self.options["quiet"]:
- print()
- print(pp.globaloption(
- " -- These are the installed packages & use flags " +
- "that were detected"))
- print(pp.globaloption(" to need use flag settings other " +
- "than the defaults."))
- print()
- elif not self.options["quiet"]:
- print(" -- preparing pkgs for file entries")
- for pkg in pkg_keys:
- output(pkg, pkgs[pkg], cp_counts[pkg])
- if self.options['verbose']:
- message = (pp.emph(" ") +
- pp.number(str(pkg_count)) +
- pp.emph(" different packages"))
- print()
- print(pp.globaloption(" -- Totals"))
- print(message)
- #print
- #unique = list(unique_flags)
- #unique.sort()
- #print unique
- if not self.options["pretend"]:
- filepath = os.path.expanduser('~/package.use.test')
- self.save_file(filepath, output.lines)
-
- def rebuild_keywords(self):
- #print("Module action not yet available")
- #print()
- """This will scan the installed packages db and analyze the
- keywords used for installation and produce a report on them.
- """
- system_keywords = portage.settings["ACCEPT_KEYWORDS"].split()
- output = RebuildPrinter(
- "keywords", self.options["pretend"], self.options["exact"],
- self.options['slot'])
- arch = portage.settings["ARCH"]
- if self.options["prefix"]:
- # build a new keyword for testing
- system_keywords = "~" + arch + "-linux"
- if self.options["verbose"] or self.options["prefix"]:
- print("Current system ARCH =", arch)
- print("Current system ACCEPT_KEYWORDS =", system_keywords)
- self.analyser = KeywordAnalyser( arch, system_keywords, portage.db[portage.root]["vartree"].dbapi)
- #self.analyser.set_order(portage.settings["USE"].split())
- # only for testing
- test_use = portage.settings["USE"].split()
- if self.options['prefix'] and 'prefix' not in test_use:
- print("REBUILD_KEYWORDS() 'prefix' flag not found in system",
- "USE flags!!! appending for testing")
- print()
- test_use.append('prefix')
- self.analyser.set_order(test_use)
- # /end testing
-
- cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
- #print "Total number of installed ebuilds =", len(cpvs)
- pkgs, cp_counts = cpv_all_diff_keywords(
- cpvs=cpvs,
- system_keywords=system_keywords,
- use_portage=self.options['portage'],
- analyser = self.analyser
- )
- #print([pkgs[p][0].cpv for p in pkgs])
- pkg_keys = []
- if pkgs:
- pkg_keys = sorted(pkgs)
- #print(len(pkgs))
- if self.options["pretend"] and not self.options["quiet"]:
- print()
- print(pp.globaloption(
- " -- These are the installed packages & keywords " +
- "that were detected"))
- print(pp.globaloption(" to need keyword settings other " +
- "than the defaults."))
- print()
- elif not self.options["quiet"]:
- print(" -- preparing pkgs for file entries")
- for pkg in pkg_keys:
- output(pkg, pkgs[pkg], cp_counts[pkg])
- if not self.options['quiet']:
- if self.analyser.mismatched:
- print("_________________________________________________")
- print(("The following packages were found to have a \n" +
- "different recorded ARCH than the current system ARCH"))
- for cpv in self.analyser.mismatched:
- print("\t", pp.cpv(cpv))
- print("===================================================")
- print("Total number of entries in report =",
- pp.output.red(str(len(pkg_keys))))
- if self.options["verbose"]:
- print("Total number of installed ebuilds =",
- pp.output.red(str(len(cpvs))))
- print()
- if not self.options["pretend"]:
- filepath = os.path.expanduser('~/package.keywords.test')
- self.save_file(filepath, output.lines)
-
-
- def rebuild_unmask(self):
- self.not_implemented("unmask")
-
-
- def save_file(self, filepath, data):
- """Writes the data to the file determined by filepath
-
- @param filepath: string. eg. '/path/to/filename'
- @param data: list of lines to write to filepath
- """
- if not self.options["quiet"]:
- print(' - Saving file: %s' %filepath)
- with open(_unicode_encode(filepath, encoding=_encodings['fs']), mode="w",
- encoding=_encodings['content']) as output:
- output.write('\n'.join(data))
- print(" - Done")
+ """Installed db analysis tool to query the installed databse
+ and produce/output stats for USE flags or keywords/mask.
+ The 'rebuild' action output is in the form suitable for file type output
+ to create a new package.use, package.keywords, package.unmask
+ type files in the event of needing to rebuild the
+ /etc/portage/* user configs
+ """
+
+ def __init__(self):
+ ModuleBase.__init__(self)
+ self.command_name = "enalyze"
+ self.module_name = "rebuild"
+ self.options = {
+ "use": False,
+ "keywords": False,
+ "unmask": False,
+ "verbose": False,
+ "quiet": False,
+ "exact": False,
+ "pretend": False,
+ "prefix": False,
+ "portage": True,
+ "slot": False
+ # "unset": False
+ }
+ self.module_opts = {
+ "-p": ("pretend", "boolean", True),
+ "--pretend": ("pretend", "boolean", True),
+ "-e": ("exact", "boolean", True),
+ "--exact": ("exact", "boolean", True),
+ "-s": ("slot", "boolean", True),
+ "--slot": ("slot", "boolean", True),
+ "-v": ("verbose", "boolean", True),
+ "--verbose": ("verbose", "boolean", True),
+ }
+ self.formatted_options = [
+ (" -h, --help", "Outputs this useage message"),
+ (" -p, --pretend", "Does not actually create the files."),
+ (" ", "It directs the outputs to the screen"),
+ (" -e, --exact", "will atomize the package with a"),
+ (" ", "leading '=' and include the version"),
+ (" -s, --slot", "will atomize the package with a"),
+ (" ", "leading '=' and include the slot"),
+ ]
+ self.formatted_args = [
+ (
+ " use",
+ "causes the action to analyze the installed packages USE flags",
+ ),
+ (
+ " keywords",
+ "causes the action to analyze the installed packages keywords",
+ ),
+ (
+ " unmask",
+ "causes the action to analyze the installed packages "
+ + "current mask status",
+ ),
+ ]
+ self.short_opts = "hepsv"
+ self.long_opts = ("help", "exact", "pretend", "slot", "verbose")
+ self.need_queries = True
+ self.arg_spec = "TargetSpec"
+ self.arg_options = ["use", "keywords", "unmask"]
+ self.arg_option = False
+ self.warning = (
+ " CAUTION",
+ "This is beta software and some features/options are incomplete,",
+ "some features may change in future releases includig its name.",
+ "The file generated is saved in your home directory",
+ "Feedback will be appreciated, http://bugs.gentoo.org",
+ )
+
+ def run(self, input_args, quiet=False):
+ """runs the module
+
+ @param input_args: input arguments to be parsed
+ """
+ self.options["quiet"] = quiet
+ query = self.main_setup(input_args)
+ query = self.validate_query(query)
+ if query in ["use"]:
+ self.rebuild_use()
+ elif query in ["keywords"]:
+ self.rebuild_keywords()
+ elif query in ["unmask"]:
+ self.rebuild_unmask()
+
+ def rebuild_use(self):
+ if not self.options["quiet"]:
+ print()
+ print(" -- Scanning installed packages for USE flag settings that")
+ print(" do not match the default settings")
+ system_use = portage.settings["USE"].split()
+ output = RebuildPrinter(
+ "use", self.options["pretend"], self.options["exact"], self.options["slot"]
+ )
+ pkgs, cp_counts = cpv_all_diff_use(system_flags=system_use)
+ pkg_count = len(pkgs)
+ if self.options["verbose"]:
+ print()
+ print(
+ (
+ pp.emph(" -- Found ")
+ + pp.number(str(pkg_count))
+ + pp.emph(" packages that need entries")
+ )
+ )
+ # print pp.emph(" package.use to maintain their current setting")
+ pkg_keys = []
+ if pkgs:
+ pkg_keys = sorted(pkgs)
+ # print len(pkgs)
+ if self.options["pretend"] and not self.options["quiet"]:
+ print()
+ print(
+ pp.globaloption(
+ " -- These are the installed packages & use flags "
+ + "that were detected"
+ )
+ )
+ print(
+ pp.globaloption(
+ " to need use flag settings other " + "than the defaults."
+ )
+ )
+ print()
+ elif not self.options["quiet"]:
+ print(" -- preparing pkgs for file entries")
+ for pkg in pkg_keys:
+ output(pkg, pkgs[pkg], cp_counts[pkg])
+ if self.options["verbose"]:
+ message = (
+ pp.emph(" ")
+ + pp.number(str(pkg_count))
+ + pp.emph(" different packages")
+ )
+ print()
+ print(pp.globaloption(" -- Totals"))
+ print(message)
+ # print
+ # unique = list(unique_flags)
+ # unique.sort()
+ # print unique
+ if not self.options["pretend"]:
+ filepath = os.path.expanduser("~/package.use.test")
+ self.save_file(filepath, output.lines)
+
+ def rebuild_keywords(self):
+ # print("Module action not yet available")
+ # print()
+ """This will scan the installed packages db and analyze the
+ keywords used for installation and produce a report on them.
+ """
+ system_keywords = portage.settings["ACCEPT_KEYWORDS"].split()
+ output = RebuildPrinter(
+ "keywords",
+ self.options["pretend"],
+ self.options["exact"],
+ self.options["slot"],
+ )
+ arch = portage.settings["ARCH"]
+ if self.options["prefix"]:
+ # build a new keyword for testing
+ system_keywords = "~" + arch + "-linux"
+ if self.options["verbose"] or self.options["prefix"]:
+ print("Current system ARCH =", arch)
+ print("Current system ACCEPT_KEYWORDS =", system_keywords)
+ self.analyser = KeywordAnalyser(
+ arch, system_keywords, portage.db[portage.root]["vartree"].dbapi
+ )
+ # self.analyser.set_order(portage.settings["USE"].split())
+ # only for testing
+ test_use = portage.settings["USE"].split()
+ if self.options["prefix"] and "prefix" not in test_use:
+ print(
+ "REBUILD_KEYWORDS() 'prefix' flag not found in system",
+ "USE flags!!! appending for testing",
+ )
+ print()
+ test_use.append("prefix")
+ self.analyser.set_order(test_use)
+ # /end testing
+
+ cpvs = portage.db[portage.root]["vartree"].dbapi.cpv_all()
+ # print "Total number of installed ebuilds =", len(cpvs)
+ pkgs, cp_counts = cpv_all_diff_keywords(
+ cpvs=cpvs,
+ system_keywords=system_keywords,
+ use_portage=self.options["portage"],
+ analyser=self.analyser,
+ )
+ # print([pkgs[p][0].cpv for p in pkgs])
+ pkg_keys = []
+ if pkgs:
+ pkg_keys = sorted(pkgs)
+ # print(len(pkgs))
+ if self.options["pretend"] and not self.options["quiet"]:
+ print()
+ print(
+ pp.globaloption(
+ " -- These are the installed packages & keywords "
+ + "that were detected"
+ )
+ )
+ print(
+ pp.globaloption(
+ " to need keyword settings other " + "than the defaults."
+ )
+ )
+ print()
+ elif not self.options["quiet"]:
+ print(" -- preparing pkgs for file entries")
+ for pkg in pkg_keys:
+ output(pkg, pkgs[pkg], cp_counts[pkg])
+ if not self.options["quiet"]:
+ if self.analyser.mismatched:
+ print("_________________________________________________")
+ print(
+ (
+ "The following packages were found to have a \n"
+ + "different recorded ARCH than the current system ARCH"
+ )
+ )
+ for cpv in self.analyser.mismatched:
+ print("\t", pp.cpv(cpv))
+ print("===================================================")
+ print(
+ "Total number of entries in report =", pp.output.red(str(len(pkg_keys)))
+ )
+ if self.options["verbose"]:
+ print(
+ "Total number of installed ebuilds =", pp.output.red(str(len(cpvs)))
+ )
+ print()
+ if not self.options["pretend"]:
+ filepath = os.path.expanduser("~/package.keywords.test")
+ self.save_file(filepath, output.lines)
+
+ def rebuild_unmask(self):
+ self.not_implemented("unmask")
+
+ def save_file(self, filepath, data):
+ """Writes the data to the file determined by filepath
+
+ @param filepath: string. eg. '/path/to/filename'
+ @param data: list of lines to write to filepath
+ """
+ if not self.options["quiet"]:
+ print(" - Saving file: %s" % filepath)
+ with open(
+ _unicode_encode(filepath, encoding=_encodings["fs"]),
+ mode="w",
+ encoding=_encodings["content"],
+ ) as output:
+ output.write("\n".join(data))
+ print(" - Done")
def main(input_args):
- """Common starting method by the analyze master
- unless all modules are converted to this class method.
+ """Common starting method by the analyze master
+ unless all modules are converted to this class method.
- @param input_args: input args as supplied by equery master module.
- """
- query_module = Rebuild()
- query_module.run(input_args, gentoolkit.CONFIG['quiet'])
+ @param input_args: input args as supplied by equery master module.
+ """
+ query_module = Rebuild()
+ query_module.run(input_args, gentoolkit.CONFIG["quiet"])
-# vim: set ts=4 sw=4 tw=79:
+# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/eprefix.py b/pym/gentoolkit/eprefix.py
index 5acaa79..868a780 100644
--- a/pym/gentoolkit/eprefix.py
+++ b/pym/gentoolkit/eprefix.py
@@ -14,9 +14,9 @@ then in code add it to the filepath eg.:
"""
# Load EPREFIX from Portage, fall back to the empty string if it fails
try:
- from portage.const import EPREFIX
+ from portage.const import EPREFIX
except ImportError:
- EPREFIX = ''
+ EPREFIX = ""
if __name__ == "__main__":
- print("EPREFIX set to:", EPREFIX)
+ print("EPREFIX set to:", EPREFIX)
diff --git a/pym/gentoolkit/equery/__init__.py b/pym/gentoolkit/equery/__init__.py
index e5b3deb..cecb5be 100644
--- a/pym/gentoolkit/equery/__init__.py
+++ b/pym/gentoolkit/equery/__init__.py
@@ -4,12 +4,8 @@
"""Gentoo package query tool"""
-__all__ = (
- 'format_options',
- 'format_package_names',
- 'mod_usage'
-)
-__docformat__ = 'epytext'
+__all__ = ("format_options", "format_package_names", "mod_usage")
+__docformat__ = "epytext"
# version is dynamically set by distutils sdist
__version__ = "git"
@@ -32,8 +28,8 @@ from gentoolkit.textwrap_ import TextWrapper
__productname__ = "equery"
__authors__ = (
- 'Karl Trygve Kalleberg - Original author',
- 'Douglas Anderson - 0.3.0 author'
+ "Karl Trygve Kalleberg - Original author",
+ "Douglas Anderson - 0.3.0 author",
)
# =======
@@ -41,318 +37,330 @@ __authors__ = (
# =======
NAME_MAP = {
- 'b': 'belongs',
- 'k': 'check',
- 'd': 'depends',
- 'g': 'depgraph',
- 'f': 'files',
- 'h': 'hasuse',
- 'l': 'list_',
- 'y': 'keywords',
- 'a': 'has',
- 'm': 'meta',
- 's': 'size',
- 'u': 'uses',
- 'w': 'which'
+ "b": "belongs",
+ "k": "check",
+ "d": "depends",
+ "g": "depgraph",
+ "f": "files",
+ "h": "hasuse",
+ "l": "list_",
+ "y": "keywords",
+ "a": "has",
+ "m": "meta",
+ "s": "size",
+ "u": "uses",
+ "w": "which",
}
# =========
# Functions
# =========
+
def print_help(with_description=True):
- """Print description, usage and a detailed help message.
-
- @param with_description (bool): Option to print module's __doc__ or not
- """
-
- if with_description:
- print(__doc__)
- print(main_usage())
- print()
- print(pp.globaloption("global options"))
- print(format_options((
- (" -h, --help", "display this help message"),
- (" -q, --quiet", "minimal output"),
- (" -C, --no-color", "turn off colors"),
- (" -N, --no-pipe", "turn off pipe detection"),
- (" -V, --version", "display version info")
- )))
- print()
- print(pp.command("modules") + " (" + pp.command("short name") + ")")
- print(format_options((
- (" (b)elongs", "list what package FILES belong to"),
- (" chec(k)", "verify checksums and timestamps for PKG"),
- (" (d)epends", "list all packages directly depending on ATOM"),
- (" dep(g)raph", "display a tree of all dependencies for PKG"),
- (" (f)iles", "list all files installed by PKG"),
- (" h(a)s", "list all packages for matching ENVIRONMENT data stored in /var/db/pkg"),
- (" (h)asuse", "list all packages that have USE flag"),
- (" ke(y)words", "display keywords for specified PKG"),
- (" (l)ist", "list package matching PKG"),
- (" (m)eta", "display metadata about PKG"),
- (" (s)ize", "display total size of all files owned by PKG"),
- (" (u)ses", "display USE flags for PKG"),
- (" (w)hich", "print full path to ebuild for PKG")
- )))
+ """Print description, usage and a detailed help message.
+
+ @param with_description (bool): Option to print module's __doc__ or not
+ """
+
+ if with_description:
+ print(__doc__)
+ print(main_usage())
+ print()
+ print(pp.globaloption("global options"))
+ print(
+ format_options(
+ (
+ (" -h, --help", "display this help message"),
+ (" -q, --quiet", "minimal output"),
+ (" -C, --no-color", "turn off colors"),
+ (" -N, --no-pipe", "turn off pipe detection"),
+ (" -V, --version", "display version info"),
+ )
+ )
+ )
+ print()
+ print(pp.command("modules") + " (" + pp.command("short name") + ")")
+ print(
+ format_options(
+ (
+ (" (b)elongs", "list what package FILES belong to"),
+ (" chec(k)", "verify checksums and timestamps for PKG"),
+ (" (d)epends", "list all packages directly depending on ATOM"),
+ (" dep(g)raph", "display a tree of all dependencies for PKG"),
+ (" (f)iles", "list all files installed by PKG"),
+ (
+ " h(a)s",
+ "list all packages for matching ENVIRONMENT data stored in /var/db/pkg",
+ ),
+ (" (h)asuse", "list all packages that have USE flag"),
+ (" ke(y)words", "display keywords for specified PKG"),
+ (" (l)ist", "list package matching PKG"),
+ (" (m)eta", "display metadata about PKG"),
+ (" (s)ize", "display total size of all files owned by PKG"),
+ (" (u)ses", "display USE flags for PKG"),
+ (" (w)hich", "print full path to ebuild for PKG"),
+ )
+ )
+ )
def expand_module_name(module_name):
- """Returns one of the values of NAME_MAP or raises KeyError"""
+ """Returns one of the values of NAME_MAP or raises KeyError"""
- if module_name == 'list':
- # list is a Python builtin type, so we must rename our module
- return 'list_'
- elif module_name in NAME_MAP.values():
- return module_name
- else:
- return NAME_MAP[module_name]
+ if module_name == "list":
+ # list is a Python builtin type, so we must rename our module
+ return "list_"
+ elif module_name in NAME_MAP.values():
+ return module_name
+ else:
+ return NAME_MAP[module_name]
def format_options(options):
- """Format module options.
-
- @type options: list
- @param options: [('option 1', 'description 1'), ('option 2', 'des... )]
- @rtype: str
- @return: formatted options string
- """
-
- result = []
- twrap = TextWrapper(width=CONFIG['termWidth'])
- opts = (x[0] for x in options)
- descs = (x[1] for x in options)
- for opt, desc in zip(opts, descs):
- twrap.initial_indent = pp.emph(opt.ljust(25))
- twrap.subsequent_indent = " " * 25
- result.append(twrap.fill(desc))
-
- return '\n'.join(result)
-
-
-def format_filetype(path, fdesc, show_type=False, show_md5=False,
- show_timestamp=False):
- """Format a path for printing.
-
- @type path: str
- @param path: the path
- @type fdesc: list
- @param fdesc: [file_type, timestamp, MD5 sum/symlink target]
- file_type is one of dev, dir, obj, sym, fif.
- If file_type is dir, there is no timestamp or MD5 sum.
- If file_type is sym, fdesc[2] is the target of the symlink.
- @type show_type: bool
- @param show_type: if True, prepend the file's type to the formatted string
- @type show_md5: bool
- @param show_md5: if True, append MD5 sum to the formatted string
- @type show_timestamp: bool
- @param show_timestamp: if True, append time-of-creation after pathname
- @rtype: str
- @return: formatted pathname with optional added information
- """
-
- ftype = fpath = stamp = md5sum = ""
-
- if fdesc[0] == "obj":
- ftype = "file"
- fpath = path
- stamp = format_timestamp(fdesc[1])
- md5sum = fdesc[2]
- elif fdesc[0] == "dir":
- ftype = "dir"
- fpath = pp.path(path)
- elif fdesc[0] == "sym":
- ftype = "sym"
- stamp = format_timestamp(fdesc[1])
- tgt = fdesc[2].split()[0]
- if CONFIG["piping"]:
- fpath = path
- else:
- fpath = pp.path_symlink(path + " -> " + tgt)
- elif fdesc[0] == "dev":
- ftype = "dev"
- fpath = path
- elif fdesc[0] == "fif":
- ftype = "fifo"
- fpath = path
- else:
- sys.stderr.write(
- pp.error("%s has unknown type: %s" % (path, fdesc[0]))
- )
-
- result = ""
- if show_type:
- result += "%4s " % ftype
- result += fpath
- if show_timestamp:
- result += " " + stamp
- if show_md5:
- result += " " + md5sum
-
- return result
+ """Format module options.
+
+ @type options: list
+ @param options: [('option 1', 'description 1'), ('option 2', 'des... )]
+ @rtype: str
+ @return: formatted options string
+ """
+
+ result = []
+ twrap = TextWrapper(width=CONFIG["termWidth"])
+ opts = (x[0] for x in options)
+ descs = (x[1] for x in options)
+ for opt, desc in zip(opts, descs):
+ twrap.initial_indent = pp.emph(opt.ljust(25))
+ twrap.subsequent_indent = " " * 25
+ result.append(twrap.fill(desc))
+
+ return "\n".join(result)
+
+
+def format_filetype(path, fdesc, show_type=False, show_md5=False, show_timestamp=False):
+ """Format a path for printing.
+
+ @type path: str
+ @param path: the path
+ @type fdesc: list
+ @param fdesc: [file_type, timestamp, MD5 sum/symlink target]
+ file_type is one of dev, dir, obj, sym, fif.
+ If file_type is dir, there is no timestamp or MD5 sum.
+ If file_type is sym, fdesc[2] is the target of the symlink.
+ @type show_type: bool
+ @param show_type: if True, prepend the file's type to the formatted string
+ @type show_md5: bool
+ @param show_md5: if True, append MD5 sum to the formatted string
+ @type show_timestamp: bool
+ @param show_timestamp: if True, append time-of-creation after pathname
+ @rtype: str
+ @return: formatted pathname with optional added information
+ """
+
+ ftype = fpath = stamp = md5sum = ""
+
+ if fdesc[0] == "obj":
+ ftype = "file"
+ fpath = path
+ stamp = format_timestamp(fdesc[1])
+ md5sum = fdesc[2]
+ elif fdesc[0] == "dir":
+ ftype = "dir"
+ fpath = pp.path(path)
+ elif fdesc[0] == "sym":
+ ftype = "sym"
+ stamp = format_timestamp(fdesc[1])
+ tgt = fdesc[2].split()[0]
+ if CONFIG["piping"]:
+ fpath = path
+ else:
+ fpath = pp.path_symlink(path + " -> " + tgt)
+ elif fdesc[0] == "dev":
+ ftype = "dev"
+ fpath = path
+ elif fdesc[0] == "fif":
+ ftype = "fifo"
+ fpath = path
+ else:
+ sys.stderr.write(pp.error("%s has unknown type: %s" % (path, fdesc[0])))
+
+ result = ""
+ if show_type:
+ result += "%4s " % ftype
+ result += fpath
+ if show_timestamp:
+ result += " " + stamp
+ if show_md5:
+ result += " " + md5sum
+
+ return result
def format_timestamp(timestamp):
- """Format a timestamp into, e.g., '2009-01-31 21:19:44' format"""
+ """Format a timestamp into, e.g., '2009-01-31 21:19:44' format"""
- return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(timestamp)))
+ return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(timestamp)))
def initialize_configuration():
- """Setup the standard equery config"""
+ """Setup the standard equery config"""
- # Get terminal size
- term_width = pp.output.get_term_size()[1]
- if term_width < 1:
- # get_term_size() failed. Set a sane default width:
- term_width = 80
+ # Get terminal size
+ term_width = pp.output.get_term_size()[1]
+ if term_width < 1:
+ # get_term_size() failed. Set a sane default width:
+ term_width = 80
- # Terminal size, minus a 1-char margin for text wrapping
- CONFIG['termWidth'] = term_width - 1
+ # Terminal size, minus a 1-char margin for text wrapping
+ CONFIG["termWidth"] = term_width - 1
- # Guess color output
- if (CONFIG['color'] == -1 and os.getenv("NOCOLOR") in ("yes", "true") or
- CONFIG['color'] == 0):
- pp.output.nocolor()
+ # Guess color output
+ if (
+ CONFIG["color"] == -1
+ and os.getenv("NOCOLOR") in ("yes", "true")
+ or CONFIG["color"] == 0
+ ):
+ pp.output.nocolor()
- if CONFIG['piping']:
- CONFIG['verbose'] = False
- # set extra wide, should disable wrapping unless
- # there is some extra long text
- CONFIG['termWidth'] = 600
+ if CONFIG["piping"]:
+ CONFIG["verbose"] = False
+ # set extra wide, should disable wrapping unless
+ # there is some extra long text
+ CONFIG["termWidth"] = 600
- CONFIG['debug'] = bool(os.getenv('DEBUG', False))
+ CONFIG["debug"] = bool(os.getenv("DEBUG", False))
def main_usage():
- """Return the main usage message for equery"""
+ """Return the main usage message for equery"""
- return "%(usage)s %(product)s [%(g_opts)s] %(mod_name)s [%(mod_opts)s]" % {
- 'usage': pp.emph("Usage:"),
- 'product': pp.productname(__productname__),
- 'g_opts': pp.globaloption("global-options"),
- 'mod_name': pp.command("module-name"),
- 'mod_opts': pp.localoption("module-options")
- }
+ return "%(usage)s %(product)s [%(g_opts)s] %(mod_name)s [%(mod_opts)s]" % {
+ "usage": pp.emph("Usage:"),
+ "product": pp.productname(__productname__),
+ "g_opts": pp.globaloption("global-options"),
+ "mod_name": pp.command("module-name"),
+ "mod_opts": pp.localoption("module-options"),
+ }
def mod_usage(mod_name="module", arg="pkgspec", optional=False):
- """Provide a consistent usage message to the calling module.
+ """Provide a consistent usage message to the calling module.
- @type arg: string
- @param arg: what kind of argument the module takes (pkgspec, filename, etc)
- @type optional: bool
- @param optional: is the argument optional?
- """
+ @type arg: string
+ @param arg: what kind of argument the module takes (pkgspec, filename, etc)
+ @type optional: bool
+ @param optional: is the argument optional?
+ """
- return "%(usage)s: %(mod_name)s [%(opts)s] %(arg)s" % {
- 'usage': pp.emph("Usage"),
- 'mod_name': pp.command(mod_name),
- 'opts': pp.localoption("options"),
- 'arg': ("[%s]" % pp.emph(arg)) if optional else pp.emph(arg)
- }
+ return "%(usage)s: %(mod_name)s [%(opts)s] %(arg)s" % {
+ "usage": pp.emph("Usage"),
+ "mod_name": pp.command(mod_name),
+ "opts": pp.localoption("options"),
+ "arg": ("[%s]" % pp.emph(arg)) if optional else pp.emph(arg),
+ }
def parse_global_options(global_opts, args):
- """Parse global input args and return True if we should display help for
- the called module, else False (or display help and exit from here).
- """
-
- need_help = False
- do_help = False
- opts = (opt[0] for opt in global_opts)
- for opt in opts:
- if opt in ('-h', '--help'):
- if args:
- need_help = True
- else:
- do_help = True
- elif opt in ('-q','--quiet'):
- CONFIG['quiet'] = True
- elif opt in ('-C', '--no-color', '--nocolor'):
- CONFIG['color'] = 0
- pp.output.nocolor()
- elif opt in ('-N', '--no-pipe'):
- CONFIG['piping'] = False
- elif opt in ('-V', '--version'):
- print_version()
- sys.exit(0)
- elif opt in ('--debug'):
- CONFIG['debug'] = True
- if do_help:
- print_help()
- sys.exit(0)
- return need_help
+ """Parse global input args and return True if we should display help for
+ the called module, else False (or display help and exit from here).
+ """
+
+ need_help = False
+ do_help = False
+ opts = (opt[0] for opt in global_opts)
+ for opt in opts:
+ if opt in ("-h", "--help"):
+ if args:
+ need_help = True
+ else:
+ do_help = True
+ elif opt in ("-q", "--quiet"):
+ CONFIG["quiet"] = True
+ elif opt in ("-C", "--no-color", "--nocolor"):
+ CONFIG["color"] = 0
+ pp.output.nocolor()
+ elif opt in ("-N", "--no-pipe"):
+ CONFIG["piping"] = False
+ elif opt in ("-V", "--version"):
+ print_version()
+ sys.exit(0)
+ elif opt in ("--debug"):
+ CONFIG["debug"] = True
+ if do_help:
+ print_help()
+ sys.exit(0)
+ return need_help
def print_version():
- """Print the version of this tool to the console."""
+ """Print the version of this tool to the console."""
- print("%(product)s (%(version)s) - %(docstring)s" % {
- "product": pp.productname(__productname__),
- "version": __version__,
- "docstring": __doc__
- })
+ print(
+ "%(product)s (%(version)s) - %(docstring)s"
+ % {
+ "product": pp.productname(__productname__),
+ "version": __version__,
+ "docstring": __doc__,
+ }
+ )
def split_arguments(args):
- """Separate module name from module arguments"""
+ """Separate module name from module arguments"""
- return args.pop(0), args
+ return args.pop(0), args
def main(argv):
- """Parse input and run the program."""
-
- short_opts = "hqCNV"
- long_opts = (
- 'help', 'quiet', 'nocolor', 'no-color', 'no-pipe', 'version', 'debug'
- )
-
- initialize_configuration()
-
- try:
- global_opts, args = getopt(argv[1:], short_opts, long_opts)
- except GetoptError as err:
- sys.stderr.write(pp.error("Global %s" % err))
- print_help(with_description=False)
- sys.exit(2)
-
- # Parse global options
- need_help = parse_global_options(global_opts, args)
-
- # verbose is shorthand for the very common 'not quiet or piping'
- if CONFIG['quiet'] or CONFIG['piping']:
- CONFIG['verbose'] = False
- else:
- CONFIG['verbose'] = True
-
- try:
- module_name, module_args = split_arguments(args)
- except IndexError:
- print_help()
- sys.exit(2)
-
- if need_help:
- module_args.append('--help')
-
- try:
- expanded_module_name = expand_module_name(module_name)
- except KeyError:
- sys.stderr.write(pp.error("Unknown module '%s'" % module_name))
- print_help(with_description=False)
- sys.exit(2)
-
- try:
- loaded_module = __import__(
- expanded_module_name, globals(), locals(), [], 1
- )
- loaded_module.main(module_args)
- except portage.exception.AmbiguousPackageName as err:
- raise errors.GentoolkitAmbiguousPackage(err.args[0])
- except IOError as err:
- if err.errno != errno.EPIPE:
- raise
-
-if __name__ == '__main__':
- main(sys.argv)
+ """Parse input and run the program."""
+
+ short_opts = "hqCNV"
+ long_opts = ("help", "quiet", "nocolor", "no-color", "no-pipe", "version", "debug")
+
+ initialize_configuration()
+
+ try:
+ global_opts, args = getopt(argv[1:], short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Global %s" % err))
+ print_help(with_description=False)
+ sys.exit(2)
+
+ # Parse global options
+ need_help = parse_global_options(global_opts, args)
+
+ # verbose is shorthand for the very common 'not quiet or piping'
+ if CONFIG["quiet"] or CONFIG["piping"]:
+ CONFIG["verbose"] = False
+ else:
+ CONFIG["verbose"] = True
+
+ try:
+ module_name, module_args = split_arguments(args)
+ except IndexError:
+ print_help()
+ sys.exit(2)
+
+ if need_help:
+ module_args.append("--help")
+
+ try:
+ expanded_module_name = expand_module_name(module_name)
+ except KeyError:
+ sys.stderr.write(pp.error("Unknown module '%s'" % module_name))
+ print_help(with_description=False)
+ sys.exit(2)
+
+ try:
+ loaded_module = __import__(expanded_module_name, globals(), locals(), [], 1)
+ loaded_module.main(module_args)
+ except portage.exception.AmbiguousPackageName as err:
+ raise errors.GentoolkitAmbiguousPackage(err.args[0])
+ except IOError as err:
+ if err.errno != errno.EPIPE:
+ raise
+
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/pym/gentoolkit/equery/belongs.py b/pym/gentoolkit/equery/belongs.py
index 1c9ab13..d62ff9a 100644
--- a/pym/gentoolkit/equery/belongs.py
+++ b/pym/gentoolkit/equery/belongs.py
@@ -8,7 +8,7 @@ Note: Normally, only one package will own a file. If multiple packages own
the same file, it usually constitutes a problem, and should be reported.
"""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
# =======
# Imports
@@ -18,137 +18,137 @@ import sys
from getopt import gnu_getopt, GetoptError
import gentoolkit.pprinter as pp
-from gentoolkit.equery import (format_filetype, format_options, mod_usage,
- CONFIG)
+from gentoolkit.equery import format_filetype, format_options, mod_usage, CONFIG
from gentoolkit.helpers import FileOwner
# =======
# Globals
# =======
-QUERY_OPTS = {
- "full_regex": False,
- "early_out": False,
- "name_only": False
-}
+QUERY_OPTS = {"full_regex": False, "early_out": False, "name_only": False}
# =======
# Classes
# =======
+
class BelongsPrinter:
- """Outputs a formatted list of packages that claim to own a files."""
-
- def __init__(self, verbose=True, name_only=False):
- if verbose:
- self.print_fn = self.print_verbose
- else:
- self.print_fn = self.print_quiet
-
- self.name_only = name_only
-
- def __call__(self, pkg, cfile):
- self.print_fn(pkg, cfile)
-
- def print_quiet(self, pkg, cfile):
- "Format for minimal output."
- if self.name_only:
- name = pkg.cp
- else:
- name = str(pkg.cpv)
- pp.uprint(name)
-
- def print_verbose(self, pkg, cfile):
- "Format for full output."
- file_str = pp.path(format_filetype(cfile, pkg.parsed_contents()[cfile]))
- if self.name_only:
- name = pkg.cp
- else:
- name = str(pkg.cpv)
- pp.uprint(pp.cpv(name), "(" + file_str + ")")
+ """Outputs a formatted list of packages that claim to own a files."""
+
+ def __init__(self, verbose=True, name_only=False):
+ if verbose:
+ self.print_fn = self.print_verbose
+ else:
+ self.print_fn = self.print_quiet
+
+ self.name_only = name_only
+
+ def __call__(self, pkg, cfile):
+ self.print_fn(pkg, cfile)
+
+ def print_quiet(self, pkg, cfile):
+ "Format for minimal output."
+ if self.name_only:
+ name = pkg.cp
+ else:
+ name = str(pkg.cpv)
+ pp.uprint(name)
+
+ def print_verbose(self, pkg, cfile):
+ "Format for full output."
+ file_str = pp.path(format_filetype(cfile, pkg.parsed_contents()[cfile]))
+ if self.name_only:
+ name = pkg.cp
+ else:
+ name = str(pkg.cpv)
+ pp.uprint(pp.cpv(name), "(" + file_str + ")")
+
# =========
# Functions
# =========
+
def parse_module_options(module_opts):
- """Parse module options and update QUERY_OPTS"""
-
- opts = (x[0] for x in module_opts)
- for opt in opts:
- if opt in ('-h','--help'):
- print_help()
- sys.exit(0)
- elif opt in ('-e', '--early-out', '--earlyout'):
- if opt == '--earlyout':
- sys.stderr.write(pp.warn("Use of --earlyout is deprecated."))
- sys.stderr.write(pp.warn("Please use --early-out."))
- print()
- QUERY_OPTS['early_out'] = True
- elif opt in ('-f', '--full-regex'):
- QUERY_OPTS['full_regex'] = True
- elif opt in ('-n', '--name-only'):
- QUERY_OPTS['name_only'] = True
+ """Parse module options and update QUERY_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ for opt in opts:
+ if opt in ("-h", "--help"):
+ print_help()
+ sys.exit(0)
+ elif opt in ("-e", "--early-out", "--earlyout"):
+ if opt == "--earlyout":
+ sys.stderr.write(pp.warn("Use of --earlyout is deprecated."))
+ sys.stderr.write(pp.warn("Please use --early-out."))
+ print()
+ QUERY_OPTS["early_out"] = True
+ elif opt in ("-f", "--full-regex"):
+ QUERY_OPTS["full_regex"] = True
+ elif opt in ("-n", "--name-only"):
+ QUERY_OPTS["name_only"] = True
def print_help(with_description=True):
- """Print description, usage and a detailed help message.
-
- @type with_description: bool
- @param with_description: if true, print module's __doc__ string
- """
-
- if with_description:
- print(__doc__.strip())
- print()
- print(mod_usage(mod_name="belongs", arg="filename"))
- print()
- print(pp.command("options"))
- print(format_options((
- (" -h, --help", "display this help message"),
- (" -f, --full-regex", "supplied query is a regex" ),
- (" -e, --early-out", "stop when first match is found"),
- (" -n, --name-only", "don't print the version")
- )))
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print(__doc__.strip())
+ print()
+ print(mod_usage(mod_name="belongs", arg="filename"))
+ print()
+ print(pp.command("options"))
+ print(
+ format_options(
+ (
+ (" -h, --help", "display this help message"),
+ (" -f, --full-regex", "supplied query is a regex"),
+ (" -e, --early-out", "stop when first match is found"),
+ (" -n, --name-only", "don't print the version"),
+ )
+ )
+ )
def main(input_args):
- """Parse input and run the program"""
-
- short_opts = "h:fen"
- long_opts = ('help', 'full-regex', 'early-out', 'earlyout',
- 'name-only')
-
- try:
- module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
- except GetoptError as err:
- sys.stderr.write(pp.error("Module %s" % err))
- print()
- print_help(with_description=False)
- sys.exit(2)
-
- parse_module_options(module_opts)
-
- if not queries:
- print_help()
- sys.exit(2)
-
- if CONFIG['verbose']:
- pp.uprint(" * Searching for %s ... " % (
- pp.regexpquery(",".join(queries)))
- )
-
- printer_fn = BelongsPrinter(
- verbose=CONFIG['verbose'], name_only=QUERY_OPTS['name_only']
- )
-
- find_owner = FileOwner(
- is_regex=QUERY_OPTS['full_regex'],
- early_out=QUERY_OPTS['early_out'],
- printer_fn=printer_fn
- )
-
- if not find_owner(queries):
- sys.exit(1)
+ """Parse input and run the program"""
+
+ short_opts = "h:fen"
+ long_opts = ("help", "full-regex", "early-out", "earlyout", "name-only")
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Module %s" % err))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ if CONFIG["verbose"]:
+ pp.uprint(" * Searching for %s ... " % (pp.regexpquery(",".join(queries))))
+
+ printer_fn = BelongsPrinter(
+ verbose=CONFIG["verbose"], name_only=QUERY_OPTS["name_only"]
+ )
+
+ find_owner = FileOwner(
+ is_regex=QUERY_OPTS["full_regex"],
+ early_out=QUERY_OPTS["early_out"],
+ printer_fn=printer_fn,
+ )
+
+ if not find_owner(queries):
+ sys.exit(1)
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/equery/check.py b/pym/gentoolkit/equery/check.py
index 47eba98..7a7c3db 100644
--- a/pym/gentoolkit/equery/check.py
+++ b/pym/gentoolkit/equery/check.py
@@ -4,7 +4,7 @@
"""Checks timestamps and MD5 sums for files owned by a given installed package"""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
# =======
# Imports
@@ -27,262 +27,265 @@ from gentoolkit.query import Query
# =======
QUERY_OPTS = {
- "in_installed": True,
- "in_porttree": False,
- "in_overlay": False,
- "check_MD5sum": True,
- "check_timestamp" : True,
- "is_regex": False,
- "only_failures": False,
- "show_progress": False,
+ "in_installed": True,
+ "in_porttree": False,
+ "in_overlay": False,
+ "check_MD5sum": True,
+ "check_timestamp": True,
+ "is_regex": False,
+ "only_failures": False,
+ "show_progress": False,
}
# =======
# Classes
# =======
+
class VerifyContents:
- """Verify installed packages' CONTENTS files.
-
- The CONTENTS file contains timestamps and MD5 sums for each file owned
- by a package.
- """
- def __init__(self, printer_fn=None):
- """Create a VerifyObjects instance.
-
- @type printer_fn: callable
- @param printer_fn: if defined, will be applied to each result as found
- """
- self.check_sums = True
- self.check_timestamps = True
- self.printer_fn = printer_fn
-
- self.is_regex = False
-
- def __call__(
- self,
- pkgs,
- is_regex=False,
- check_sums=True,
- check_timestamps=True
- ):
- self.is_regex = is_regex
- self.check_sums = check_sums
- self.check_timestamps = check_timestamps
-
- result = {}
- for pkg in pkgs:
- # _run_checks returns tuple(n_passed, n_checked, err)
- check_results = self._run_checks(pkg.parsed_contents())
- result[pkg.cpv] = check_results
- if self.printer_fn is not None:
- self.printer_fn(pkg.cpv, check_results)
-
- return result
-
- def _run_checks(self, files):
- """Run some basic sanity checks on a package's contents.
-
- If the file type (ftype) is not a directory or symlink, optionally
- verify MD5 sums or mtimes via L{self._verify_obj}.
-
- @see: gentoolkit.packages.get_contents()
- @type files: dict
- @param files: in form {'PATH': ['TYPE', 'TIMESTAMP', 'MD5SUM']}
- @rtype: tuple
- @return:
- n_passed (int): number of files that passed all checks
- n_checked (int): number of files checked
- errs (list): check errors' descriptions
- """
- n_checked = 0
- n_passed = 0
- errs = []
- for cfile in files:
- n_checked += 1
- ftype = files[cfile][0]
- real_cfile = os.environ.get('ROOT', '') + cfile
- if not os.path.lexists(real_cfile):
- errs.append("%s does not exist" % cfile)
- continue
- elif ftype == "dir":
- if not os.path.isdir(real_cfile):
- err = "%(cfile)s exists, but is not a directory"
- errs.append(err % locals())
- continue
- elif ftype == "obj":
- obj_errs = self._verify_obj(files, cfile, real_cfile, errs)
- if len(obj_errs) > len(errs):
- errs = obj_errs[:]
- continue
- elif ftype == "sym":
- target = files[cfile][2].strip()
- if not os.path.islink(real_cfile):
- err = "%(cfile)s exists, but is not a symlink"
- errs.append(err % locals())
- continue
- tgt = os.readlink(real_cfile)
- if tgt != target:
- err = "%(cfile)s does not point to %(target)s"
- errs.append(err % locals())
- continue
- else:
- err = "%(cfile)s has unknown type %(ftype)s"
- errs.append(err % locals())
- continue
- n_passed += 1
-
- return n_passed, n_checked, errs
-
- def _verify_obj(self, files, cfile, real_cfile, errs):
- """Verify the MD5 sum and/or mtime and return any errors."""
-
- obj_errs = errs[:]
- if self.check_sums:
- md5sum = files[cfile][2]
- try:
- cur_checksum = checksum.perform_md5(real_cfile, calc_prelink=1)
- except IOError:
- err = "Insufficient permissions to read %(cfile)s"
- obj_errs.append(err % locals())
- return obj_errs
- if cur_checksum != md5sum:
- err = "%(cfile)s has incorrect MD5sum"
- obj_errs.append(err % locals())
- return obj_errs
- if self.check_timestamps:
- mtime = int(files[cfile][1])
- st_mtime = int(os.lstat(real_cfile).st_mtime)
- if st_mtime != mtime:
- err = (
- "%(cfile)s has wrong mtime (is %(st_mtime)d, should be "
- "%(mtime)d)"
- )
- obj_errs.append(err % locals())
- return obj_errs
-
- return obj_errs
+ """Verify installed packages' CONTENTS files.
+
+ The CONTENTS file contains timestamps and MD5 sums for each file owned
+ by a package.
+ """
+
+ def __init__(self, printer_fn=None):
+ """Create a VerifyObjects instance.
+
+ @type printer_fn: callable
+ @param printer_fn: if defined, will be applied to each result as found
+ """
+ self.check_sums = True
+ self.check_timestamps = True
+ self.printer_fn = printer_fn
+
+ self.is_regex = False
+
+ def __call__(self, pkgs, is_regex=False, check_sums=True, check_timestamps=True):
+ self.is_regex = is_regex
+ self.check_sums = check_sums
+ self.check_timestamps = check_timestamps
+
+ result = {}
+ for pkg in pkgs:
+ # _run_checks returns tuple(n_passed, n_checked, err)
+ check_results = self._run_checks(pkg.parsed_contents())
+ result[pkg.cpv] = check_results
+ if self.printer_fn is not None:
+ self.printer_fn(pkg.cpv, check_results)
+
+ return result
+
+ def _run_checks(self, files):
+ """Run some basic sanity checks on a package's contents.
+
+ If the file type (ftype) is not a directory or symlink, optionally
+ verify MD5 sums or mtimes via L{self._verify_obj}.
+
+ @see: gentoolkit.packages.get_contents()
+ @type files: dict
+ @param files: in form {'PATH': ['TYPE', 'TIMESTAMP', 'MD5SUM']}
+ @rtype: tuple
+ @return:
+ n_passed (int): number of files that passed all checks
+ n_checked (int): number of files checked
+ errs (list): check errors' descriptions
+ """
+ n_checked = 0
+ n_passed = 0
+ errs = []
+ for cfile in files:
+ n_checked += 1
+ ftype = files[cfile][0]
+ real_cfile = os.environ.get("ROOT", "") + cfile
+ if not os.path.lexists(real_cfile):
+ errs.append("%s does not exist" % cfile)
+ continue
+ elif ftype == "dir":
+ if not os.path.isdir(real_cfile):
+ err = "%(cfile)s exists, but is not a directory"
+ errs.append(err % locals())
+ continue
+ elif ftype == "obj":
+ obj_errs = self._verify_obj(files, cfile, real_cfile, errs)
+ if len(obj_errs) > len(errs):
+ errs = obj_errs[:]
+ continue
+ elif ftype == "sym":
+ target = files[cfile][2].strip()
+ if not os.path.islink(real_cfile):
+ err = "%(cfile)s exists, but is not a symlink"
+ errs.append(err % locals())
+ continue
+ tgt = os.readlink(real_cfile)
+ if tgt != target:
+ err = "%(cfile)s does not point to %(target)s"
+ errs.append(err % locals())
+ continue
+ else:
+ err = "%(cfile)s has unknown type %(ftype)s"
+ errs.append(err % locals())
+ continue
+ n_passed += 1
+
+ return n_passed, n_checked, errs
+
+ def _verify_obj(self, files, cfile, real_cfile, errs):
+ """Verify the MD5 sum and/or mtime and return any errors."""
+
+ obj_errs = errs[:]
+ if self.check_sums:
+ md5sum = files[cfile][2]
+ try:
+ cur_checksum = checksum.perform_md5(real_cfile, calc_prelink=1)
+ except IOError:
+ err = "Insufficient permissions to read %(cfile)s"
+ obj_errs.append(err % locals())
+ return obj_errs
+ if cur_checksum != md5sum:
+ err = "%(cfile)s has incorrect MD5sum"
+ obj_errs.append(err % locals())
+ return obj_errs
+ if self.check_timestamps:
+ mtime = int(files[cfile][1])
+ st_mtime = int(os.lstat(real_cfile).st_mtime)
+ if st_mtime != mtime:
+ err = (
+ "%(cfile)s has wrong mtime (is %(st_mtime)d, should be "
+ "%(mtime)d)"
+ )
+ obj_errs.append(err % locals())
+ return obj_errs
+
+ return obj_errs
+
# =========
# Functions
# =========
+
def print_help(with_description=True):
- """Print description, usage and a detailed help message.
-
- @type with_description: bool
- @param with_description: if true, print module's __doc__ string
- """
-
- if with_description:
- print(__doc__.strip())
- print()
-
- # Deprecation warning added by djanderson, 12/2008
- depwarning = (
- "Default action for this module has changed in Gentoolkit 0.3.",
- "Use globbing to simulate the old behavior (see man equery).",
- "Use '*' to check all installed packages.",
- "Use 'foo-bar/*' to filter by category."
- )
- for line in depwarning:
- sys.stderr.write(pp.warn(line))
- print()
-
- print(mod_usage(mod_name="check"))
- print()
- print(pp.command("options"))
- print(format_options((
- (" -h, --help", "display this help message"),
- (" -f, --full-regex", "query is a regular expression"),
- (" -o, --only-failures", "only display packages that do not pass"),
- )))
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print(__doc__.strip())
+ print()
+
+ # Deprecation warning added by djanderson, 12/2008
+ depwarning = (
+ "Default action for this module has changed in Gentoolkit 0.3.",
+ "Use globbing to simulate the old behavior (see man equery).",
+ "Use '*' to check all installed packages.",
+ "Use 'foo-bar/*' to filter by category.",
+ )
+ for line in depwarning:
+ sys.stderr.write(pp.warn(line))
+ print()
+
+ print(mod_usage(mod_name="check"))
+ print()
+ print(pp.command("options"))
+ print(
+ format_options(
+ (
+ (" -h, --help", "display this help message"),
+ (" -f, --full-regex", "query is a regular expression"),
+ (" -o, --only-failures", "only display packages that do not pass"),
+ )
+ )
+ )
def checks_printer(cpv, data, verbose=True, only_failures=False):
- """Output formatted results of pkg file(s) checks"""
- seen = []
-
- n_passed, n_checked, errs = data
- n_failed = n_checked - n_passed
- if only_failures and not n_failed:
- return
- else:
- if verbose:
- if not cpv in seen:
- pp.uprint("* Checking %s ..." % (pp.emph(str(cpv))))
- seen.append(cpv)
- else:
- pp.uprint("%s:" % cpv, end=' ')
-
- if verbose:
- for err in errs:
- sys.stderr.write(pp.error(err))
-
- if verbose:
- n_passed = pp.number(str(n_passed))
- n_checked = pp.number(str(n_checked))
- info = " %(n_passed)s out of %(n_checked)s files passed"
- print(info % locals())
- print()
- else:
- print("failed(%s)" % n_failed)
+ """Output formatted results of pkg file(s) checks"""
+ seen = []
+
+ n_passed, n_checked, errs = data
+ n_failed = n_checked - n_passed
+ if only_failures and not n_failed:
+ return
+ else:
+ if verbose:
+ if not cpv in seen:
+ pp.uprint("* Checking %s ..." % (pp.emph(str(cpv))))
+ seen.append(cpv)
+ else:
+ pp.uprint("%s:" % cpv, end=" ")
+
+ if verbose:
+ for err in errs:
+ sys.stderr.write(pp.error(err))
+
+ if verbose:
+ n_passed = pp.number(str(n_passed))
+ n_checked = pp.number(str(n_checked))
+ info = " %(n_passed)s out of %(n_checked)s files passed"
+ print(info % locals())
+ print()
+ else:
+ print("failed(%s)" % n_failed)
def parse_module_options(module_opts):
- """Parse module options and update QUERY_OPTS"""
+ """Parse module options and update QUERY_OPTS"""
- opts = (x[0] for x in module_opts)
- for opt in opts:
- if opt in ('-h', '--help'):
- print_help()
- sys.exit(0)
- elif opt in ('-f', '--full-regex'):
- QUERY_OPTS['is_regex'] = True
- elif opt in ('-o', '--only-failures'):
- QUERY_OPTS['only_failures'] = True
+ opts = (x[0] for x in module_opts)
+ for opt in opts:
+ if opt in ("-h", "--help"):
+ print_help()
+ sys.exit(0)
+ elif opt in ("-f", "--full-regex"):
+ QUERY_OPTS["is_regex"] = True
+ elif opt in ("-o", "--only-failures"):
+ QUERY_OPTS["only_failures"] = True
def main(input_args):
- """Parse input and run the program"""
+ """Parse input and run the program"""
+
+ short_opts = "hof"
+ long_opts = ("help", "only-failures", "full-regex")
- short_opts = "hof"
- long_opts = ('help', 'only-failures', 'full-regex')
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Module %s" % err))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
- try:
- module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
- except GetoptError as err:
- sys.stderr.write(pp.error("Module %s" % err))
- print()
- print_help(with_description=False)
- sys.exit(2)
+ parse_module_options(module_opts)
- parse_module_options(module_opts)
+ if not queries:
+ print_help()
+ sys.exit(2)
- if not queries:
- print_help()
- sys.exit(2)
+ first_run = True
+ for query in (Query(x, QUERY_OPTS["is_regex"]) for x in queries):
+ if not first_run:
+ print()
- first_run = True
- for query in (Query(x, QUERY_OPTS['is_regex']) for x in queries):
- if not first_run:
- print()
+ matches = query.smart_find(**QUERY_OPTS)
- matches = query.smart_find(**QUERY_OPTS)
+ if not matches:
+ raise errors.GentoolkitNoMatches(query, in_installed=True)
- if not matches:
- raise errors.GentoolkitNoMatches(query, in_installed=True)
+ matches.sort()
- matches.sort()
+ printer = partial(
+ checks_printer,
+ verbose=CONFIG["verbose"],
+ only_failures=QUERY_OPTS["only_failures"],
+ )
+ check = VerifyContents(printer_fn=printer)
+ check(matches)
- printer = partial(
- checks_printer,
- verbose=CONFIG['verbose'],
- only_failures=QUERY_OPTS['only_failures']
- )
- check = VerifyContents(printer_fn=printer)
- check(matches)
+ first_run = False
- first_run = False
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/equery/depends.py b/pym/gentoolkit/equery/depends.py
index 74c6933..581e2b6 100644
--- a/pym/gentoolkit/equery/depends.py
+++ b/pym/gentoolkit/equery/depends.py
@@ -4,7 +4,7 @@
"""List all packages that depend on a atom given query"""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
# =======
# Imports
@@ -24,181 +24,190 @@ from gentoolkit.cpv import CPV
# =======
QUERY_OPTS = {
- "include_masked": False,
- "only_direct": True,
- "max_depth": -1,
+ "include_masked": False,
+ "only_direct": True,
+ "max_depth": -1,
}
# =======
# Classes
# =======
+
class DependPrinter:
- """Output L{gentoolkit.dependencies.Dependencies} objects."""
- def __init__(self, verbose=True):
- self.verbose = verbose
-
- if verbose:
- self.print_fn = self.print_verbose
- else:
- self.print_fn = self.print_quiet
-
- def __call__(self, dep, dep_is_displayed=False):
- self.format_depend(dep, dep_is_displayed)
-
- @staticmethod
- def print_verbose(indent, cpv, use_conditional, depatom):
- """Verbosely prints a set of dep strings."""
-
- sep = ' ? ' if (depatom and use_conditional) else ''
- pp.uprint(indent + pp.cpv(cpv), "(" + use_conditional +
- sep + depatom + ")")
-
- @staticmethod
- def print_quiet(indent, cpv, use_conditional, depatom):
- """Quietly prints a subset set of dep strings."""
-
- pp.uprint(indent + cpv)
-
- def format_depend(self, dep, dep_is_displayed):
- """Format a dependency for printing.
-
- @type dep: L{gentoolkit.dependencies.Dependencies}
- @param dep: the dependency to display
- """
-
- # Don't print blank lines
- if dep_is_displayed and not self.verbose:
- return
-
- depth = getattr(dep, 'depth', 0)
- indent = " " * depth
- mdep = dep.matching_dep
- use_conditional = ""
- if mdep.use_conditional:
- use_conditional = " & ".join(
- pp.useflag(u) for u in mdep.use_conditional.split()
- )
- if mdep.operator == '=*':
- formatted_dep = '=%s*' % str(mdep.cpv)
- else:
- formatted_dep = mdep.operator + str(mdep.cpv)
- if mdep.slot:
- formatted_dep += pp.emph(':') + pp.slot(mdep.slot)
- if mdep.sub_slot:
- formatted_dep += pp.slot('/') + pp.slot(mdep.sub_slot)
- if mdep.use:
- useflags = pp.useflag(','.join(mdep.use.tokens))
- formatted_dep += (pp.emph('[') + useflags + pp.emph(']'))
-
- if dep_is_displayed:
- indent = indent + " " * len(str(dep.cpv))
- self.print_fn(indent, '', use_conditional, formatted_dep)
- else:
- self.print_fn(indent, str(dep.cpv), use_conditional, formatted_dep)
+ """Output L{gentoolkit.dependencies.Dependencies} objects."""
+
+ def __init__(self, verbose=True):
+ self.verbose = verbose
+
+ if verbose:
+ self.print_fn = self.print_verbose
+ else:
+ self.print_fn = self.print_quiet
+
+ def __call__(self, dep, dep_is_displayed=False):
+ self.format_depend(dep, dep_is_displayed)
+
+ @staticmethod
+ def print_verbose(indent, cpv, use_conditional, depatom):
+ """Verbosely prints a set of dep strings."""
+
+ sep = " ? " if (depatom and use_conditional) else ""
+ pp.uprint(indent + pp.cpv(cpv), "(" + use_conditional + sep + depatom + ")")
+
+ @staticmethod
+ def print_quiet(indent, cpv, use_conditional, depatom):
+ """Quietly prints a subset set of dep strings."""
+
+ pp.uprint(indent + cpv)
+
+ def format_depend(self, dep, dep_is_displayed):
+ """Format a dependency for printing.
+
+ @type dep: L{gentoolkit.dependencies.Dependencies}
+ @param dep: the dependency to display
+ """
+
+ # Don't print blank lines
+ if dep_is_displayed and not self.verbose:
+ return
+
+ depth = getattr(dep, "depth", 0)
+ indent = " " * depth
+ mdep = dep.matching_dep
+ use_conditional = ""
+ if mdep.use_conditional:
+ use_conditional = " & ".join(
+ pp.useflag(u) for u in mdep.use_conditional.split()
+ )
+ if mdep.operator == "=*":
+ formatted_dep = "=%s*" % str(mdep.cpv)
+ else:
+ formatted_dep = mdep.operator + str(mdep.cpv)
+ if mdep.slot:
+ formatted_dep += pp.emph(":") + pp.slot(mdep.slot)
+ if mdep.sub_slot:
+ formatted_dep += pp.slot("/") + pp.slot(mdep.sub_slot)
+ if mdep.use:
+ useflags = pp.useflag(",".join(mdep.use.tokens))
+ formatted_dep += pp.emph("[") + useflags + pp.emph("]")
+
+ if dep_is_displayed:
+ indent = indent + " " * len(str(dep.cpv))
+ self.print_fn(indent, "", use_conditional, formatted_dep)
+ else:
+ self.print_fn(indent, str(dep.cpv), use_conditional, formatted_dep)
+
# =========
# Functions
# =========
+
def print_help(with_description=True):
- """Print description, usage and a detailed help message.
-
- @type with_description: bool
- @param with_description: if true, print module's __doc__ string
- """
-
- if with_description:
- print(__doc__.strip())
- print()
- print(mod_usage(mod_name="depends"))
- print()
- print(pp.command("options"))
- print(format_options((
- (" -h, --help", "display this help message"),
- (" -a, --all-packages",
- "include dependencies that are not installed (slow)"),
- (" -D, --indirect",
- "search both direct and indirect dependencies"),
- (" --depth=N", "limit indirect dependency tree to specified depth")
- )))
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print(__doc__.strip())
+ print()
+ print(mod_usage(mod_name="depends"))
+ print()
+ print(pp.command("options"))
+ print(
+ format_options(
+ (
+ (" -h, --help", "display this help message"),
+ (
+ " -a, --all-packages",
+ "include dependencies that are not installed (slow)",
+ ),
+ (" -D, --indirect", "search both direct and indirect dependencies"),
+ (" --depth=N", "limit indirect dependency tree to specified depth"),
+ )
+ )
+ )
def parse_module_options(module_opts):
- """Parse module options and update QUERY_OPTS"""
-
- opts = (x[0] for x in module_opts)
- posargs = (x[1] for x in module_opts)
- for opt, posarg in zip(opts, posargs):
- if opt in ('-h', '--help'):
- print_help()
- sys.exit(0)
- elif opt in ('-a', '--all-packages'):
- QUERY_OPTS['include_masked'] = True
- elif opt in ('-D', '--indirect'):
- QUERY_OPTS['only_direct'] = False
- elif opt in ('--depth'):
- if posarg.isdigit():
- depth = int(posarg)
- else:
- err = "Module option --depth requires integer (got '%s')"
- sys.stdout.write(pp.error(err % posarg))
- print()
- print_help(with_description=False)
- sys.exit(2)
- QUERY_OPTS["max_depth"] = depth
+ """Parse module options and update QUERY_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ("-h", "--help"):
+ print_help()
+ sys.exit(0)
+ elif opt in ("-a", "--all-packages"):
+ QUERY_OPTS["include_masked"] = True
+ elif opt in ("-D", "--indirect"):
+ QUERY_OPTS["only_direct"] = False
+ elif opt in ("--depth"):
+ if posarg.isdigit():
+ depth = int(posarg)
+ else:
+ err = "Module option --depth requires integer (got '%s')"
+ sys.stdout.write(pp.error(err % posarg))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
+ QUERY_OPTS["max_depth"] = depth
def main(input_args):
- """Parse input and run the program"""
- short_opts = "hadD" # -d, --direct was old option for default action
- long_opts = ('help', 'all-packages', 'direct', 'indirect', 'depth=')
-
- try:
- module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
- except GetoptError as err:
- sys.stderr.write(pp.error("Module %s" % err))
- print()
- print_help(with_description=False)
- sys.exit(2)
-
- parse_module_options(module_opts)
-
- if not queries:
- print_help()
- sys.exit(2)
-
- #
- # Output
- #
-
- dep_print = DependPrinter(verbose=CONFIG['verbose'])
-
- first_run = True
- got_match = False
- for query in queries:
- if not first_run:
- print()
-
- pkg = Dependencies(query)
- if QUERY_OPTS['include_masked']:
- pkggetter = get_cpvs
- else:
- pkggetter = get_installed_cpvs
-
- if CONFIG['verbose']:
- print(" * These packages depend on %s:" % pp.emph(pkg.cpv))
- if pkg.graph_reverse_depends(
- pkgset=sorted(pkggetter(), key=CPV),
- max_depth=QUERY_OPTS["max_depth"],
- only_direct=QUERY_OPTS["only_direct"],
- printer_fn=dep_print
- ):
- got_match = True
-
- first_run = False
-
- if not got_match:
- sys.exit(1)
+ """Parse input and run the program"""
+ short_opts = "hadD" # -d, --direct was old option for default action
+ long_opts = ("help", "all-packages", "direct", "indirect", "depth=")
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Module %s" % err))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ #
+ # Output
+ #
+
+ dep_print = DependPrinter(verbose=CONFIG["verbose"])
+
+ first_run = True
+ got_match = False
+ for query in queries:
+ if not first_run:
+ print()
+
+ pkg = Dependencies(query)
+ if QUERY_OPTS["include_masked"]:
+ pkggetter = get_cpvs
+ else:
+ pkggetter = get_installed_cpvs
+
+ if CONFIG["verbose"]:
+ print(" * These packages depend on %s:" % pp.emph(pkg.cpv))
+ if pkg.graph_reverse_depends(
+ pkgset=sorted(pkggetter(), key=CPV),
+ max_depth=QUERY_OPTS["max_depth"],
+ only_direct=QUERY_OPTS["only_direct"],
+ printer_fn=dep_print,
+ ):
+ got_match = True
+
+ first_run = False
+
+ if not got_match:
+ sys.exit(1)
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/equery/depgraph.py b/pym/gentoolkit/equery/depgraph.py
index 4ee37ee..9003a47 100644
--- a/pym/gentoolkit/equery/depgraph.py
+++ b/pym/gentoolkit/equery/depgraph.py
@@ -4,7 +4,7 @@
"""Display a direct dependency graph for a given package"""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
# =======
# Imports
@@ -27,222 +27,229 @@ from gentoolkit.query import Query
# =======
QUERY_OPTS = {
- "depth": 1,
- "no_atom": False,
- "no_indent": False,
- "no_useflags": False,
- "no_mask": False,
- "in_installed": True,
- "in_porttree": True,
- "in_overlay": True,
- "include_masked": True,
- "show_progress": (not CONFIG['quiet'])
+ "depth": 1,
+ "no_atom": False,
+ "no_indent": False,
+ "no_useflags": False,
+ "no_mask": False,
+ "in_installed": True,
+ "in_porttree": True,
+ "in_overlay": True,
+ "include_masked": True,
+ "show_progress": (not CONFIG["quiet"]),
}
# =========
# Functions
# =========
+
def print_help(with_description=True):
- """Print description, usage and a detailed help message.
-
- @type with_description: bool
- @param with_description: if true, print module's __doc__ string
- """
-
- if with_description:
- print(__doc__.strip())
- print()
- print("Default depth is set to 1 (direct only). Use --depth=0 for no max.")
- print()
- print(mod_usage(mod_name="depgraph"))
- print()
- print(pp.command("options"))
- print(format_options((
- (" -h, --help", "display this help message"),
- (" -A, --no-atom", "do not show dependency atom"),
- (" -M, --no-mask", "do not show masking status"),
- (" -U, --no-useflags", "do not show USE flags"),
- (" -l, --linear", "do not format the graph by indenting dependencies"),
- (" --depth=N", "limit dependency graph to specified depth")
- )))
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print(__doc__.strip())
+ print()
+ print("Default depth is set to 1 (direct only). Use --depth=0 for no max.")
+ print()
+ print(mod_usage(mod_name="depgraph"))
+ print()
+ print(pp.command("options"))
+ print(
+ format_options(
+ (
+ (" -h, --help", "display this help message"),
+ (" -A, --no-atom", "do not show dependency atom"),
+ (" -M, --no-mask", "do not show masking status"),
+ (" -U, --no-useflags", "do not show USE flags"),
+ (" -l, --linear", "do not format the graph by indenting dependencies"),
+ (" --depth=N", "limit dependency graph to specified depth"),
+ )
+ )
+ )
def parse_module_options(module_opts):
- """Parse module options and update QUERY_OPTS"""
-
- opts = (x[0] for x in module_opts)
- posargs = (x[1] for x in module_opts)
- for opt, posarg in zip(opts, posargs):
- if opt in ('-h', '--help'):
- print_help()
- sys.exit(0)
- if opt in ('-A', '--no-atom'):
- QUERY_OPTS["no_atom"] = True
- if opt in ('-U', '--no-useflags'):
- QUERY_OPTS["no_useflags"] = True
- if opt in ('-M', '--no-mask'):
- QUERY_OPTS["no_mask"] = True
- if opt in ('-l', '--linear'):
- QUERY_OPTS["no_indent"] = True
- if opt in ('--depth'):
- if posarg.isdigit():
- depth = int(posarg)
- else:
- err = "Module option --depth requires integer (got '%s')"
- sys.stderr.write(pp.error(err % posarg))
- print()
- print_help(with_description=False)
- sys.exit(2)
- QUERY_OPTS["depth"] = depth
+ """Parse module options and update QUERY_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ("-h", "--help"):
+ print_help()
+ sys.exit(0)
+ if opt in ("-A", "--no-atom"):
+ QUERY_OPTS["no_atom"] = True
+ if opt in ("-U", "--no-useflags"):
+ QUERY_OPTS["no_useflags"] = True
+ if opt in ("-M", "--no-mask"):
+ QUERY_OPTS["no_mask"] = True
+ if opt in ("-l", "--linear"):
+ QUERY_OPTS["no_indent"] = True
+ if opt in ("--depth"):
+ if posarg.isdigit():
+ depth = int(posarg)
+ else:
+ err = "Module option --depth requires integer (got '%s')"
+ sys.stderr.write(pp.error(err % posarg))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
+ QUERY_OPTS["depth"] = depth
def depgraph_printer(
- depth,
- pkg,
- dep,
- no_use=False,
- no_atom=False,
- no_indent=False,
- initial_pkg=False,
- no_mask=False
+ depth,
+ pkg,
+ dep,
+ no_use=False,
+ no_atom=False,
+ no_indent=False,
+ initial_pkg=False,
+ no_mask=False,
):
- """Display L{gentoolkit.dependencies.Dependencies.graph_depends} results.
-
- @type depth: int
- @param depth: depth of indirection, used to calculate indent
- @type pkg: L{gentoolkit.package.Package}
- @param pkg: "best match" package matched by B{dep}
- @type dep: L{gentoolkit.atom.Atom}
- @param dep: dependency that matched B{pkg}
- @type no_use: bool
- @param no_use: don't output USE flags
- @type no_atom: bool
- @param no_atom: don't output dep atom
- @type no_indent: bool
- @param no_indent: don't output indent based on B{depth}
- @type initial_pkg: bool
- @param initial_pkg: somewhat of a hack used to print the root package of
- the graph with absolutely no indent
- """
- indent = '' if no_indent or initial_pkg else ' ' + (' ' * depth)
- decorator = '[%3d] ' % depth if no_indent else '`-- '
- use = ''
- atom = ''
- mask = ''
- try:
- if not no_atom:
- if dep.operator == '=*':
- atom += ' (=%s*)' % dep.cpv
- else:
- atom += ' (%s%s)' % (dep.operator, dep.cpv)
- if not no_use and dep is not None and dep.use:
- use = ' [%s]' % ' '.join(
- pp.useflag(x, enabled=True) for x in dep.use.tokens
- )
- except AttributeError:
- # 'NoneType' object has no attribute 'atom'
- pass
- if pkg and not no_mask:
- mask = pkg.mask_status()
- if not mask:
- mask = [determine_keyword(portage.settings["ARCH"],
- portage.settings["ACCEPT_KEYWORDS"],
- pkg.environment('KEYWORDS'))]
- mask = pp.masking(mask)
- try:
- pp.uprint(' '.join(
- (indent, decorator, pp.cpv(str(pkg.cpv)), atom, mask, use)
- ))
- except AttributeError:
- # 'NoneType' object has no attribute 'cpv'
- pp.uprint(''.join((indent, decorator, "(no match for %r)" % dep.atom)))
+ """Display L{gentoolkit.dependencies.Dependencies.graph_depends} results.
+
+ @type depth: int
+ @param depth: depth of indirection, used to calculate indent
+ @type pkg: L{gentoolkit.package.Package}
+ @param pkg: "best match" package matched by B{dep}
+ @type dep: L{gentoolkit.atom.Atom}
+ @param dep: dependency that matched B{pkg}
+ @type no_use: bool
+ @param no_use: don't output USE flags
+ @type no_atom: bool
+ @param no_atom: don't output dep atom
+ @type no_indent: bool
+ @param no_indent: don't output indent based on B{depth}
+ @type initial_pkg: bool
+ @param initial_pkg: somewhat of a hack used to print the root package of
+ the graph with absolutely no indent
+ """
+ indent = "" if no_indent or initial_pkg else " " + (" " * depth)
+ decorator = "[%3d] " % depth if no_indent else "`-- "
+ use = ""
+ atom = ""
+ mask = ""
+ try:
+ if not no_atom:
+ if dep.operator == "=*":
+ atom += " (=%s*)" % dep.cpv
+ else:
+ atom += " (%s%s)" % (dep.operator, dep.cpv)
+ if not no_use and dep is not None and dep.use:
+ use = " [%s]" % " ".join(
+ pp.useflag(x, enabled=True) for x in dep.use.tokens
+ )
+ except AttributeError:
+ # 'NoneType' object has no attribute 'atom'
+ pass
+ if pkg and not no_mask:
+ mask = pkg.mask_status()
+ if not mask:
+ mask = [
+ determine_keyword(
+ portage.settings["ARCH"],
+ portage.settings["ACCEPT_KEYWORDS"],
+ pkg.environment("KEYWORDS"),
+ )
+ ]
+ mask = pp.masking(mask)
+ try:
+ pp.uprint(" ".join((indent, decorator, pp.cpv(str(pkg.cpv)), atom, mask, use)))
+ except AttributeError:
+ # 'NoneType' object has no attribute 'cpv'
+ pp.uprint("".join((indent, decorator, "(no match for %r)" % dep.atom)))
def make_depgraph(pkg, printer_fn):
- """Create and display depgraph for each package."""
+ """Create and display depgraph for each package."""
- print()
- if CONFIG['verbose']:
- pp.uprint(" * " + pp.subsection("dependency graph for ") +
- pp.cpv(str(pkg.cpv)))
- else:
- pp.uprint("%s:" % pkg.cpv)
+ print()
+ if CONFIG["verbose"]:
+ pp.uprint(" * " + pp.subsection("dependency graph for ") + pp.cpv(str(pkg.cpv)))
+ else:
+ pp.uprint("%s:" % pkg.cpv)
- # Print out the first package
- printer_fn(0, pkg, None, initial_pkg=True)
+ # Print out the first package
+ printer_fn(0, pkg, None, initial_pkg=True)
- deps = pkg.deps.graph_depends(
- max_depth=QUERY_OPTS['depth'],
- printer_fn=printer_fn,
- # Use this to set this pkg as the graph's root; better way?
- result=[(0, pkg)]
- )
+ deps = pkg.deps.graph_depends(
+ max_depth=QUERY_OPTS["depth"],
+ printer_fn=printer_fn,
+ # Use this to set this pkg as the graph's root; better way?
+ result=[(0, pkg)],
+ )
- if CONFIG['verbose']:
- pkgname = pp.cpv(str(pkg.cpv))
- n_packages = pp.number(str(len(deps)))
- max_seen = pp.number(str(max(x[0] for x in deps)))
- info = "[ %s stats: packages (%s), max depth (%s) ]"
- pp.uprint(info % (pkgname, n_packages, max_seen))
+ if CONFIG["verbose"]:
+ pkgname = pp.cpv(str(pkg.cpv))
+ n_packages = pp.number(str(len(deps)))
+ max_seen = pp.number(str(max(x[0] for x in deps)))
+ info = "[ %s stats: packages (%s), max depth (%s) ]"
+ pp.uprint(info % (pkgname, n_packages, max_seen))
def main(input_args):
- """Parse input and run the program"""
-
- short_opts = "hAMUl"
- long_opts = ('help', 'no-atom', 'no-useflags', 'no-mask', 'depth=')
-
- try:
- module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
- except GetoptError as err:
- sys.stderr.write(pp.error("Module %s" % err))
- print()
- print_help(with_description=False)
- sys.exit(2)
-
- parse_module_options(module_opts)
-
- if not queries:
- print_help()
- sys.exit(2)
-
- #
- # Output
- #
-
- first_run = True
- for query in (Query(x) for x in queries):
- if not first_run:
- print()
-
- matches = query.smart_find(**QUERY_OPTS)
-
- if not matches:
- raise errors.GentoolkitNoMatches(query)
-
- matches.sort()
-
- if CONFIG['verbose']:
- printer = partial(
- depgraph_printer,
- no_atom=QUERY_OPTS['no_atom'],
- no_indent=QUERY_OPTS['no_indent'],
- no_use=QUERY_OPTS['no_useflags'],
- no_mask=QUERY_OPTS['no_mask']
- )
- else:
- printer = partial(
- depgraph_printer,
- no_atom=True,
- no_indent=True,
- no_use=True,
- no_mask=True
- )
-
- for pkg in matches:
- make_depgraph(pkg, printer)
-
- first_run = False
+ """Parse input and run the program"""
+
+ short_opts = "hAMUl"
+ long_opts = ("help", "no-atom", "no-useflags", "no-mask", "depth=")
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Module %s" % err))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ #
+ # Output
+ #
+
+ first_run = True
+ for query in (Query(x) for x in queries):
+ if not first_run:
+ print()
+
+ matches = query.smart_find(**QUERY_OPTS)
+
+ if not matches:
+ raise errors.GentoolkitNoMatches(query)
+
+ matches.sort()
+
+ if CONFIG["verbose"]:
+ printer = partial(
+ depgraph_printer,
+ no_atom=QUERY_OPTS["no_atom"],
+ no_indent=QUERY_OPTS["no_indent"],
+ no_use=QUERY_OPTS["no_useflags"],
+ no_mask=QUERY_OPTS["no_mask"],
+ )
+ else:
+ printer = partial(
+ depgraph_printer,
+ no_atom=True,
+ no_indent=True,
+ no_use=True,
+ no_mask=True,
+ )
+
+ for pkg in matches:
+ make_depgraph(pkg, printer)
+
+ first_run = False
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/equery/files.py b/pym/gentoolkit/equery/files.py
index cfcd306..ae9e386 100644
--- a/pym/gentoolkit/equery/files.py
+++ b/pym/gentoolkit/equery/files.py
@@ -4,7 +4,7 @@
"""List files owned by a given package."""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
# =======
# Imports
@@ -17,8 +17,7 @@ from getopt import gnu_getopt, GetoptError
import portage
import gentoolkit.pprinter as pp
-from gentoolkit.equery import (format_filetype, format_options, mod_usage,
- CONFIG)
+from gentoolkit.equery import format_filetype, format_options, mod_usage, CONFIG
from gentoolkit.query import Query
# =======
@@ -26,303 +25,314 @@ from gentoolkit.query import Query
# =======
QUERY_OPTS = {
- "in_installed": True,
- "in_porttree": False,
- "in_overlay": False,
- "include_masked": True,
- "output_tree": False,
- "show_progress": (not CONFIG['quiet']),
- "show_type": False,
- "show_timestamp": False,
- "show_MD5": False,
- "type_filter": None
+ "in_installed": True,
+ "in_porttree": False,
+ "in_overlay": False,
+ "include_masked": True,
+ "output_tree": False,
+ "show_progress": (not CONFIG["quiet"]),
+ "show_type": False,
+ "show_timestamp": False,
+ "show_MD5": False,
+ "type_filter": None,
}
FILTER_RULES = (
- 'dir', 'obj', 'sym', 'dev', 'path', 'conf', 'cmd', 'doc', 'man', 'info',
- 'fifo'
+ "dir",
+ "obj",
+ "sym",
+ "dev",
+ "path",
+ "conf",
+ "cmd",
+ "doc",
+ "man",
+ "info",
+ "fifo",
)
# =========
# Functions
# =========
+
def print_help(with_description=True):
- """Print description, usage and a detailed help message.
-
- @type with_description: bool
- @param with_description: if true, print module's __doc__ string
- """
-
- if with_description:
- print(__doc__.strip())
- print()
- print(mod_usage(mod_name="files"))
- print()
- print(pp.command("options"))
- print(format_options((
- (" -h, --help", "display this help message"),
- (" -m, --md5sum", "include MD5 sum in output"),
- (" -s, --timestamp", "include timestamp in output"),
- (" -t, --type", "include file type in output"),
- (" --tree", "display results in a tree (turns off other options)"),
- (" -f, --filter=RULES", "filter output by file type"),
- (" RULES",
- "a comma-separated list (no spaces); choose from:")
- )))
- print(" " * 24, ', '.join(pp.emph(x) for x in FILTER_RULES))
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print(__doc__.strip())
+ print()
+ print(mod_usage(mod_name="files"))
+ print()
+ print(pp.command("options"))
+ print(
+ format_options(
+ (
+ (" -h, --help", "display this help message"),
+ (" -m, --md5sum", "include MD5 sum in output"),
+ (" -s, --timestamp", "include timestamp in output"),
+ (" -t, --type", "include file type in output"),
+ (" --tree", "display results in a tree (turns off other options)"),
+ (" -f, --filter=RULES", "filter output by file type"),
+ (
+ " RULES",
+ "a comma-separated list (no spaces); choose from:",
+ ),
+ )
+ )
+ )
+ print(" " * 24, ", ".join(pp.emph(x) for x in FILTER_RULES))
def display_files(contents):
- """Display the content of an installed package.
-
- @see: gentoolkit.package.Package.parsed_contents
- @type contents: dict
- @param contents: {'path': ['filetype', ...], ...}
- """
-
- filenames = list(contents.keys())
- filenames.sort()
- last = []
-
- for name in filenames:
- if QUERY_OPTS["output_tree"]:
- dirdepth = name.count('/')
- indent = " "
- if dirdepth == 2:
- indent = " "
- elif dirdepth > 2:
- indent = " " * (dirdepth - 1)
-
- basename = name.rsplit("/", dirdepth - 1)
- if contents[name][0] == "dir":
- if len(last) == 0:
- last = basename
- pp.uprint(pp.path(indent + basename[0]))
- continue
- for i, directory in enumerate(basename):
- try:
- if directory in last[i]:
- continue
- except IndexError:
- pass
- last = basename
- if len(last) == 1:
- pp.uprint(pp.path(indent + last[0]))
- continue
- pp.uprint(pp.path(indent + "> /" + last[-1]))
- elif contents[name][0] == "sym":
- pp.uprint(pp.path(indent + "+"), end=' ')
- pp.uprint(pp.path_symlink(basename[-1] + " -> " +
- contents[name][2]))
- else:
- pp.uprint(pp.path(indent + "+ ") + basename[-1])
- else:
- pp.uprint(format_filetype(
- name,
- contents[name],
- show_type=QUERY_OPTS["show_type"],
- show_md5=QUERY_OPTS["show_MD5"],
- show_timestamp=QUERY_OPTS["show_timestamp"]
- ))
+ """Display the content of an installed package.
+
+ @see: gentoolkit.package.Package.parsed_contents
+ @type contents: dict
+ @param contents: {'path': ['filetype', ...], ...}
+ """
+
+ filenames = list(contents.keys())
+ filenames.sort()
+ last = []
+
+ for name in filenames:
+ if QUERY_OPTS["output_tree"]:
+ dirdepth = name.count("/")
+ indent = " "
+ if dirdepth == 2:
+ indent = " "
+ elif dirdepth > 2:
+ indent = " " * (dirdepth - 1)
+
+ basename = name.rsplit("/", dirdepth - 1)
+ if contents[name][0] == "dir":
+ if len(last) == 0:
+ last = basename
+ pp.uprint(pp.path(indent + basename[0]))
+ continue
+ for i, directory in enumerate(basename):
+ try:
+ if directory in last[i]:
+ continue
+ except IndexError:
+ pass
+ last = basename
+ if len(last) == 1:
+ pp.uprint(pp.path(indent + last[0]))
+ continue
+ pp.uprint(pp.path(indent + "> /" + last[-1]))
+ elif contents[name][0] == "sym":
+ pp.uprint(pp.path(indent + "+"), end=" ")
+ pp.uprint(pp.path_symlink(basename[-1] + " -> " + contents[name][2]))
+ else:
+ pp.uprint(pp.path(indent + "+ ") + basename[-1])
+ else:
+ pp.uprint(
+ format_filetype(
+ name,
+ contents[name],
+ show_type=QUERY_OPTS["show_type"],
+ show_md5=QUERY_OPTS["show_MD5"],
+ show_timestamp=QUERY_OPTS["show_timestamp"],
+ )
+ )
def filter_by_doc(contents, content_filter):
- """Return a copy of content filtered by documentation."""
+ """Return a copy of content filtered by documentation."""
- filtered_content = {}
- for doctype in ('doc' ,'man' ,'info'):
- # List only files from /usr/share/{doc,man,info}
- if doctype in content_filter:
- docpath = os.path.join(os.sep, 'usr', 'share', doctype)
- for path in contents:
- if contents[path][0] == 'obj' and path.startswith(docpath):
- filtered_content[path] = contents[path]
+ filtered_content = {}
+ for doctype in ("doc", "man", "info"):
+ # List only files from /usr/share/{doc,man,info}
+ if doctype in content_filter:
+ docpath = os.path.join(os.sep, "usr", "share", doctype)
+ for path in contents:
+ if contents[path][0] == "obj" and path.startswith(docpath):
+ filtered_content[path] = contents[path]
- return filtered_content
+ return filtered_content
def filter_by_command(contents):
- """Return a copy of content filtered by executable commands."""
+ """Return a copy of content filtered by executable commands."""
- filtered_content = {}
- userpath = os.environ["PATH"].split(os.pathsep)
- userpath = [os.path.normpath(x) for x in userpath]
- for path in contents:
- if (contents[path][0] in ['obj', 'sym'] and
- os.path.dirname(path) in userpath):
- filtered_content[path] = contents[path]
+ filtered_content = {}
+ userpath = os.environ["PATH"].split(os.pathsep)
+ userpath = [os.path.normpath(x) for x in userpath]
+ for path in contents:
+ if contents[path][0] in ["obj", "sym"] and os.path.dirname(path) in userpath:
+ filtered_content[path] = contents[path]
- return filtered_content
+ return filtered_content
def filter_by_path(contents):
- """Return a copy of content filtered by file paths."""
-
- filtered_content = {}
- paths = list(reversed(sorted(contents.keys())))
- while paths:
- basepath = paths.pop()
- if contents[basepath][0] == 'dir':
- check_subdirs = False
- for path in paths:
- if (contents[path][0] != "dir" and
- os.path.dirname(path) == basepath):
- filtered_content[basepath] = contents[basepath]
- check_subdirs = True
- break
- if check_subdirs:
- while (paths and paths[-1].startswith(basepath)):
- paths.pop()
-
- return filtered_content
+ """Return a copy of content filtered by file paths."""
+
+ filtered_content = {}
+ paths = list(reversed(sorted(contents.keys())))
+ while paths:
+ basepath = paths.pop()
+ if contents[basepath][0] == "dir":
+ check_subdirs = False
+ for path in paths:
+ if contents[path][0] != "dir" and os.path.dirname(path) == basepath:
+ filtered_content[basepath] = contents[basepath]
+ check_subdirs = True
+ break
+ if check_subdirs:
+ while paths and paths[-1].startswith(basepath):
+ paths.pop()
+
+ return filtered_content
def filter_by_conf(contents):
- """Return a copy of content filtered by configuration files."""
+ """Return a copy of content filtered by configuration files."""
- filtered_content = {}
- conf_path = portage.settings["CONFIG_PROTECT"].split()
- conf_path = tuple(os.path.normpath(x) for x in conf_path)
- conf_mask_path = portage.settings["CONFIG_PROTECT_MASK"].split()
- conf_mask_path = tuple(os.path.normpath(x) for x in conf_mask_path)
- for path in contents:
- if contents[path][0] == 'obj' and path.startswith(conf_path):
- if not path.startswith(conf_mask_path):
- filtered_content[path] = contents[path]
+ filtered_content = {}
+ conf_path = portage.settings["CONFIG_PROTECT"].split()
+ conf_path = tuple(os.path.normpath(x) for x in conf_path)
+ conf_mask_path = portage.settings["CONFIG_PROTECT_MASK"].split()
+ conf_mask_path = tuple(os.path.normpath(x) for x in conf_mask_path)
+ for path in contents:
+ if contents[path][0] == "obj" and path.startswith(conf_path):
+ if not path.startswith(conf_mask_path):
+ filtered_content[path] = contents[path]
- return filtered_content
+ return filtered_content
def filter_by_fifo(contents):
- """Return a copy of content filtered by fifo entries."""
+ """Return a copy of content filtered by fifo entries."""
- filtered_content = {}
- for path in contents:
- if contents[path][0] in ['fif']:
- filtered_content[path] = contents[path]
+ filtered_content = {}
+ for path in contents:
+ if contents[path][0] in ["fif"]:
+ filtered_content[path] = contents[path]
- return filtered_content
+ return filtered_content
def filter_contents(contents):
- """Filter files by type if specified by the user.
-
- @see: gentoolkit.package.Package.parsed_contents
- @type contents: dict
- @param contents: {'path': ['filetype', ...], ...}
- @rtype: dict
- @return: contents with unrequested filetypes stripped
- """
-
- if QUERY_OPTS['type_filter']:
- content_filter = QUERY_OPTS['type_filter']
- else:
- return contents
-
- filtered_content = {}
- if frozenset(('dir', 'obj', 'sym', 'dev')).intersection(content_filter):
- # Filter elements by type (as recorded in CONTENTS)
- for path in contents:
- if contents[path][0] in content_filter:
- filtered_content[path] = contents[path]
- if "cmd" in content_filter:
- filtered_content.update(filter_by_command(contents))
- if "path" in content_filter:
- filtered_content.update(filter_by_path(contents))
- if "conf" in content_filter:
- filtered_content.update(filter_by_conf(contents))
- if frozenset(('doc' ,'man' ,'info')).intersection(content_filter):
- filtered_content.update(filter_by_doc(contents, content_filter))
- if "fifo" in content_filter:
- filtered_content.update(filter_by_fifo(contents))
-
- return filtered_content
+ """Filter files by type if specified by the user.
+
+ @see: gentoolkit.package.Package.parsed_contents
+ @type contents: dict
+ @param contents: {'path': ['filetype', ...], ...}
+ @rtype: dict
+ @return: contents with unrequested filetypes stripped
+ """
+
+ if QUERY_OPTS["type_filter"]:
+ content_filter = QUERY_OPTS["type_filter"]
+ else:
+ return contents
+
+ filtered_content = {}
+ if frozenset(("dir", "obj", "sym", "dev")).intersection(content_filter):
+ # Filter elements by type (as recorded in CONTENTS)
+ for path in contents:
+ if contents[path][0] in content_filter:
+ filtered_content[path] = contents[path]
+ if "cmd" in content_filter:
+ filtered_content.update(filter_by_command(contents))
+ if "path" in content_filter:
+ filtered_content.update(filter_by_path(contents))
+ if "conf" in content_filter:
+ filtered_content.update(filter_by_conf(contents))
+ if frozenset(("doc", "man", "info")).intersection(content_filter):
+ filtered_content.update(filter_by_doc(contents, content_filter))
+ if "fifo" in content_filter:
+ filtered_content.update(filter_by_fifo(contents))
+
+ return filtered_content
def parse_module_options(module_opts):
- """Parse module options and update QUERY_OPTS"""
-
- content_filter = []
- opts = (x[0] for x in module_opts)
- posargs = (x[1] for x in module_opts)
- for opt, posarg in zip(opts, posargs):
- if opt in ('-h', '--help'):
- print_help()
- sys.exit(0)
- elif opt in ('-m', '--md5sum'):
- QUERY_OPTS["show_MD5"] = True
- elif opt in ('-s', '--timestamp'):
- QUERY_OPTS["show_timestamp"] = True
- elif opt in ('-t', '--type'):
- QUERY_OPTS["show_type"] = True
- elif opt in ('--tree'):
- QUERY_OPTS["output_tree"] = True
- elif opt in ('-f', '--filter'):
- f_split = posarg.split(',')
- content_filter.extend(x.lstrip('=') for x in f_split)
- for rule in content_filter:
- if not rule in FILTER_RULES:
- sys.stderr.write(
- pp.error("Invalid filter rule '%s'" % rule)
- )
- print()
- print_help(with_description=False)
- sys.exit(2)
- QUERY_OPTS["type_filter"] = content_filter
+ """Parse module options and update QUERY_OPTS"""
+
+ content_filter = []
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ("-h", "--help"):
+ print_help()
+ sys.exit(0)
+ elif opt in ("-m", "--md5sum"):
+ QUERY_OPTS["show_MD5"] = True
+ elif opt in ("-s", "--timestamp"):
+ QUERY_OPTS["show_timestamp"] = True
+ elif opt in ("-t", "--type"):
+ QUERY_OPTS["show_type"] = True
+ elif opt in ("--tree"):
+ QUERY_OPTS["output_tree"] = True
+ elif opt in ("-f", "--filter"):
+ f_split = posarg.split(",")
+ content_filter.extend(x.lstrip("=") for x in f_split)
+ for rule in content_filter:
+ if not rule in FILTER_RULES:
+ sys.stderr.write(pp.error("Invalid filter rule '%s'" % rule))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
+ QUERY_OPTS["type_filter"] = content_filter
def main(input_args):
- """Parse input and run the program"""
+ """Parse input and run the program"""
+
+ # -e, --exact-name is legacy option. djanderson '09
+ short_opts = "hemstf:"
+ long_opts = ("help", "exact-name", "md5sum", "timestamp", "type", "tree", "filter=")
- # -e, --exact-name is legacy option. djanderson '09
- short_opts = "hemstf:"
- long_opts = ('help', 'exact-name', 'md5sum', 'timestamp', 'type', 'tree',
- 'filter=')
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Module %s" % err))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
- try:
- module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
- except GetoptError as err:
- sys.stderr.write(pp.error("Module %s" % err))
- print()
- print_help(with_description=False)
- sys.exit(2)
+ parse_module_options(module_opts)
- parse_module_options(module_opts)
+ if not queries:
+ print_help()
+ sys.exit(2)
- if not queries:
- print_help()
- sys.exit(2)
+ # Turn off filtering for tree output
+ if QUERY_OPTS["output_tree"]:
+ QUERY_OPTS["type_filter"] = None
- # Turn off filtering for tree output
- if QUERY_OPTS["output_tree"]:
- QUERY_OPTS["type_filter"] = None
+ #
+ # Output files
+ #
- #
- # Output files
- #
+ first_run = True
+ for query in queries:
+ if not first_run:
+ print()
- first_run = True
- for query in queries:
- if not first_run:
- print()
+ matches = Query(query).smart_find(**QUERY_OPTS)
- matches = Query(query).smart_find(**QUERY_OPTS)
+ if not matches:
+ sys.stderr.write(pp.error("No matching packages found for %s" % query))
- if not matches:
- sys.stderr.write(
- pp.error("No matching packages found for %s" % query)
- )
+ matches.sort()
- matches.sort()
+ for pkg in matches:
+ if CONFIG["verbose"]:
+ pp.uprint(" * Contents of %s:" % pp.cpv(str(pkg.cpv)))
- for pkg in matches:
- if CONFIG['verbose']:
- pp.uprint(" * Contents of %s:" % pp.cpv(str(pkg.cpv)))
+ contents = pkg.parsed_contents()
+ display_files(filter_contents(contents))
- contents = pkg.parsed_contents()
- display_files(filter_contents(contents))
+ first_run = False
- first_run = False
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/equery/has.py b/pym/gentoolkit/equery/has.py
index c1c8bba..bc98097 100644
--- a/pym/gentoolkit/equery/has.py
+++ b/pym/gentoolkit/equery/has.py
@@ -4,7 +4,7 @@
"""List all installed packages that match for a given ENVIRONMENT variable"""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
# =======
# Imports
@@ -24,184 +24,194 @@ from gentoolkit.query import Query
# =======
QUERY_OPTS = {
- "in_installed": True,
- "in_porttree": False,
- "in_overlay": False,
- "include_masked": True,
- "show_progress": False,
- "package_format": None,
- "package_filter": None,
- "env_var": None
+ "in_installed": True,
+ "in_porttree": False,
+ "in_overlay": False,
+ "include_masked": True,
+ "show_progress": False,
+ "package_format": None,
+ "package_filter": None,
+ "env_var": None,
}
# =========
# Functions
# =========
+
def print_help(with_description=True):
- """Print description, usage and a detailed help message.
-
- @type with_description: bool
- @param with_description: if true, print module's __doc__ string
- """
-
- if with_description:
- print(__doc__.strip())
- print()
- print(mod_usage(mod_name="has", arg="env_var [expr]"))
- print()
- print(pp.command("options"))
- print(format_options((
- (" -h, --help", "display this help message"),
- (" -I, --exclude-installed",
- "exclude installed packages from search path"),
- (" -o, --overlay-tree", "include overlays in search path"),
- (" -p, --portage-tree", "include entire portage tree in search path"),
- (" -F, --format=TMPL", "specify a custom output format"),
- (" TMPL",
- "a format template using (see man page):")
- )))
-# print(" " * 24, ', '.join(pp.emph(x) for x in FORMAT_TMPL_VARS))
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print(__doc__.strip())
+ print()
+ print(mod_usage(mod_name="has", arg="env_var [expr]"))
+ print()
+ print(pp.command("options"))
+ print(
+ format_options(
+ (
+ (" -h, --help", "display this help message"),
+ (
+ " -I, --exclude-installed",
+ "exclude installed packages from search path",
+ ),
+ (" -o, --overlay-tree", "include overlays in search path"),
+ (" -p, --portage-tree", "include entire portage tree in search path"),
+ (" -F, --format=TMPL", "specify a custom output format"),
+ (" TMPL", "a format template using (see man page):"),
+ )
+ )
+ )
+
+
+# print(" " * 24, ', '.join(pp.emph(x) for x in FORMAT_TMPL_VARS))
def query_in_env(query, env_var, pkg):
- """Check if the query is in the pkg's environment."""
+ """Check if the query is in the pkg's environment."""
- try:
- if env_var in ("USE", "IUSE", "CFLAGS", "CXXFLAGS", "LDFLAGS"):
- results = set(
- [x.lstrip("+-") for x in pkg.environment(env_var).split()]
- )
- else:
- results = set(pkg.environment(env_var).split())
- except errors.GentoolkitFatalError:
- # aux_get KeyError or other unexpected result
- return False
+ try:
+ if env_var in ("USE", "IUSE", "CFLAGS", "CXXFLAGS", "LDFLAGS"):
+ results = set([x.lstrip("+-") for x in pkg.environment(env_var).split()])
+ else:
+ results = set(pkg.environment(env_var).split())
+ except errors.GentoolkitFatalError:
+ # aux_get KeyError or other unexpected result
+ return False
- if query in results:
- return True
+ if query in results:
+ return True
- return False
+ return False
def display_pkg(query, env_var, pkg):
- """Display information for a given package."""
-
- if CONFIG['verbose']:
- pkgstr = PackageFormatter(
- pkg,
- do_format=True,
- custom_format=QUERY_OPTS["package_format"]
- )
- else:
- pkgstr = PackageFormatter(
- pkg,
- do_format=False,
- custom_format=QUERY_OPTS["package_format"]
- )
-
- if (QUERY_OPTS["in_installed"] and
- not QUERY_OPTS["in_porttree"] and
- not QUERY_OPTS["in_overlay"]):
- if not 'I' in pkgstr.location:
- return False
- if (QUERY_OPTS["in_porttree"] and
- not QUERY_OPTS["in_overlay"]):
- if not 'P' in pkgstr.location:
- return False
- if (QUERY_OPTS["in_overlay"] and
- not QUERY_OPTS["in_porttree"]):
- if not 'O' in pkgstr.location:
- return False
- pp.uprint(pkgstr)
-
- return True
+ """Display information for a given package."""
+
+ if CONFIG["verbose"]:
+ pkgstr = PackageFormatter(
+ pkg, do_format=True, custom_format=QUERY_OPTS["package_format"]
+ )
+ else:
+ pkgstr = PackageFormatter(
+ pkg, do_format=False, custom_format=QUERY_OPTS["package_format"]
+ )
+
+ if (
+ QUERY_OPTS["in_installed"]
+ and not QUERY_OPTS["in_porttree"]
+ and not QUERY_OPTS["in_overlay"]
+ ):
+ if not "I" in pkgstr.location:
+ return False
+ if QUERY_OPTS["in_porttree"] and not QUERY_OPTS["in_overlay"]:
+ if not "P" in pkgstr.location:
+ return False
+ if QUERY_OPTS["in_overlay"] and not QUERY_OPTS["in_porttree"]:
+ if not "O" in pkgstr.location:
+ return False
+ pp.uprint(pkgstr)
+
+ return True
def parse_module_options(module_opts):
- """Parse module options and update QUERY_OPTS"""
-
- # Parse module options
- opts = (x[0] for x in module_opts)
- posargs = (x[1] for x in module_opts)
- for opt, posarg in zip(opts, posargs):
- if opt in ('-h', '--help'):
- print_help()
- sys.exit(0)
- elif opt in ('-I', '--exclue-installed'):
- QUERY_OPTS['in_installed'] = False
- elif opt in ('-p', '--portage-tree'):
- QUERY_OPTS['in_porttree'] = True
- elif opt in ('-o', '--overlay-tree'):
- QUERY_OPTS['in_overlay'] = True
- elif opt in ('-F', '--format'):
- QUERY_OPTS["package_format"] = posarg
- elif opt in ('--package'):
- QUERY_OPTS["package_filter"] = posarg
+ """Parse module options and update QUERY_OPTS"""
+
+ # Parse module options
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ("-h", "--help"):
+ print_help()
+ sys.exit(0)
+ elif opt in ("-I", "--exclue-installed"):
+ QUERY_OPTS["in_installed"] = False
+ elif opt in ("-p", "--portage-tree"):
+ QUERY_OPTS["in_porttree"] = True
+ elif opt in ("-o", "--overlay-tree"):
+ QUERY_OPTS["in_overlay"] = True
+ elif opt in ("-F", "--format"):
+ QUERY_OPTS["package_format"] = posarg
+ elif opt in ("--package"):
+ QUERY_OPTS["package_filter"] = posarg
def main(input_args):
- """Parse input and run the program"""
-
- short_opts = "hiIpoF:" # -i was option for default action
- # --installed is no longer needed, kept for compatibility (djanderson '09)
- long_opts = ('help', 'installed', 'exclude-installed', 'portage-tree',
- 'overlay-tree', 'format=', 'package=')
-
- try:
- module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
- except GetoptError as err:
- sys.stderr.write(pp.error("Module %s" % err))
- print()
- print_help(with_description=False)
- sys.exit(2)
-
- parse_module_options(module_opts)
-
- if not queries:
- print_help()
- sys.exit(2)
-
- query_scope = QUERY_OPTS['package_filter'] or '*'
- matches = Query(query_scope).smart_find(**QUERY_OPTS)
- matches.sort()
-
- # split out the first query since it is suppose to be the env_var
- QUERY_OPTS['env_var'] = queries.pop(0)
- env_var = QUERY_OPTS['env_var']
-
- #
- # Output
- #
-
- if not queries:
- if not QUERY_OPTS['package_filter']:
- err = "Used ENV_VAR without match_expression or --package"
- raise errors.GentoolkitFatalError(err, is_serious=False)
- else:
- if len(matches) > 1:
- raise errors.AmbiguousPackageName(matches)
- for match in matches:
- env = QUERY_OPTS['env_var']
- print(match.environment(env))
-
- first_run = True
- got_match = False
- for query in queries:
- if not first_run:
- print()
-
- if CONFIG['verbose']:
- status = " * Searching for {0} {1} ... "
- pp.uprint(status.format(env_var, pp.emph(query)))
-
- for pkg in matches:
- if query_in_env(query, env_var, pkg):
- display_pkg(query, env_var, pkg)
- got_match = True
- first_run = False
-
- if not got_match:
- sys.exit(1)
+ """Parse input and run the program"""
+
+ short_opts = "hiIpoF:" # -i was option for default action
+ # --installed is no longer needed, kept for compatibility (djanderson '09)
+ long_opts = (
+ "help",
+ "installed",
+ "exclude-installed",
+ "portage-tree",
+ "overlay-tree",
+ "format=",
+ "package=",
+ )
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Module %s" % err))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ query_scope = QUERY_OPTS["package_filter"] or "*"
+ matches = Query(query_scope).smart_find(**QUERY_OPTS)
+ matches.sort()
+
+ # split out the first query since it is suppose to be the env_var
+ QUERY_OPTS["env_var"] = queries.pop(0)
+ env_var = QUERY_OPTS["env_var"]
+
+ #
+ # Output
+ #
+
+ if not queries:
+ if not QUERY_OPTS["package_filter"]:
+ err = "Used ENV_VAR without match_expression or --package"
+ raise errors.GentoolkitFatalError(err, is_serious=False)
+ else:
+ if len(matches) > 1:
+ raise errors.AmbiguousPackageName(matches)
+ for match in matches:
+ env = QUERY_OPTS["env_var"]
+ print(match.environment(env))
+
+ first_run = True
+ got_match = False
+ for query in queries:
+ if not first_run:
+ print()
+
+ if CONFIG["verbose"]:
+ status = " * Searching for {0} {1} ... "
+ pp.uprint(status.format(env_var, pp.emph(query)))
+
+ for pkg in matches:
+ if query_in_env(query, env_var, pkg):
+ display_pkg(query, env_var, pkg)
+ got_match = True
+ first_run = False
+
+ if not got_match:
+ sys.exit(1)
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/equery/hasuse.py b/pym/gentoolkit/equery/hasuse.py
index 07207bc..13fbb24 100644
--- a/pym/gentoolkit/equery/hasuse.py
+++ b/pym/gentoolkit/equery/hasuse.py
@@ -4,7 +4,7 @@
"""List all installed packages that have a given USE flag"""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
# =======
# Imports
@@ -24,153 +24,161 @@ from gentoolkit.query import Query
# =======
QUERY_OPTS = {
- "in_installed": True,
- "in_porttree": False,
- "in_overlay": False,
- "include_masked": True,
- "show_progress": False,
- "package_format": None
+ "in_installed": True,
+ "in_porttree": False,
+ "in_overlay": False,
+ "include_masked": True,
+ "show_progress": False,
+ "package_format": None,
}
# =========
# Functions
# =========
+
def print_help(with_description=True):
- """Print description, usage and a detailed help message.
-
- @type with_description: bool
- @param with_description: if true, print module's __doc__ string
- """
-
- if with_description:
- print(__doc__.strip())
- print()
- print(mod_usage(mod_name="hasuse", arg="USE-flag"))
- print()
- print(pp.command("options"))
- print(format_options((
- (" -h, --help", "display this help message"),
- (" -I, --exclude-installed",
- "exclude installed packages from search path"),
- (" -o, --overlay-tree", "include overlays in search path"),
- (" -p, --portage-tree", "include entire portage tree in search path"),
- (" -F, --format=TMPL", "specify a custom output format"),
- (" TMPL",
- "a format template using (see man page):")
- )))
- print(" " * 24, ', '.join(pp.emph(x) for x in FORMAT_TMPL_VARS))
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print(__doc__.strip())
+ print()
+ print(mod_usage(mod_name="hasuse", arg="USE-flag"))
+ print()
+ print(pp.command("options"))
+ print(
+ format_options(
+ (
+ (" -h, --help", "display this help message"),
+ (
+ " -I, --exclude-installed",
+ "exclude installed packages from search path",
+ ),
+ (" -o, --overlay-tree", "include overlays in search path"),
+ (" -p, --portage-tree", "include entire portage tree in search path"),
+ (" -F, --format=TMPL", "specify a custom output format"),
+ (" TMPL", "a format template using (see man page):"),
+ )
+ )
+ )
+ print(" " * 24, ", ".join(pp.emph(x) for x in FORMAT_TMPL_VARS))
def display_useflags(query, pkg):
- """Display USE flag information for a given package."""
-
- try:
- useflags = [x.lstrip("+-") for x in pkg.environment("IUSE").split()]
- except errors.GentoolkitFatalError:
- # aux_get KeyError or other unexpected result
- return False
-
- if query not in useflags:
- return False
-
- if CONFIG['verbose']:
- pkgstr = PackageFormatter(
- pkg,
- do_format=True,
- custom_format=QUERY_OPTS["package_format"]
- )
- else:
- pkgstr = PackageFormatter(
- pkg,
- do_format=False,
- custom_format=QUERY_OPTS["package_format"]
- )
-
- if (QUERY_OPTS["in_installed"] and
- not QUERY_OPTS["in_porttree"] and
- not QUERY_OPTS["in_overlay"]):
- if not 'I' in pkgstr.location:
- return False
- if (QUERY_OPTS["in_porttree"] and
- not QUERY_OPTS["in_overlay"]):
- if not 'P' in pkgstr.location:
- return False
- if (QUERY_OPTS["in_overlay"] and
- not QUERY_OPTS["in_porttree"]):
- if not 'O' in pkgstr.location:
- return False
- pp.uprint(pkgstr)
-
- return True
-
+ """Display USE flag information for a given package."""
+
+ try:
+ useflags = [x.lstrip("+-") for x in pkg.environment("IUSE").split()]
+ except errors.GentoolkitFatalError:
+ # aux_get KeyError or other unexpected result
+ return False
+
+ if query not in useflags:
+ return False
+
+ if CONFIG["verbose"]:
+ pkgstr = PackageFormatter(
+ pkg, do_format=True, custom_format=QUERY_OPTS["package_format"]
+ )
+ else:
+ pkgstr = PackageFormatter(
+ pkg, do_format=False, custom_format=QUERY_OPTS["package_format"]
+ )
+
+ if (
+ QUERY_OPTS["in_installed"]
+ and not QUERY_OPTS["in_porttree"]
+ and not QUERY_OPTS["in_overlay"]
+ ):
+ if not "I" in pkgstr.location:
+ return False
+ if QUERY_OPTS["in_porttree"] and not QUERY_OPTS["in_overlay"]:
+ if not "P" in pkgstr.location:
+ return False
+ if QUERY_OPTS["in_overlay"] and not QUERY_OPTS["in_porttree"]:
+ if not "O" in pkgstr.location:
+ return False
+ pp.uprint(pkgstr)
+
+ return True
def parse_module_options(module_opts):
- """Parse module options and update QUERY_OPTS"""
-
- # Parse module options
- opts = (x[0] for x in module_opts)
- posargs = (x[1] for x in module_opts)
- for opt, posarg in zip(opts, posargs):
- if opt in ('-h', '--help'):
- print_help()
- sys.exit(0)
- elif opt in ('-I', '--exclue-installed'):
- QUERY_OPTS['in_installed'] = False
- elif opt in ('-p', '--portage-tree'):
- QUERY_OPTS['in_porttree'] = True
- elif opt in ('-o', '--overlay-tree'):
- QUERY_OPTS['in_overlay'] = True
- elif opt in ('-F', '--format'):
- QUERY_OPTS["package_format"] = posarg
+ """Parse module options and update QUERY_OPTS"""
+
+ # Parse module options
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ("-h", "--help"):
+ print_help()
+ sys.exit(0)
+ elif opt in ("-I", "--exclue-installed"):
+ QUERY_OPTS["in_installed"] = False
+ elif opt in ("-p", "--portage-tree"):
+ QUERY_OPTS["in_porttree"] = True
+ elif opt in ("-o", "--overlay-tree"):
+ QUERY_OPTS["in_overlay"] = True
+ elif opt in ("-F", "--format"):
+ QUERY_OPTS["package_format"] = posarg
def main(input_args):
- """Parse input and run the program"""
-
- short_opts = "hiIpoF:" # -i was option for default action
- # --installed is no longer needed, kept for compatibility (djanderson '09)
- long_opts = ('help', 'installed', 'exclude-installed', 'portage-tree',
- 'overlay-tree', 'format=')
-
- try:
- module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
- except GetoptError as err:
- sys.stderr.write(pp.error("Module %s" % err))
- print()
- print_help(with_description=False)
- sys.exit(2)
-
- parse_module_options(module_opts)
-
- if not queries:
- print_help()
- sys.exit(2)
-
- matches = Query("*").smart_find(**QUERY_OPTS)
- matches.sort()
-
- #
- # Output
- #
-
- first_run = True
- got_match = False
- for query in queries:
- if not first_run:
- print()
-
- if CONFIG['verbose']:
- pp.uprint(" * Searching for USE flag %s ... " % pp.emph(query))
-
- for pkg in matches:
- if display_useflags(query, pkg):
- got_match = True
-
- first_run = False
+ """Parse input and run the program"""
+
+ short_opts = "hiIpoF:" # -i was option for default action
+ # --installed is no longer needed, kept for compatibility (djanderson '09)
+ long_opts = (
+ "help",
+ "installed",
+ "exclude-installed",
+ "portage-tree",
+ "overlay-tree",
+ "format=",
+ )
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Module %s" % err))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ matches = Query("*").smart_find(**QUERY_OPTS)
+ matches.sort()
+
+ #
+ # Output
+ #
+
+ first_run = True
+ got_match = False
+ for query in queries:
+ if not first_run:
+ print()
+
+ if CONFIG["verbose"]:
+ pp.uprint(" * Searching for USE flag %s ... " % pp.emph(query))
+
+ for pkg in matches:
+ if display_useflags(query, pkg):
+ got_match = True
+
+ first_run = False
+
+ if not got_match:
+ sys.exit(1)
- if not got_match:
- sys.exit(1)
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/equery/keywords.py b/pym/gentoolkit/equery/keywords.py
index be79fe3..dbe5133 100644
--- a/pym/gentoolkit/equery/keywords.py
+++ b/pym/gentoolkit/equery/keywords.py
@@ -1,8 +1,9 @@
-# vim:fileencoding=utf-8
+# vim:fileencoding=utf-8
# Copyright 2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
from gentoolkit.eshowkw import main as emain
+
def main(input_args):
- emain(input_args, True) \ No newline at end of file
+ emain(input_args, True)
diff --git a/pym/gentoolkit/equery/list_.py b/pym/gentoolkit/equery/list_.py
index f66dfed..1e03d91 100644
--- a/pym/gentoolkit/equery/list_.py
+++ b/pym/gentoolkit/equery/list_.py
@@ -4,7 +4,7 @@
"""List installed packages matching the query pattern"""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
# =======
# Imports
@@ -25,231 +25,249 @@ from gentoolkit.query import Query
# =======
QUERY_OPTS = {
- "duplicates": False,
- "in_installed": True,
- "in_porttree": False,
- "in_overlay": False,
- "include_mask_reason": False,
- "is_regex": False,
- "show_progress": (not CONFIG['quiet']),
- "package_format": None,
- "binpkgs-missing": False
+ "duplicates": False,
+ "in_installed": True,
+ "in_porttree": False,
+ "in_overlay": False,
+ "include_mask_reason": False,
+ "is_regex": False,
+ "show_progress": (not CONFIG["quiet"]),
+ "package_format": None,
+ "binpkgs-missing": False,
}
# =========
# Functions
# =========
+
def print_help(with_description=True):
- """Print description, usage and a detailed help message.
-
- @type with_description: bool
- @param with_description: if true, print module's __doc__ string
- """
-
- if with_description:
- print(__doc__.strip())
- print()
-
- # Deprecation warning added by djanderson, 12/2008
- depwarning = (
- "Default action for this module has changed in Gentoolkit 0.3.",
- "Use globbing to simulate the old behavior (see man equery).",
- "Use '*' to check all installed packages.",
- "Use 'foo-bar/*' to filter by category."
- )
- for line in depwarning:
- sys.stderr.write(pp.warn(line))
- print()
-
- print(mod_usage(mod_name="list"))
- print()
- print(pp.command("options"))
- print(format_options((
- (" -h, --help", "display this help message"),
- (" -d, --duplicates", "list only installed duplicate packages"),
- (" -b, --binpkgs-missing", "list only installed packages without a corresponding binary package"),
- (" -f, --full-regex", "query is a regular expression"),
- (" -m, --mask-reason", "include reason for package mask"),
- (" -I, --exclude-installed",
- "exclude installed packages from output"),
- (" -o, --overlay-tree", "list packages in overlays"),
- (" -p, --portage-tree", "list packages in the main portage tree"),
- (" -F, --format=TMPL", "specify a custom output format"),
- (" TMPL",
- "a format template using (see man page):")
- )))
- print(" " * 24, ', '.join(pp.emph(x) for x in FORMAT_TMPL_VARS))
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print(__doc__.strip())
+ print()
+
+ # Deprecation warning added by djanderson, 12/2008
+ depwarning = (
+ "Default action for this module has changed in Gentoolkit 0.3.",
+ "Use globbing to simulate the old behavior (see man equery).",
+ "Use '*' to check all installed packages.",
+ "Use 'foo-bar/*' to filter by category.",
+ )
+ for line in depwarning:
+ sys.stderr.write(pp.warn(line))
+ print()
+
+ print(mod_usage(mod_name="list"))
+ print()
+ print(pp.command("options"))
+ print(
+ format_options(
+ (
+ (" -h, --help", "display this help message"),
+ (" -d, --duplicates", "list only installed duplicate packages"),
+ (
+ " -b, --binpkgs-missing",
+ "list only installed packages without a corresponding binary package",
+ ),
+ (" -f, --full-regex", "query is a regular expression"),
+ (" -m, --mask-reason", "include reason for package mask"),
+ (" -I, --exclude-installed", "exclude installed packages from output"),
+ (" -o, --overlay-tree", "list packages in overlays"),
+ (" -p, --portage-tree", "list packages in the main portage tree"),
+ (" -F, --format=TMPL", "specify a custom output format"),
+ (" TMPL", "a format template using (see man page):"),
+ )
+ )
+ )
+ print(" " * 24, ", ".join(pp.emph(x) for x in FORMAT_TMPL_VARS))
def get_duplicates(matches):
- """Return only packages that have more than one version installed."""
+ """Return only packages that have more than one version installed."""
- dups = {}
- result = []
- for pkg in matches:
- if pkg.cp in dups:
- dups[pkg.cp].append(pkg)
- else:
- dups[pkg.cp] = [pkg]
+ dups = {}
+ result = []
+ for pkg in matches:
+ if pkg.cp in dups:
+ dups[pkg.cp].append(pkg)
+ else:
+ dups[pkg.cp] = [pkg]
- for cpv in dups.values():
- if len(cpv) > 1:
- result.extend(cpv)
+ for cpv in dups.values():
+ if len(cpv) > 1:
+ result.extend(cpv)
- return result
+ return result
def get_binpkgs_missing(matches):
- """Return only packages that do not have a corresponding binary package."""
+ """Return only packages that do not have a corresponding binary package."""
- result = []
- binary_packages = set(get_bintree_cpvs())
- matched_packages = set(x.cpv for x in matches)
- missing_binary_packages = set(matched_packages.difference(binary_packages))
+ result = []
+ binary_packages = set(get_bintree_cpvs())
+ matched_packages = set(x.cpv for x in matches)
+ missing_binary_packages = set(matched_packages.difference(binary_packages))
- for pkg in matches:
- if pkg.cpv in missing_binary_packages:
- result.append(pkg)
- return result
+ for pkg in matches:
+ if pkg.cpv in missing_binary_packages:
+ result.append(pkg)
+ return result
def parse_module_options(module_opts):
- """Parse module options and update QUERY_OPTS"""
-
- opts = (x[0] for x in module_opts)
- posargs = (x[1] for x in module_opts)
- for opt, posarg in zip(opts, posargs):
- if opt in ('-h', '--help'):
- print_help()
- sys.exit(0)
- elif opt in ('-I', '--exclude-installed'):
- QUERY_OPTS['in_installed'] = False
- elif opt in ('-p', '--portage-tree'):
- QUERY_OPTS['in_porttree'] = True
- elif opt in ('-o', '--overlay-tree'):
- QUERY_OPTS['in_overlay'] = True
- elif opt in ('-f', '--full-regex'):
- QUERY_OPTS['is_regex'] = True
- elif opt in ('-m', '--mask-reason'):
- QUERY_OPTS['include_mask_reason'] = True
- elif opt in ('-e', '--exact-name'):
- sys.stderr.write(pp.warn("-e, --exact-name is now default."))
- sys.stderr.write(
- pp.warn("Use globbing to simulate the old behavior.")
- )
- print()
- elif opt in ('-d', '--duplicates'):
- QUERY_OPTS['duplicates'] = True
- elif opt in ('-b', '--binpkgs-missing'):
- QUERY_OPTS['binpkgs-missing'] = True
- elif opt in ('-F', '--format'):
- QUERY_OPTS["package_format"] = posarg
+ """Parse module options and update QUERY_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ("-h", "--help"):
+ print_help()
+ sys.exit(0)
+ elif opt in ("-I", "--exclude-installed"):
+ QUERY_OPTS["in_installed"] = False
+ elif opt in ("-p", "--portage-tree"):
+ QUERY_OPTS["in_porttree"] = True
+ elif opt in ("-o", "--overlay-tree"):
+ QUERY_OPTS["in_overlay"] = True
+ elif opt in ("-f", "--full-regex"):
+ QUERY_OPTS["is_regex"] = True
+ elif opt in ("-m", "--mask-reason"):
+ QUERY_OPTS["include_mask_reason"] = True
+ elif opt in ("-e", "--exact-name"):
+ sys.stderr.write(pp.warn("-e, --exact-name is now default."))
+ sys.stderr.write(pp.warn("Use globbing to simulate the old behavior."))
+ print()
+ elif opt in ("-d", "--duplicates"):
+ QUERY_OPTS["duplicates"] = True
+ elif opt in ("-b", "--binpkgs-missing"):
+ QUERY_OPTS["binpkgs-missing"] = True
+ elif opt in ("-F", "--format"):
+ QUERY_OPTS["package_format"] = posarg
def main(input_args):
- """Parse input and run the program"""
-
- short_opts = "hdbefiImopF:" # -i, -e were options for default actions
-
- # 04/09: djanderson
- # --all is no longer needed. Kept for compatibility.
- # --installed is no longer needed. Kept for compatibility.
- # --exact-name is no longer needed. Kept for compatibility.
- long_opts = ('help', 'all', 'installed', 'exclude-installed',
- 'mask-reason', 'portage-tree', 'overlay-tree', 'format=', 'full-regex',
- 'exact-name', 'duplicates', 'binpkgs-missing')
-
- try:
- module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
- except GetoptError as err:
- sys.stderr.write(pp.error("Module %s" % err))
- print()
- print_help(with_description=False)
- sys.exit(2)
-
- parse_module_options(module_opts)
-
- # Only search installed packages when listing duplicate or missing binary packages
- if QUERY_OPTS["duplicates"] or QUERY_OPTS["binpkgs-missing"]:
- QUERY_OPTS["in_installed"] = True
- QUERY_OPTS["in_porttree"] = False
- QUERY_OPTS["in_overlay"] = False
- QUERY_OPTS["include_mask_reason"] = False
-
- if not queries:
- print_help()
- sys.exit(2)
-
- first_run = True
- for query in (Query(x, QUERY_OPTS['is_regex']) for x in queries):
- if not first_run:
- print()
-
- # if we are in quiet mode, do not raise GentoolkitNoMatches exception
- # instead we raise GentoolkitNonZeroExit to exit with an exit value of 3
- try:
- matches = query.smart_find(**QUERY_OPTS)
- except errors.GentoolkitNoMatches:
- if CONFIG['verbose']:
- raise
- else:
- raise errors.GentoolkitNonZeroExit(3)
-
- # Find duplicate packages
- if QUERY_OPTS["duplicates"]:
- matches = get_duplicates(matches)
-
- # Find missing binary packages
- if QUERY_OPTS["binpkgs-missing"]:
- matches = get_binpkgs_missing(matches)
-
- matches.sort()
-
- #
- # Output
- #
-
- for pkg in matches:
- pkgstr = PackageFormatter(
- pkg,
- do_format=CONFIG['verbose'],
- custom_format=QUERY_OPTS["package_format"]
- )
-
- if (QUERY_OPTS["in_porttree"] and
- not QUERY_OPTS["in_overlay"]):
- if not 'P' in pkgstr.location:
- continue
- if (QUERY_OPTS["in_overlay"] and
- not QUERY_OPTS["in_porttree"]):
- if not 'O' in pkgstr.location:
- continue
- pp.uprint(pkgstr)
-
- if QUERY_OPTS["include_mask_reason"]:
- ms_int, ms_orig = pkgstr.format_mask_status()
- if ms_int < 3:
- # ms_int is a number representation of mask level.
- # Only 2 and above are "hard masked" and have reasons.
- continue
- mask_reason = pkg.mask_reason()
- if not mask_reason:
- # Package not on system or not masked
- continue
- elif not any(mask_reason):
- print(" * No mask reason given")
- else:
- status = ', '.join(ms_orig)
- explanation = mask_reason[0]
- mask_location = mask_reason[1]
- pp.uprint(" * Masked by %r" % status)
- pp.uprint(" * %s:" % mask_location)
- pp.uprint('\n'.join(
- [' * %s' % line.lstrip(' #')
- for line in explanation.splitlines()]
- ))
-
- first_run = False
+ """Parse input and run the program"""
+
+ short_opts = "hdbefiImopF:" # -i, -e were options for default actions
+
+ # 04/09: djanderson
+ # --all is no longer needed. Kept for compatibility.
+ # --installed is no longer needed. Kept for compatibility.
+ # --exact-name is no longer needed. Kept for compatibility.
+ long_opts = (
+ "help",
+ "all",
+ "installed",
+ "exclude-installed",
+ "mask-reason",
+ "portage-tree",
+ "overlay-tree",
+ "format=",
+ "full-regex",
+ "exact-name",
+ "duplicates",
+ "binpkgs-missing",
+ )
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Module %s" % err))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ # Only search installed packages when listing duplicate or missing binary packages
+ if QUERY_OPTS["duplicates"] or QUERY_OPTS["binpkgs-missing"]:
+ QUERY_OPTS["in_installed"] = True
+ QUERY_OPTS["in_porttree"] = False
+ QUERY_OPTS["in_overlay"] = False
+ QUERY_OPTS["include_mask_reason"] = False
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ first_run = True
+ for query in (Query(x, QUERY_OPTS["is_regex"]) for x in queries):
+ if not first_run:
+ print()
+
+ # if we are in quiet mode, do not raise GentoolkitNoMatches exception
+ # instead we raise GentoolkitNonZeroExit to exit with an exit value of 3
+ try:
+ matches = query.smart_find(**QUERY_OPTS)
+ except errors.GentoolkitNoMatches:
+ if CONFIG["verbose"]:
+ raise
+ else:
+ raise errors.GentoolkitNonZeroExit(3)
+
+ # Find duplicate packages
+ if QUERY_OPTS["duplicates"]:
+ matches = get_duplicates(matches)
+
+ # Find missing binary packages
+ if QUERY_OPTS["binpkgs-missing"]:
+ matches = get_binpkgs_missing(matches)
+
+ matches.sort()
+
+ #
+ # Output
+ #
+
+ for pkg in matches:
+ pkgstr = PackageFormatter(
+ pkg,
+ do_format=CONFIG["verbose"],
+ custom_format=QUERY_OPTS["package_format"],
+ )
+
+ if QUERY_OPTS["in_porttree"] and not QUERY_OPTS["in_overlay"]:
+ if not "P" in pkgstr.location:
+ continue
+ if QUERY_OPTS["in_overlay"] and not QUERY_OPTS["in_porttree"]:
+ if not "O" in pkgstr.location:
+ continue
+ pp.uprint(pkgstr)
+
+ if QUERY_OPTS["include_mask_reason"]:
+ ms_int, ms_orig = pkgstr.format_mask_status()
+ if ms_int < 3:
+ # ms_int is a number representation of mask level.
+ # Only 2 and above are "hard masked" and have reasons.
+ continue
+ mask_reason = pkg.mask_reason()
+ if not mask_reason:
+ # Package not on system or not masked
+ continue
+ elif not any(mask_reason):
+ print(" * No mask reason given")
+ else:
+ status = ", ".join(ms_orig)
+ explanation = mask_reason[0]
+ mask_location = mask_reason[1]
+ pp.uprint(" * Masked by %r" % status)
+ pp.uprint(" * %s:" % mask_location)
+ pp.uprint(
+ "\n".join(
+ [
+ " * %s" % line.lstrip(" #")
+ for line in explanation.splitlines()
+ ]
+ )
+ )
+
+ first_run = False
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/equery/meta.py b/pym/gentoolkit/equery/meta.py
index 2e632d5..7747893 100644
--- a/pym/gentoolkit/equery/meta.py
+++ b/pym/gentoolkit/equery/meta.py
@@ -4,7 +4,7 @@
"""Display metadata about a given package."""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
# =======
# Imports
@@ -28,533 +28,558 @@ from gentoolkit.query import Query
# =======
QUERY_OPTS = {
- 'current': False,
- 'description': False,
- 'herd': False,
- 'keywords': False,
- 'license': False,
- 'maintainer': False,
- 'stablereq': False,
- 'useflags': False,
- 'upstream': False,
- 'xml': False
+ "current": False,
+ "description": False,
+ "herd": False,
+ "keywords": False,
+ "license": False,
+ "maintainer": False,
+ "stablereq": False,
+ "useflags": False,
+ "upstream": False,
+ "xml": False,
}
STABLEREQ_arches = {
- 'alpha': 'alpha@gentoo.org',
- 'amd64': 'amd64@gentoo.org',
- 'arm': 'arm@gentoo.org',
- 'hppa': 'hppa@gentoo.org',
- 'ia64': 'ia64@gentoo.org',
- 'm68k': 'm68k@gentoo.org',
- 'ppc64': 'ppc64@gentoo.org',
- 'ppc': 'ppc@gentoo.org',
- 's390': 's390@gentoo.org',
- 'sh': 'sh@gentoo.org',
- 'sparc': 'sparc@gentoo.org',
- 'x86': 'x86@gentoo.org',
+ "alpha": "alpha@gentoo.org",
+ "amd64": "amd64@gentoo.org",
+ "arm": "arm@gentoo.org",
+ "hppa": "hppa@gentoo.org",
+ "ia64": "ia64@gentoo.org",
+ "m68k": "m68k@gentoo.org",
+ "ppc64": "ppc64@gentoo.org",
+ "ppc": "ppc@gentoo.org",
+ "s390": "s390@gentoo.org",
+ "sh": "sh@gentoo.org",
+ "sparc": "sparc@gentoo.org",
+ "x86": "x86@gentoo.org",
}
# =========
# Functions
# =========
+
def print_help(with_description=True, with_usage=True):
- """Print description, usage and a detailed help message.
-
- @type with_description: bool
- @param with_description: if true, print module's __doc__ string
- """
-
- if with_description:
- print(__doc__.strip())
- print()
- if with_usage:
- print(mod_usage(mod_name="meta"))
- print()
- print(pp.command("options"))
- print(format_options((
- (" -h, --help", "display this help message"),
- (" -d, --description", "show an extended package description"),
- (" -H, --herd", "show the herd(s) for the package"),
- (" -k, --keywords", "show keywords for all matching package versions"),
- (" -l, --license", "show licenses for the best maching version"),
- (" -m, --maintainer", "show the maintainer(s) for the package"),
- (" -r, --reverse", "show the output in reverse order if applicable"),
- (" -S, --stablreq", "show STABLEREQ arches (cc's) for all matching package versions"),
- (" -u, --useflags", "show per-package USE flag descriptions"),
- (" -U, --upstream", "show package's upstream information"),
- (" -x, --xml", "show the plain metadata.xml file")
- )))
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print(__doc__.strip())
+ print()
+ if with_usage:
+ print(mod_usage(mod_name="meta"))
+ print()
+ print(pp.command("options"))
+ print(
+ format_options(
+ (
+ (" -h, --help", "display this help message"),
+ (" -d, --description", "show an extended package description"),
+ (" -H, --herd", "show the herd(s) for the package"),
+ (" -k, --keywords", "show keywords for all matching package versions"),
+ (" -l, --license", "show licenses for the best maching version"),
+ (" -m, --maintainer", "show the maintainer(s) for the package"),
+ (" -r, --reverse", "show the output in reverse order if applicable"),
+ (
+ " -S, --stablreq",
+ "show STABLEREQ arches (cc's) for all matching package versions",
+ ),
+ (" -u, --useflags", "show per-package USE flag descriptions"),
+ (" -U, --upstream", "show package's upstream information"),
+ (" -x, --xml", "show the plain metadata.xml file"),
+ )
+ )
+ )
+
def stablereq(matches):
- """Produce the list of cc's for a STABLREQ bug
- @type matches: array
- @param matches: set of L{gentoolkit.package.Package} instances whose
- 'key' are all the same.
- @rtype: dict
- @return: a dict with L{gentoolkit.package.Package} instance keys and
- 'array of cc's to be added to a STABLEREQ bug.
- """
- result = {}
- for pkg in matches:
- keywords_str = pkg.environment(('KEYWORDS'), prefer_vdb=False)
- # get any unstable keywords
- keywords = set([x.lstrip('~') for x in keywords_str.split() if'~' in x])
- stable_arches = set(list(STABLEREQ_arches))
- cc_keywords = stable_arches.intersection(keywords)
- # add cc's
- result[pkg] = [STABLEREQ_arches[x] for x in cc_keywords]
- return result
+ """Produce the list of cc's for a STABLREQ bug
+ @type matches: array
+ @param matches: set of L{gentoolkit.package.Package} instances whose
+ 'key' are all the same.
+ @rtype: dict
+ @return: a dict with L{gentoolkit.package.Package} instance keys and
+ 'array of cc's to be added to a STABLEREQ bug.
+ """
+ result = {}
+ for pkg in matches:
+ keywords_str = pkg.environment(("KEYWORDS"), prefer_vdb=False)
+ # get any unstable keywords
+ keywords = set([x.lstrip("~") for x in keywords_str.split() if "~" in x])
+ stable_arches = set(list(STABLEREQ_arches))
+ cc_keywords = stable_arches.intersection(keywords)
+ # add cc's
+ result[pkg] = [STABLEREQ_arches[x] for x in cc_keywords]
+ return result
+
def filter_keywords(matches):
- """Filters non-unique keywords per slot.
-
- Does not filter arch mask keywords (-). Besides simple non-unique keywords,
- also remove unstable keywords (~) if a higher version in the same slot is
- stable. This view makes version bumps easier for package maintainers.
-
- @type matches: array
- @param matches: set of L{gentoolkit.package.Package} instances whose
- 'key' are all the same.
- @rtype: dict
- @return: a dict with L{gentoolkit.package.Package} instance keys and
- 'array of keywords not found in a higher version of pkg within the
- same slot' values.
- """
- def del_archmask(keywords):
- """Don't add arch_masked to filter set."""
- return [x for x in keywords if not x.startswith('-')]
-
- def add_unstable(keywords):
- """Add unstable keyword for all stable keywords to filter set."""
- result = list(keywords)
- result.extend(
- ['~%s' % x for x in keywords if not x.startswith(('-', '~'))]
- )
- return result
-
- result = {}
- slot_map = {}
- # Start from the newest
- rev_matches = reversed(matches)
- for pkg in rev_matches:
- keywords_str, slot = pkg.environment(('KEYWORDS', 'SLOT'),
- prefer_vdb=False)
- keywords = keywords_str.split()
- result[pkg] = [x for x in keywords if x not in slot_map.get(slot, [])]
- try:
- slot_map[slot].update(del_archmask(add_unstable(keywords)))
- except KeyError:
- slot_map[slot] = set(del_archmask(add_unstable(keywords)))
-
- return result
+ """Filters non-unique keywords per slot.
+
+ Does not filter arch mask keywords (-). Besides simple non-unique keywords,
+ also remove unstable keywords (~) if a higher version in the same slot is
+ stable. This view makes version bumps easier for package maintainers.
+
+ @type matches: array
+ @param matches: set of L{gentoolkit.package.Package} instances whose
+ 'key' are all the same.
+ @rtype: dict
+ @return: a dict with L{gentoolkit.package.Package} instance keys and
+ 'array of keywords not found in a higher version of pkg within the
+ same slot' values.
+ """
+
+ def del_archmask(keywords):
+ """Don't add arch_masked to filter set."""
+ return [x for x in keywords if not x.startswith("-")]
+
+ def add_unstable(keywords):
+ """Add unstable keyword for all stable keywords to filter set."""
+ result = list(keywords)
+ result.extend(["~%s" % x for x in keywords if not x.startswith(("-", "~"))])
+ return result
+
+ result = {}
+ slot_map = {}
+ # Start from the newest
+ rev_matches = reversed(matches)
+ for pkg in rev_matches:
+ keywords_str, slot = pkg.environment(("KEYWORDS", "SLOT"), prefer_vdb=False)
+ keywords = keywords_str.split()
+ result[pkg] = [x for x in keywords if x not in slot_map.get(slot, [])]
+ try:
+ slot_map[slot].update(del_archmask(add_unstable(keywords)))
+ except KeyError:
+ slot_map[slot] = set(del_archmask(add_unstable(keywords)))
+
+ return result
def format_herds(herds):
- """Format herd information for display."""
+ """Format herd information for display."""
- result = []
- for herd in herds:
- herdstr = ''
- email = "(%s)" % herd[1] if herd[1] else ''
- herdstr = herd[0]
- if CONFIG['verbose']:
- herdstr += " %s" % (email,)
- result.append(herdstr)
+ result = []
+ for herd in herds:
+ herdstr = ""
+ email = "(%s)" % herd[1] if herd[1] else ""
+ herdstr = herd[0]
+ if CONFIG["verbose"]:
+ herdstr += " %s" % (email,)
+ result.append(herdstr)
- return result
+ return result
def format_maintainers(maints):
- """Format maintainer information for display."""
+ """Format maintainer information for display."""
- result = []
- for maint in maints:
- maintstr = maint.email or ''
- if CONFIG['verbose']:
- maintstr += " (%s)" % (maint.name,) if maint.name else ''
- maintstr += " - %s" % (maint.restrict,) if maint.restrict else ''
- maintstr += "\n%s" % (maint.description,) if maint.description else ''
- result.append(maintstr)
+ result = []
+ for maint in maints:
+ maintstr = maint.email or ""
+ if CONFIG["verbose"]:
+ maintstr += " (%s)" % (maint.name,) if maint.name else ""
+ maintstr += " - %s" % (maint.restrict,) if maint.restrict else ""
+ maintstr += "\n%s" % (maint.description,) if maint.description else ""
+ result.append(maintstr)
- return result
+ return result
def format_upstream(upstream):
- """Format upstream information for display."""
-
- def _format_upstream_docs(docs):
- result = []
- for doc in docs:
- doc_location = doc[0]
- doc_lang = doc[1]
- docstr = doc_location
- if doc_lang is not None:
- docstr += " (%s)" % (doc_lang,)
- result.append(docstr)
- return result
-
- def _format_upstream_ids(ids):
- result = []
- for id_ in ids:
- site = id_[0]
- proj_id = id_[1]
- idstr = "%s ID: %s" % (site, proj_id)
- result.append(idstr)
- return result
-
- result = []
- for up in upstream:
- upmaints = format_maintainers(up.maintainers)
- for upmaint in upmaints:
- result.append(format_line(upmaint, "Maintainer: ", " " * 13))
-
- for upchange in up.changelogs:
- result.append(format_line(upchange, "ChangeLog: ", " " * 13))
-
- updocs = _format_upstream_docs(up.docs)
- for updoc in updocs:
- result.append(format_line(updoc, "Docs: ", " " * 13))
-
- for upbug in up.bugtrackers:
- result.append(format_line(upbug, "Bugs-to: ", " " * 13))
-
- upids = _format_upstream_ids(up.remoteids)
- for upid in upids:
- result.append(format_line(upid, "Remote-ID: ", " " * 13))
-
- return result
+ """Format upstream information for display."""
+
+ def _format_upstream_docs(docs):
+ result = []
+ for doc in docs:
+ doc_location = doc[0]
+ doc_lang = doc[1]
+ docstr = doc_location
+ if doc_lang is not None:
+ docstr += " (%s)" % (doc_lang,)
+ result.append(docstr)
+ return result
+
+ def _format_upstream_ids(ids):
+ result = []
+ for id_ in ids:
+ site = id_[0]
+ proj_id = id_[1]
+ idstr = "%s ID: %s" % (site, proj_id)
+ result.append(idstr)
+ return result
+
+ result = []
+ for up in upstream:
+ upmaints = format_maintainers(up.maintainers)
+ for upmaint in upmaints:
+ result.append(format_line(upmaint, "Maintainer: ", " " * 13))
+
+ for upchange in up.changelogs:
+ result.append(format_line(upchange, "ChangeLog: ", " " * 13))
+
+ updocs = _format_upstream_docs(up.docs)
+ for updoc in updocs:
+ result.append(format_line(updoc, "Docs: ", " " * 13))
+
+ for upbug in up.bugtrackers:
+ result.append(format_line(upbug, "Bugs-to: ", " " * 13))
+
+ upids = _format_upstream_ids(up.remoteids)
+ for upid in upids:
+ result.append(format_line(upid, "Remote-ID: ", " " * 13))
+
+ return result
def format_useflags(useflags):
- """Format USE flag information for display."""
+ """Format USE flag information for display."""
- result = []
- for flag in useflags:
- result.append(pp.useflag(flag.name))
- result.append(flag.description)
- result.append("")
+ result = []
+ for flag in useflags:
+ result.append(pp.useflag(flag.name))
+ result.append(flag.description)
+ result.append("")
- return result
+ return result
def format_keywords(keywords):
- """Sort and colorize keywords for display."""
+ """Sort and colorize keywords for display."""
- result = []
+ result = []
- for kw in sorted(keywords, key=Keyword):
- if kw.startswith('-'):
- # arch masked
- kw = pp.keyword(kw, stable=False, hard_masked=True)
- elif kw.startswith('~'):
- # keyword masked
- kw = pp.keyword(kw, stable=False, hard_masked=False)
- else:
- # stable
- kw = pp.keyword(kw, stable=True, hard_masked=False)
- result.append(kw)
+ for kw in sorted(keywords, key=Keyword):
+ if kw.startswith("-"):
+ # arch masked
+ kw = pp.keyword(kw, stable=False, hard_masked=True)
+ elif kw.startswith("~"):
+ # keyword masked
+ kw = pp.keyword(kw, stable=False, hard_masked=False)
+ else:
+ # stable
+ kw = pp.keyword(kw, stable=True, hard_masked=False)
+ result.append(kw)
- return ' '.join(result)
+ return " ".join(result)
def format_keywords_line(pkg, fmtd_keywords, slot, verstr_len):
- """Format the entire keywords line for display."""
+ """Format the entire keywords line for display."""
- ver = pkg.fullversion
- result = "%s:%s: %s" % (ver, pp.slot(slot), fmtd_keywords)
- if CONFIG['verbose'] and fmtd_keywords:
- result = format_line(fmtd_keywords, "%s:%s: " % (ver, pp.slot(slot)),
- " " * (verstr_len + 2))
+ ver = pkg.fullversion
+ result = "%s:%s: %s" % (ver, pp.slot(slot), fmtd_keywords)
+ if CONFIG["verbose"] and fmtd_keywords:
+ result = format_line(
+ fmtd_keywords, "%s:%s: " % (ver, pp.slot(slot)), " " * (verstr_len + 2)
+ )
- return result
+ return result
def format_stablereq_line(pkg, fmtd_ccs, slot):
- """Format the entire stablereq line for display (no indented linewrapping)
- """
- return "%s:%s: %s" % (pkg.fullversion, pp.slot(slot), fmtd_ccs)
+ """Format the entire stablereq line for display (no indented linewrapping)"""
+ return "%s:%s: %s" % (pkg.fullversion, pp.slot(slot), fmtd_ccs)
def format_homepage(homepage):
- """format the homepage(s) entries for dispaly"""
- result = []
- for page in homepage.split():
- result.append(format_line(page, "Homepage: ", " " * 13))
- return result
+ """format the homepage(s) entries for dispaly"""
+ result = []
+ for page in homepage.split():
+ result.append(format_line(page, "Homepage: ", " " * 13))
+ return result
def call_format_functions(best_match, matches):
- """Call information gathering functions and display the results."""
-
- if CONFIG['verbose']:
- repo = best_match.repo_name()
- pp.uprint(" * %s [%s]" % (pp.cpv(best_match.cp), pp.section(repo)))
-
- got_opts = False
- if any(QUERY_OPTS.values()):
- # Specific information requested, less formatting
- got_opts = True
-
- if QUERY_OPTS["herd"] or not got_opts:
- herds = best_match.metadata.herds(include_email=True)
- if any(not h[0] for h in herds):
- print(pp.warn("The packages metadata.xml has an empty <herd> tag"),
- file = sys.stderr)
- herds = [x for x in herds if x[0]]
- herds = format_herds(herds)
- if QUERY_OPTS["herd"]:
- print_sequence(format_list(herds))
- else:
- for herd in herds:
- pp.uprint(format_line(herd, "Herd: ", " " * 13))
-
- if QUERY_OPTS["maintainer"] or not got_opts:
- maints = format_maintainers(best_match.metadata.maintainers())
- if QUERY_OPTS["maintainer"]:
- print_sequence(format_list(maints))
- else:
- if not maints:
- pp.uprint(format_line([], "Maintainer: ", " " * 13))
- else:
- for maint in maints:
- pp.uprint(format_line(maint, "Maintainer: ", " " * 13))
-
- if QUERY_OPTS["upstream"] or not got_opts:
- upstream = format_upstream(best_match.metadata.upstream())
- homepage = format_homepage(best_match.environment("HOMEPAGE"))
- if QUERY_OPTS["upstream"]:
- upstream = format_list(upstream)
- else:
- upstream = format_list(upstream, "Upstream: ", " " * 13)
- print_sequence(upstream)
- print_sequence(homepage)
-
- if not got_opts:
- pkg_loc = best_match.package_path()
- pp.uprint(format_line(pkg_loc, "Location: ", " " * 13))
-
- if QUERY_OPTS["keywords"] or not got_opts:
- # Get {<Package 'dev-libs/glib-2.20.5'>: [u'ia64', u'm68k', ...], ...}
- keyword_map = filter_keywords(matches)
-
- for match in matches:
- slot = match.environment('SLOT')
- verstr_len = len(match.fullversion) + len(slot)
- fmtd_keywords = format_keywords(keyword_map[match])
- keywords_line = format_keywords_line(
- match, fmtd_keywords, slot, verstr_len
- )
- if QUERY_OPTS["keywords"]:
- pp.uprint(keywords_line)
- else:
- indent = " " * (16 + verstr_len)
- pp.uprint(format_line(keywords_line, "Keywords: ", indent))
-
- if QUERY_OPTS["description"]:
- desc = best_match.metadata.descriptions()
- print_sequence(format_list(desc))
-
- if QUERY_OPTS["useflags"]:
- useflags = format_useflags(best_match.metadata.use())
- print_sequence(format_list(useflags))
-
- if QUERY_OPTS["license"] or not got_opts:
- _license = best_match.environment(["LICENSE"])
- if QUERY_OPTS["license"]:
- _license = format_list(_license)
- else:
- _license = format_list(_license, "License: ", " " * 13)
- print_sequence(_license)
-
- if QUERY_OPTS["stablereq"]:
- # Get {<Package 'dev-libs/glib-2.20.5'>: [u'ia64', u'm68k', ...], ...}
- stablereq_map = stablereq(matches)
- for match in matches:
- slot = match.environment('SLOT')
- verstr_len = len(match.fullversion) + len(slot)
- fmtd_ccs = ','.join(sorted(stablereq_map[match]))
- stablereq_line = format_stablereq_line(
- match, fmtd_ccs, slot
- )
- #print("STABLEREQ:", )
- pp.uprint(stablereq_line)
-
- if QUERY_OPTS["xml"]:
- print_file(os.path.join(best_match.package_path(), 'metadata.xml'))
+ """Call information gathering functions and display the results."""
+
+ if CONFIG["verbose"]:
+ repo = best_match.repo_name()
+ pp.uprint(" * %s [%s]" % (pp.cpv(best_match.cp), pp.section(repo)))
+
+ got_opts = False
+ if any(QUERY_OPTS.values()):
+ # Specific information requested, less formatting
+ got_opts = True
+
+ if QUERY_OPTS["herd"] or not got_opts:
+ herds = best_match.metadata.herds(include_email=True)
+ if any(not h[0] for h in herds):
+ print(
+ pp.warn("The packages metadata.xml has an empty <herd> tag"),
+ file=sys.stderr,
+ )
+ herds = [x for x in herds if x[0]]
+ herds = format_herds(herds)
+ if QUERY_OPTS["herd"]:
+ print_sequence(format_list(herds))
+ else:
+ for herd in herds:
+ pp.uprint(format_line(herd, "Herd: ", " " * 13))
+
+ if QUERY_OPTS["maintainer"] or not got_opts:
+ maints = format_maintainers(best_match.metadata.maintainers())
+ if QUERY_OPTS["maintainer"]:
+ print_sequence(format_list(maints))
+ else:
+ if not maints:
+ pp.uprint(format_line([], "Maintainer: ", " " * 13))
+ else:
+ for maint in maints:
+ pp.uprint(format_line(maint, "Maintainer: ", " " * 13))
+
+ if QUERY_OPTS["upstream"] or not got_opts:
+ upstream = format_upstream(best_match.metadata.upstream())
+ homepage = format_homepage(best_match.environment("HOMEPAGE"))
+ if QUERY_OPTS["upstream"]:
+ upstream = format_list(upstream)
+ else:
+ upstream = format_list(upstream, "Upstream: ", " " * 13)
+ print_sequence(upstream)
+ print_sequence(homepage)
+
+ if not got_opts:
+ pkg_loc = best_match.package_path()
+ pp.uprint(format_line(pkg_loc, "Location: ", " " * 13))
+
+ if QUERY_OPTS["keywords"] or not got_opts:
+ # Get {<Package 'dev-libs/glib-2.20.5'>: [u'ia64', u'm68k', ...], ...}
+ keyword_map = filter_keywords(matches)
+
+ for match in matches:
+ slot = match.environment("SLOT")
+ verstr_len = len(match.fullversion) + len(slot)
+ fmtd_keywords = format_keywords(keyword_map[match])
+ keywords_line = format_keywords_line(match, fmtd_keywords, slot, verstr_len)
+ if QUERY_OPTS["keywords"]:
+ pp.uprint(keywords_line)
+ else:
+ indent = " " * (16 + verstr_len)
+ pp.uprint(format_line(keywords_line, "Keywords: ", indent))
+
+ if QUERY_OPTS["description"]:
+ desc = best_match.metadata.descriptions()
+ print_sequence(format_list(desc))
+
+ if QUERY_OPTS["useflags"]:
+ useflags = format_useflags(best_match.metadata.use())
+ print_sequence(format_list(useflags))
+
+ if QUERY_OPTS["license"] or not got_opts:
+ _license = best_match.environment(["LICENSE"])
+ if QUERY_OPTS["license"]:
+ _license = format_list(_license)
+ else:
+ _license = format_list(_license, "License: ", " " * 13)
+ print_sequence(_license)
+
+ if QUERY_OPTS["stablereq"]:
+ # Get {<Package 'dev-libs/glib-2.20.5'>: [u'ia64', u'm68k', ...], ...}
+ stablereq_map = stablereq(matches)
+ for match in matches:
+ slot = match.environment("SLOT")
+ verstr_len = len(match.fullversion) + len(slot)
+ fmtd_ccs = ",".join(sorted(stablereq_map[match]))
+ stablereq_line = format_stablereq_line(match, fmtd_ccs, slot)
+ # print("STABLEREQ:", )
+ pp.uprint(stablereq_line)
+
+ if QUERY_OPTS["xml"]:
+ print_file(os.path.join(best_match.package_path(), "metadata.xml"))
def format_line(line, first="", subsequent="", force_quiet=False):
- """Wrap a string at word boundaries and optionally indent the first line
- and/or subsequent lines with custom strings.
-
- Preserve newlines if the longest line is not longer than
- CONFIG['termWidth']. To force the preservation of newlines and indents,
- split the string into a list and feed it to format_line via format_list.
-
- @see: format_list()
- @type line: string
- @param line: text to format
- @type first: string
- @param first: text to prepend to the first line
- @type subsequent: string
- @param subsequent: text to prepend to subsequent lines
- @type force_quiet: boolean
- @rtype: string
- @return: A wrapped line
- """
-
- if line:
- line = line.expandtabs().strip("\n").splitlines()
- else:
- if force_quiet:
- return
- else:
- return first + "None specified"
-
- if len(first) > len(subsequent):
- wider_indent = first
- else:
- wider_indent = subsequent
-
- widest_line_len = len(max(line, key=len)) + len(wider_indent)
-
- if widest_line_len > CONFIG['termWidth']:
- twrap = TextWrapper(width=CONFIG['termWidth'], expand_tabs=False,
- initial_indent=first, subsequent_indent=subsequent)
- line = " ".join(line)
- line = re.sub(r"\s+", " ", line)
- line = line.lstrip()
- result = twrap.fill(line)
- else:
- # line will fit inside CONFIG['termWidth'], so preserve whitespace and
- # newlines
- line[0] = first + line[0] # Avoid two newlines if len == 1
-
- if len(line) > 1:
- line[0] = line[0] + "\n"
- for i in range(1, (len(line[1:-1]) + 1)):
- line[i] = subsequent + line[i] + "\n"
- line[-1] = subsequent + line[-1] # Avoid two newlines on last line
-
- if line[-1].isspace():
- del line[-1] # Avoid trailing blank lines
-
- result = "".join(line)
-
- return result
+ """Wrap a string at word boundaries and optionally indent the first line
+ and/or subsequent lines with custom strings.
+
+ Preserve newlines if the longest line is not longer than
+ CONFIG['termWidth']. To force the preservation of newlines and indents,
+ split the string into a list and feed it to format_line via format_list.
+
+ @see: format_list()
+ @type line: string
+ @param line: text to format
+ @type first: string
+ @param first: text to prepend to the first line
+ @type subsequent: string
+ @param subsequent: text to prepend to subsequent lines
+ @type force_quiet: boolean
+ @rtype: string
+ @return: A wrapped line
+ """
+
+ if line:
+ line = line.expandtabs().strip("\n").splitlines()
+ else:
+ if force_quiet:
+ return
+ else:
+ return first + "None specified"
+
+ if len(first) > len(subsequent):
+ wider_indent = first
+ else:
+ wider_indent = subsequent
+
+ widest_line_len = len(max(line, key=len)) + len(wider_indent)
+
+ if widest_line_len > CONFIG["termWidth"]:
+ twrap = TextWrapper(
+ width=CONFIG["termWidth"],
+ expand_tabs=False,
+ initial_indent=first,
+ subsequent_indent=subsequent,
+ )
+ line = " ".join(line)
+ line = re.sub(r"\s+", " ", line)
+ line = line.lstrip()
+ result = twrap.fill(line)
+ else:
+ # line will fit inside CONFIG['termWidth'], so preserve whitespace and
+ # newlines
+ line[0] = first + line[0] # Avoid two newlines if len == 1
+
+ if len(line) > 1:
+ line[0] = line[0] + "\n"
+ for i in range(1, (len(line[1:-1]) + 1)):
+ line[i] = subsequent + line[i] + "\n"
+ line[-1] = subsequent + line[-1] # Avoid two newlines on last line
+
+ if line[-1].isspace():
+ del line[-1] # Avoid trailing blank lines
+
+ result = "".join(line)
+
+ return result
def format_list(lst, first="", subsequent="", force_quiet=False):
- """Feed elements of a list to format_line().
-
- @see: format_line()
- @type lst: list
- @param lst: list to format
- @type first: string
- @param first: text to prepend to the first line
- @type subsequent: string
- @param subsequent: text to prepend to subsequent lines
- @rtype: list
- @return: list with element text wrapped at CONFIG['termWidth']
- """
-
- result = []
- if lst:
- # Format the first line
- line = format_line(lst[0], first, subsequent, force_quiet)
- result.append(line)
- # Format subsequent lines
- for elem in lst[1:]:
- if elem:
- result.append(format_line(elem, subsequent, subsequent,
- force_quiet))
- else:
- # We don't want to send a blank line to format_line()
- result.append("")
- else:
- if CONFIG['verbose']:
- if force_quiet:
- result = None
- else:
- # Send empty list, we'll get back first + `None specified'
- result.append(format_line(lst, first, subsequent))
-
- return result
+ """Feed elements of a list to format_line().
+
+ @see: format_line()
+ @type lst: list
+ @param lst: list to format
+ @type first: string
+ @param first: text to prepend to the first line
+ @type subsequent: string
+ @param subsequent: text to prepend to subsequent lines
+ @rtype: list
+ @return: list with element text wrapped at CONFIG['termWidth']
+ """
+
+ result = []
+ if lst:
+ # Format the first line
+ line = format_line(lst[0], first, subsequent, force_quiet)
+ result.append(line)
+ # Format subsequent lines
+ for elem in lst[1:]:
+ if elem:
+ result.append(format_line(elem, subsequent, subsequent, force_quiet))
+ else:
+ # We don't want to send a blank line to format_line()
+ result.append("")
+ else:
+ if CONFIG["verbose"]:
+ if force_quiet:
+ result = None
+ else:
+ # Send empty list, we'll get back first + `None specified'
+ result.append(format_line(lst, first, subsequent))
+
+ return result
def parse_module_options(module_opts):
- """Parse module options and update QUERY_OPTS"""
-
- opts = (x[0] for x in module_opts)
- for opt in opts:
- if opt in ('-h', '--help'):
- print_help()
- sys.exit(0)
- elif opt in ('-d', '--description'):
- QUERY_OPTS["description"] = True
- elif opt in ('-H', '--herd'):
- QUERY_OPTS["herd"] = True
- elif opt in ('-l', '--license'):
- QUERY_OPTS["license"] = True
- elif opt in ('-m', '--maintainer'):
- QUERY_OPTS["maintainer"] = True
- elif opt in ('-k', '--keywords'):
- QUERY_OPTS["keywords"] = True
- elif opt in ('-S', '--stablereq'):
- QUERY_OPTS["stablereq"] = True
- elif opt in ('-u', '--useflags'):
- QUERY_OPTS["useflags"] = True
- elif opt in ('-U', '--upstream'):
- QUERY_OPTS["upstream"] = True
- elif opt in ('-x', '--xml'):
- QUERY_OPTS["xml"] = True
+ """Parse module options and update QUERY_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ for opt in opts:
+ if opt in ("-h", "--help"):
+ print_help()
+ sys.exit(0)
+ elif opt in ("-d", "--description"):
+ QUERY_OPTS["description"] = True
+ elif opt in ("-H", "--herd"):
+ QUERY_OPTS["herd"] = True
+ elif opt in ("-l", "--license"):
+ QUERY_OPTS["license"] = True
+ elif opt in ("-m", "--maintainer"):
+ QUERY_OPTS["maintainer"] = True
+ elif opt in ("-k", "--keywords"):
+ QUERY_OPTS["keywords"] = True
+ elif opt in ("-S", "--stablereq"):
+ QUERY_OPTS["stablereq"] = True
+ elif opt in ("-u", "--useflags"):
+ QUERY_OPTS["useflags"] = True
+ elif opt in ("-U", "--upstream"):
+ QUERY_OPTS["upstream"] = True
+ elif opt in ("-x", "--xml"):
+ QUERY_OPTS["xml"] = True
def main(input_args):
- """Parse input and run the program."""
-
- short_opts = "hdHklmrSuUx"
- long_opts = ('help', 'description', 'herd', 'keywords', 'license',
- 'maintainer', 'reverse', 'stablereq', 'useflags', 'upstream', 'xml')
-
- try:
- module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
- except GetoptError as err:
- sys.stderr.write(pp.error("Module %s" % err))
- print()
- print_help(with_description=False)
- sys.exit(2)
-
- parse_module_options(module_opts)
-
- # Find queries' Portage directory and throw error if invalid
- if not queries:
- print_help()
- sys.exit(2)
-
- first_run = True
- for query in (Query(x) for x in queries):
- best_match = query.find_best()
- matches = query.find(include_masked=True)
- if best_match is None or not matches:
- raise errors.GentoolkitNoMatches(query)
-
- if best_match.metadata is None:
- print(pp.warn("Package {0} is missing "
- "metadata.xml".format(best_match.cpv)),
- file = sys.stderr)
- continue
-
- if not first_run:
- print()
-
- matches.sort()
- matches.sort(reverse=any(name in ('-r', '--reverse')
- for name, opt in module_opts))
- call_format_functions(best_match, matches)
-
- first_run = False
+ """Parse input and run the program."""
+
+ short_opts = "hdHklmrSuUx"
+ long_opts = (
+ "help",
+ "description",
+ "herd",
+ "keywords",
+ "license",
+ "maintainer",
+ "reverse",
+ "stablereq",
+ "useflags",
+ "upstream",
+ "xml",
+ )
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Module %s" % err))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ # Find queries' Portage directory and throw error if invalid
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ first_run = True
+ for query in (Query(x) for x in queries):
+ best_match = query.find_best()
+ matches = query.find(include_masked=True)
+ if best_match is None or not matches:
+ raise errors.GentoolkitNoMatches(query)
+
+ if best_match.metadata is None:
+ print(
+ pp.warn(
+ "Package {0} is missing " "metadata.xml".format(best_match.cpv)
+ ),
+ file=sys.stderr,
+ )
+ continue
+
+ if not first_run:
+ print()
+
+ matches.sort()
+ matches.sort(
+ reverse=any(name in ("-r", "--reverse") for name, opt in module_opts)
+ )
+ call_format_functions(best_match, matches)
+
+ first_run = False
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/equery/size.py b/pym/gentoolkit/equery/size.py
index cb570ba..068e701 100644
--- a/pym/gentoolkit/equery/size.py
+++ b/pym/gentoolkit/equery/size.py
@@ -4,7 +4,7 @@
"""Print total size of files contained in a given package"""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
# =======
# Imports
@@ -22,171 +22,176 @@ from gentoolkit.query import Query
# =======
QUERY_OPTS = {
- "in_installed": True,
- "in_porttree": False,
- "in_overlay": False,
- "include_masked": True,
- "is_regex": False,
- "show_progress": False,
- "size_in_bytes": False
+ "in_installed": True,
+ "in_porttree": False,
+ "in_overlay": False,
+ "include_masked": True,
+ "is_regex": False,
+ "show_progress": False,
+ "size_in_bytes": False,
}
# =========
# Functions
# =========
+
def print_help(with_description=True):
- """Print description, usage and a detailed help message.
-
- @type with_description: bool
- @param with_description: if true, print module's __doc__ string
- """
-
- if with_description:
- print(__doc__.strip())
- print()
-
- # Deprecation warning added by djanderson, 12/2008
- depwarning = (
- "Default action for this module has changed in Gentoolkit 0.3.",
- "Use globbing to simulate the old behavior (see man equery).",
- "Use '*' to check all installed packages.",
- "Use 'foo-bar/*' to filter by category."
- )
- for line in depwarning:
- sys.stderr.write(pp.warn(line))
- print()
-
- print(mod_usage(mod_name="size"))
- print()
- print(pp.command("options"))
- print(format_options((
- (" -h, --help", "display this help message"),
- (" -b, --bytes", "report size in bytes"),
- (" -f, --full-regex", "query is a regular expression")
- )))
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print(__doc__.strip())
+ print()
+
+ # Deprecation warning added by djanderson, 12/2008
+ depwarning = (
+ "Default action for this module has changed in Gentoolkit 0.3.",
+ "Use globbing to simulate the old behavior (see man equery).",
+ "Use '*' to check all installed packages.",
+ "Use 'foo-bar/*' to filter by category.",
+ )
+ for line in depwarning:
+ sys.stderr.write(pp.warn(line))
+ print()
+
+ print(mod_usage(mod_name="size"))
+ print()
+ print(pp.command("options"))
+ print(
+ format_options(
+ (
+ (" -h, --help", "display this help message"),
+ (" -b, --bytes", "report size in bytes"),
+ (" -f, --full-regex", "query is a regular expression"),
+ )
+ )
+ )
def display_size(match_set):
- """Display the total size of all accessible files owned by packages.
+ """Display the total size of all accessible files owned by packages.
- @type match_set: list
- @param match_set: package cat/pkg-ver strings
- """
+ @type match_set: list
+ @param match_set: package cat/pkg-ver strings
+ """
- for pkg in match_set:
- size, files, uncounted = pkg.size()
+ for pkg in match_set:
+ size, files, uncounted = pkg.size()
- if CONFIG['verbose']:
- pp.uprint(" * %s" % pp.cpv(str(pkg.cpv)))
- print("Total files : %s".rjust(25) % pp.number(str(files)))
+ if CONFIG["verbose"]:
+ pp.uprint(" * %s" % pp.cpv(str(pkg.cpv)))
+ print("Total files : %s".rjust(25) % pp.number(str(files)))
- if uncounted:
- print(("Inaccessible files : %s".rjust(25) %
- pp.number(str(uncounted))))
+ if uncounted:
+ print(("Inaccessible files : %s".rjust(25) % pp.number(str(uncounted))))
- if QUERY_OPTS["size_in_bytes"]:
- size_str = pp.number(str(size))
- else:
- size_str = "%s %s" % format_bytes(size)
+ if QUERY_OPTS["size_in_bytes"]:
+ size_str = pp.number(str(size))
+ else:
+ size_str = "%s %s" % format_bytes(size)
- print("Total size : %s".rjust(25) % size_str)
- else:
- info = "%s: total(%d), inaccessible(%d), size(%s)"
- pp.uprint(info % (str(pkg.cpv), files, uncounted, size))
+ print("Total size : %s".rjust(25) % size_str)
+ else:
+ info = "%s: total(%d), inaccessible(%d), size(%s)"
+ pp.uprint(info % (str(pkg.cpv), files, uncounted, size))
def format_bytes(bytes_, precision=2):
- """Format bytes into human-readable format (IEC naming standard).
+ """Format bytes into human-readable format (IEC naming standard).
- @see: http://mail.python.org/pipermail/python-list/2008-August/503423.html
- @rtype: tuple
- @return: (str(num), str(label))
- """
+ @see: http://mail.python.org/pipermail/python-list/2008-August/503423.html
+ @rtype: tuple
+ @return: (str(num), str(label))
+ """
- labels = (
- (1<<40, 'TiB'),
- (1<<30, 'GiB'),
- (1<<20, 'MiB'),
- (1<<10, 'KiB'),
- (1, 'bytes')
- )
+ labels = (
+ (1 << 40, "TiB"),
+ (1 << 30, "GiB"),
+ (1 << 20, "MiB"),
+ (1 << 10, "KiB"),
+ (1, "bytes"),
+ )
- if bytes_ == 0:
- return (pp.number('0'), 'bytes')
- elif bytes_ == 1:
- return (pp.number('1'), 'byte')
+ if bytes_ == 0:
+ return (pp.number("0"), "bytes")
+ elif bytes_ == 1:
+ return (pp.number("1"), "byte")
- for factor, label in labels:
- if not bytes_ >= factor:
- continue
+ for factor, label in labels:
+ if not bytes_ >= factor:
+ continue
- float_split = str(bytes_/float(factor)).split('.')
- integer = float_split[0]
- decimal = float_split[1]
- if int(decimal[0:precision]):
- float_string = '.'.join([integer, decimal[0:precision]])
- else:
- float_string = integer
+ float_split = str(bytes_ / float(factor)).split(".")
+ integer = float_split[0]
+ decimal = float_split[1]
+ if int(decimal[0:precision]):
+ float_string = ".".join([integer, decimal[0:precision]])
+ else:
+ float_string = integer
- return (pp.number(float_string), label)
+ return (pp.number(float_string), label)
def parse_module_options(module_opts):
- """Parse module options and update QUERY_OPTS"""
-
- opts = (x[0] for x in module_opts)
- for opt in opts:
- if opt in ('-h', '--help'):
- print_help()
- sys.exit(0)
- elif opt in ('-b', '--bytes'):
- QUERY_OPTS["size_in_bytes"] = True
- elif opt in ('-e', '--exact-name'):
- sys.stderr.write(pp.warn("-e, --exact-name is now default."))
- warning = pp.warn("Use globbing to simulate the old behavior.")
- sys.stderr.write(warning)
- print()
- elif opt in ('-f', '--full-regex'):
- QUERY_OPTS['is_regex'] = True
+ """Parse module options and update QUERY_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ for opt in opts:
+ if opt in ("-h", "--help"):
+ print_help()
+ sys.exit(0)
+ elif opt in ("-b", "--bytes"):
+ QUERY_OPTS["size_in_bytes"] = True
+ elif opt in ("-e", "--exact-name"):
+ sys.stderr.write(pp.warn("-e, --exact-name is now default."))
+ warning = pp.warn("Use globbing to simulate the old behavior.")
+ sys.stderr.write(warning)
+ print()
+ elif opt in ("-f", "--full-regex"):
+ QUERY_OPTS["is_regex"] = True
def main(input_args):
- """Parse input and run the program"""
+ """Parse input and run the program"""
+
+ # -e, --exact-name is no longer needed. Kept for compatibility.
+ # 04/09 djanderson
+ short_opts = "hbfe"
+ long_opts = ("help", "bytes", "full-regex", "exact-name")
- # -e, --exact-name is no longer needed. Kept for compatibility.
- # 04/09 djanderson
- short_opts = "hbfe"
- long_opts = ('help', 'bytes', 'full-regex', 'exact-name')
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Module %s" % err))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
- try:
- module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
- except GetoptError as err:
- sys.stderr.write(pp.error("Module %s" % err))
- print()
- print_help(with_description=False)
- sys.exit(2)
+ parse_module_options(module_opts)
- parse_module_options(module_opts)
+ if not queries:
+ print_help()
+ sys.exit(2)
- if not queries:
- print_help()
- sys.exit(2)
+ first_run = True
+ for query in (Query(x, QUERY_OPTS["is_regex"]) for x in queries):
+ if not first_run:
+ print()
- first_run = True
- for query in (Query(x, QUERY_OPTS['is_regex']) for x in queries):
- if not first_run:
- print()
+ matches = query.smart_find(**QUERY_OPTS)
- matches = query.smart_find(**QUERY_OPTS)
+ if not matches:
+ sys.stderr.write(pp.error("No package found matching %s" % query))
- if not matches:
- sys.stderr.write(pp.error("No package found matching %s" % query))
+ matches.sort()
- matches.sort()
+ display_size(matches)
- display_size(matches)
+ first_run = False
- first_run = False
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/equery/uses.py b/pym/gentoolkit/equery/uses.py
index dfb6f31..7c90b90 100644
--- a/pym/gentoolkit/equery/uses.py
+++ b/pym/gentoolkit/equery/uses.py
@@ -4,7 +4,7 @@
"""Display USE flags for a given package"""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
# =======
# Imports
@@ -31,288 +31,294 @@ from gentoolkit.flag import get_flags, reduce_flags
# Globals
# =======
-QUERY_OPTS = {"all_versions" : False, "ignore_l10n" : False}
+QUERY_OPTS = {"all_versions": False, "ignore_l10n": False}
# =========
# Functions
# =========
-def print_help(with_description=True):
- """Print description, usage and a detailed help message.
-
- @type with_description: bool
- @param with_description: if true, print module's __doc__ string
- """
- if with_description:
- print(__doc__.strip())
- print()
- print(mod_usage(mod_name=__name__.split('.')[-1]))
- print()
- print(pp.command("options"))
- print(format_options((
- (" -h, --help", "display this help message"),
- (" -a, --all", "include all package versions"),
- (" -i, --ignore-l10n", "don't show l10n USE flags")
- )))
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print(__doc__.strip())
+ print()
+ print(mod_usage(mod_name=__name__.split(".")[-1]))
+ print()
+ print(pp.command("options"))
+ print(
+ format_options(
+ (
+ (" -h, --help", "display this help message"),
+ (" -a, --all", "include all package versions"),
+ (" -i, --ignore-l10n", "don't show l10n USE flags"),
+ )
+ )
+ )
def display_useflags(output):
- """Print USE flag descriptions and statuses.
-
- @type output: list
- @param output: [(inuse, inused, flag, desc, restrict), ...]
- inuse (int) = 0 or 1; if 1, flag is set in make.conf
- inused (int) = 0 or 1; if 1, package is installed with flag enabled
- flag (str) = the name of the USE flag
- desc (str) = the flag's description
- restrict (str) = corresponds to the text of restrict in metadata
- """
-
- maxflag_len = len(max([t[2] for t in output], key=len))
-
- twrap = TextWrapper()
- twrap.width = CONFIG['termWidth']
- twrap.subsequent_indent = " " * (maxflag_len + 8)
-
- markers = ("-", "+")
- color = (
- partial(pp.useflag, enabled=False), partial(pp.useflag, enabled=True)
- )
- for in_makeconf, in_installed, flag, desc, restrict in output:
- if CONFIG['verbose']:
- flag_name = ""
- if in_makeconf != in_installed:
- flag_name += pp.emph(" %s %s" %
- (markers[in_makeconf], markers[in_installed]))
- else:
- flag_name += (" %s %s" %
- (markers[in_makeconf], markers[in_installed]))
-
- flag_name += " " + color[in_makeconf](flag.ljust(maxflag_len))
- flag_name += " : "
-
- # Strip initial whitespace at the start of the description
- # Bug 432530
- if desc:
- desc = desc.lstrip()
-
- # print description
- if restrict:
- restrict = "(%s %s)" % (pp.emph("Restricted to"),
- pp.cpv(restrict))
- twrap.initial_indent = flag_name
- pp.uprint(twrap.fill(restrict))
- if desc:
- twrap.initial_indent = twrap.subsequent_indent
- pp.uprint(twrap.fill(desc))
- else:
- print(" : <unknown>")
- else:
- if desc:
- twrap.initial_indent = flag_name
- desc = twrap.fill(desc)
- pp.uprint(desc)
- else:
- twrap.initial_indent = flag_name
- print(twrap.fill("<unknown>"))
- else:
- pp.uprint(markers[in_makeconf] + flag)
+ """Print USE flag descriptions and statuses.
+
+ @type output: list
+ @param output: [(inuse, inused, flag, desc, restrict), ...]
+ inuse (int) = 0 or 1; if 1, flag is set in make.conf
+ inused (int) = 0 or 1; if 1, package is installed with flag enabled
+ flag (str) = the name of the USE flag
+ desc (str) = the flag's description
+ restrict (str) = corresponds to the text of restrict in metadata
+ """
+
+ maxflag_len = len(max([t[2] for t in output], key=len))
+
+ twrap = TextWrapper()
+ twrap.width = CONFIG["termWidth"]
+ twrap.subsequent_indent = " " * (maxflag_len + 8)
+
+ markers = ("-", "+")
+ color = (partial(pp.useflag, enabled=False), partial(pp.useflag, enabled=True))
+ for in_makeconf, in_installed, flag, desc, restrict in output:
+ if CONFIG["verbose"]:
+ flag_name = ""
+ if in_makeconf != in_installed:
+ flag_name += pp.emph(
+ " %s %s" % (markers[in_makeconf], markers[in_installed])
+ )
+ else:
+ flag_name += " %s %s" % (markers[in_makeconf], markers[in_installed])
+
+ flag_name += " " + color[in_makeconf](flag.ljust(maxflag_len))
+ flag_name += " : "
+
+ # Strip initial whitespace at the start of the description
+ # Bug 432530
+ if desc:
+ desc = desc.lstrip()
+
+ # print description
+ if restrict:
+ restrict = "(%s %s)" % (pp.emph("Restricted to"), pp.cpv(restrict))
+ twrap.initial_indent = flag_name
+ pp.uprint(twrap.fill(restrict))
+ if desc:
+ twrap.initial_indent = twrap.subsequent_indent
+ pp.uprint(twrap.fill(desc))
+ else:
+ print(" : <unknown>")
+ else:
+ if desc:
+ twrap.initial_indent = flag_name
+ desc = twrap.fill(desc)
+ pp.uprint(desc)
+ else:
+ twrap.initial_indent = flag_name
+ print(twrap.fill("<unknown>"))
+ else:
+ pp.uprint(markers[in_makeconf] + flag)
def get_global_useflags():
- """Get global and expanded USE flag variables from
- PORTDIR/profiles/use.desc and PORTDIR/profiles/desc/*.desc respectively.
-
- @rtype: dict
- @return: {'flag_name': 'flag description', ...}
- """
-
- global_usedesc = {}
- # Get global USE flag descriptions
- try:
- path = os.path.join(settings["PORTDIR"], 'profiles', 'use.desc')
- with open(_unicode_encode(path, encoding=_encodings['fs']),
- encoding=_encodings['content']) as open_file:
- for line in open_file:
- if line.startswith('#'):
- continue
- # Ex. of fields: ['syslog', 'Enables support for syslog\n']
- fields = line.split(" - ", 1)
- if len(fields) == 2:
- global_usedesc[fields[0]] = fields[1].rstrip()
- except IOError:
- sys.stderr.write(
- pp.warn(
- "Could not load USE flag descriptions from %s" % pp.path(path)
- )
- )
-
- del path, open_file
- # Add USE_EXPANDED variables to usedesc hash -- Bug #238005
- for path in glob(os.path.join(settings["PORTDIR"],
- 'profiles', 'desc', '*.desc')):
- try:
- with open(_unicode_encode(path, encoding=_encodings['fs']),
- encoding=_encodings['content']) as open_file:
- for line in open_file:
- if line.startswith('#'):
- continue
- fields = [field.strip() for field in line.split(" - ", 1)]
- if len(fields) == 2:
- expanded_useflag = "%s_%s" % \
- (path.split("/")[-1][0:-5], fields[0])
- global_usedesc[expanded_useflag] = fields[1]
- except IOError:
- sys.stderr.write(
- pp.warn("Could not load USE flag descriptions from %s" % path)
- )
-
- return global_usedesc
+ """Get global and expanded USE flag variables from
+ PORTDIR/profiles/use.desc and PORTDIR/profiles/desc/*.desc respectively.
+
+ @rtype: dict
+ @return: {'flag_name': 'flag description', ...}
+ """
+
+ global_usedesc = {}
+ # Get global USE flag descriptions
+ try:
+ path = os.path.join(settings["PORTDIR"], "profiles", "use.desc")
+ with open(
+ _unicode_encode(path, encoding=_encodings["fs"]),
+ encoding=_encodings["content"],
+ ) as open_file:
+ for line in open_file:
+ if line.startswith("#"):
+ continue
+ # Ex. of fields: ['syslog', 'Enables support for syslog\n']
+ fields = line.split(" - ", 1)
+ if len(fields) == 2:
+ global_usedesc[fields[0]] = fields[1].rstrip()
+ except IOError:
+ sys.stderr.write(
+ pp.warn("Could not load USE flag descriptions from %s" % pp.path(path))
+ )
+
+ del path, open_file
+ # Add USE_EXPANDED variables to usedesc hash -- Bug #238005
+ for path in glob(os.path.join(settings["PORTDIR"], "profiles", "desc", "*.desc")):
+ try:
+ with open(
+ _unicode_encode(path, encoding=_encodings["fs"]),
+ encoding=_encodings["content"],
+ ) as open_file:
+ for line in open_file:
+ if line.startswith("#"):
+ continue
+ fields = [field.strip() for field in line.split(" - ", 1)]
+ if len(fields) == 2:
+ expanded_useflag = "%s_%s" % (
+ path.split("/")[-1][0:-5],
+ fields[0],
+ )
+ global_usedesc[expanded_useflag] = fields[1]
+ except IOError:
+ sys.stderr.write(
+ pp.warn("Could not load USE flag descriptions from %s" % path)
+ )
+
+ return global_usedesc
def get_output_descriptions(pkg, global_usedesc):
- """Prepare descriptions and usage information for each USE flag."""
-
- if pkg.metadata is None:
- local_usedesc = []
- else:
- local_usedesc = pkg.metadata.use()
-
- iuse, final_use = get_flags(pkg.cpv, final_setting=True)
- usevar = reduce_flags(iuse)
- usevar.sort()
-
- if QUERY_OPTS['ignore_l10n']:
- for a in usevar[:]:
- #TODO: Remove linguas after transition to l10n is complete
- if a.startswith("l10n_") or a.startswith("linguas_"):
- usevar.remove(a)
-
-
- if pkg.is_installed():
- used_flags = pkg.use().split()
- else:
- used_flags = settings["USE"].split()
-
- # store (inuse, inused, flag, desc, restrict)
- output = []
- for flag in usevar:
- inuse = False
- inused = False
-
- local_use = None
- for use in local_usedesc:
- if use.name == flag:
- local_use = use
- break
-
- try:
- desc = local_use.description
- except AttributeError:
- try:
- desc = global_usedesc[flag]
- except KeyError:
- desc = ""
-
- try:
- restrict = local_use.restrict
- restrict = restrict if restrict is not None else ""
- except AttributeError:
- restrict = ""
-
- if flag in final_use:
- inuse = True
- if flag in used_flags:
- inused = True
-
- output.append((inuse, inused, flag, desc, restrict))
-
- return output
+ """Prepare descriptions and usage information for each USE flag."""
+
+ if pkg.metadata is None:
+ local_usedesc = []
+ else:
+ local_usedesc = pkg.metadata.use()
+
+ iuse, final_use = get_flags(pkg.cpv, final_setting=True)
+ usevar = reduce_flags(iuse)
+ usevar.sort()
+
+ if QUERY_OPTS["ignore_l10n"]:
+ for a in usevar[:]:
+ # TODO: Remove linguas after transition to l10n is complete
+ if a.startswith("l10n_") or a.startswith("linguas_"):
+ usevar.remove(a)
+
+ if pkg.is_installed():
+ used_flags = pkg.use().split()
+ else:
+ used_flags = settings["USE"].split()
+
+ # store (inuse, inused, flag, desc, restrict)
+ output = []
+ for flag in usevar:
+ inuse = False
+ inused = False
+
+ local_use = None
+ for use in local_usedesc:
+ if use.name == flag:
+ local_use = use
+ break
+
+ try:
+ desc = local_use.description
+ except AttributeError:
+ try:
+ desc = global_usedesc[flag]
+ except KeyError:
+ desc = ""
+
+ try:
+ restrict = local_use.restrict
+ restrict = restrict if restrict is not None else ""
+ except AttributeError:
+ restrict = ""
+
+ if flag in final_use:
+ inuse = True
+ if flag in used_flags:
+ inused = True
+
+ output.append((inuse, inused, flag, desc, restrict))
+
+ return output
def parse_module_options(module_opts):
- """Parse module options and update QUERY_OPTS"""
+ """Parse module options and update QUERY_OPTS"""
- opts = (x[0] for x in module_opts)
- for opt in opts:
- if opt in ('-h', '--help'):
- print_help()
- sys.exit(0)
- elif opt in ('-a', '--all'):
- QUERY_OPTS['all_versions'] = True
- elif opt in ('-i', '--ignore-l10n'):
- QUERY_OPTS['ignore_l10n'] = True
+ opts = (x[0] for x in module_opts)
+ for opt in opts:
+ if opt in ("-h", "--help"):
+ print_help()
+ sys.exit(0)
+ elif opt in ("-a", "--all"):
+ QUERY_OPTS["all_versions"] = True
+ elif opt in ("-i", "--ignore-l10n"):
+ QUERY_OPTS["ignore_l10n"] = True
def print_legend():
- """Print a legend to explain the output format."""
+ """Print a legend to explain the output format."""
- print("[ Legend : %s - final flag setting for installation]" % pp.emph("U"))
- print("[ : %s - package is installed with flag ]" % pp.emph("I"))
- print("[ Colors : %s, %s ]" % (
- pp.useflag("set", enabled=True), pp.useflag("unset", enabled=False)))
+ print("[ Legend : %s - final flag setting for installation]" % pp.emph("U"))
+ print("[ : %s - package is installed with flag ]" % pp.emph("I"))
+ print(
+ "[ Colors : %s, %s ]"
+ % (pp.useflag("set", enabled=True), pp.useflag("unset", enabled=False))
+ )
def main(input_args):
- """Parse input and run the program"""
-
- short_opts = "hai"
- long_opts = ('help', 'all', 'ignore-l10n')
-
- try:
- module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
- except GetoptError as err:
- sys.stderr.write(pp.error("Module %s" % err))
- print()
- print_help(with_description=False)
- sys.exit(2)
-
- parse_module_options(module_opts)
-
- if not queries:
- print_help()
- sys.exit(2)
-
- #
- # Output
- #
-
- first_run = True
- legend_printed = False
- for query in (Query(x) for x in queries):
- if not first_run:
- print()
-
- if QUERY_OPTS["all_versions"]:
- matches = query.find(include_masked=True)
- else:
- matches = [query.find_best()]
-
- if not any(matches):
- raise errors.GentoolkitNoMatches(query)
-
- matches.sort()
-
- global_usedesc = get_global_useflags()
- for pkg in matches:
-
- output = get_output_descriptions(pkg, global_usedesc)
- if output:
- if CONFIG['verbose']:
- if not legend_printed:
- print_legend()
- legend_printed = True
- print((" * Found these USE flags for %s:" %
- pp.cpv(str(pkg.cpv))))
- print(pp.emph(" U I"))
- display_useflags(output)
- else:
- if CONFIG['verbose']:
- sys.stderr.write(
- pp.warn("No USE flags found for %s" % pp.cpv(pkg.cpv))
- )
-
- first_run = False
+ """Parse input and run the program"""
+
+ short_opts = "hai"
+ long_opts = ("help", "all", "ignore-l10n")
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Module %s" % err))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ #
+ # Output
+ #
+
+ first_run = True
+ legend_printed = False
+ for query in (Query(x) for x in queries):
+ if not first_run:
+ print()
+
+ if QUERY_OPTS["all_versions"]:
+ matches = query.find(include_masked=True)
+ else:
+ matches = [query.find_best()]
+
+ if not any(matches):
+ raise errors.GentoolkitNoMatches(query)
+
+ matches.sort()
+
+ global_usedesc = get_global_useflags()
+ for pkg in matches:
+
+ output = get_output_descriptions(pkg, global_usedesc)
+ if output:
+ if CONFIG["verbose"]:
+ if not legend_printed:
+ print_legend()
+ legend_printed = True
+ print((" * Found these USE flags for %s:" % pp.cpv(str(pkg.cpv))))
+ print(pp.emph(" U I"))
+ display_useflags(output)
+ else:
+ if CONFIG["verbose"]:
+ sys.stderr.write(
+ pp.warn("No USE flags found for %s" % pp.cpv(pkg.cpv))
+ )
+
+ first_run = False
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/equery/which.py b/pym/gentoolkit/equery/which.py
index c7fabd7..0b726dd 100644
--- a/pym/gentoolkit/equery/which.py
+++ b/pym/gentoolkit/equery/which.py
@@ -6,7 +6,7 @@
configuration
"""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
# =======
# Imports
@@ -28,94 +28,98 @@ from portage import _encodings, _unicode_encode
# Globals
# =======
-QUERY_OPTS = {
- "include_masked": False,
- "ebuild":False
- }
+QUERY_OPTS = {"include_masked": False, "ebuild": False}
# =========
# Functions
# =========
+
def print_help(with_description=True):
- """Print description, usage and a detailed help message.
-
- @type with_description: bool
- @param with_description: if true, print module's __doc__ string
- """
-
- if with_description:
- print(__doc__.strip())
- print()
- print(mod_usage(mod_name="which"))
- print()
- print(pp.command("options"))
- print(format_options((
- (" -h, --help", "display this help message"),
- (" -m, --include-masked", "return highest version ebuild available"),
- (" -e, --ebuild", "print the ebuild")
- )))
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print(__doc__.strip())
+ print()
+ print(mod_usage(mod_name="which"))
+ print()
+ print(pp.command("options"))
+ print(
+ format_options(
+ (
+ (" -h, --help", "display this help message"),
+ (" -m, --include-masked", "return highest version ebuild available"),
+ (" -e, --ebuild", "print the ebuild"),
+ )
+ )
+ )
+
def print_ebuild(ebuild_path):
- """Output the ebuild to std_out"""
- with open(_unicode_encode(ebuild_path, encoding=_encodings['fs']),
- encoding=_encodings['content']) as f:
- lines = f.readlines()
- print("\n\n")
- print("".join(lines))
- print("\n")
+ """Output the ebuild to std_out"""
+ with open(
+ _unicode_encode(ebuild_path, encoding=_encodings["fs"]),
+ encoding=_encodings["content"],
+ ) as f:
+ lines = f.readlines()
+ print("\n\n")
+ print("".join(lines))
+ print("\n")
+
def parse_module_options(module_opts):
- """Parse module options and update QUERY_OPTS"""
+ """Parse module options and update QUERY_OPTS"""
- opts = (x[0] for x in module_opts)
- for opt in opts:
- if opt in ('-h', '--help'):
- print_help()
- sys.exit(0)
- elif opt in ('-m', '--include-masked'):
- QUERY_OPTS['include_masked'] = True
- elif opt in ('-e', '--ebuild'):
- QUERY_OPTS['ebuild'] = True
+ opts = (x[0] for x in module_opts)
+ for opt in opts:
+ if opt in ("-h", "--help"):
+ print_help()
+ sys.exit(0)
+ elif opt in ("-m", "--include-masked"):
+ QUERY_OPTS["include_masked"] = True
+ elif opt in ("-e", "--ebuild"):
+ QUERY_OPTS["ebuild"] = True
def main(input_args):
- """Parse input and run the program"""
-
- short_opts = "hme"
- long_opts = ('help', 'include-masked', 'ebuild')
-
- try:
- module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
- except GetoptError as err:
- sys.stderr.write(pp.error("Module %s" % err))
- print()
- print_help(with_description=False)
- sys.exit(2)
-
- parse_module_options(module_opts)
-
- if not queries:
- print_help()
- sys.exit(2)
-
- for query in (Query(x) for x in queries):
- matches = query.find(
- include_masked=QUERY_OPTS['include_masked'],
- in_installed=False
- )
- if matches:
- pkg = sorted(matches).pop()
- ebuild_path = pkg.ebuild_path()
- if ebuild_path:
- pp.uprint(os.path.normpath(ebuild_path))
- if QUERY_OPTS['ebuild']:
- print_ebuild(ebuild_path)
- else:
- sys.stderr.write(
- pp.warn("No ebuilds to satisfy %s" % pkg.cpv)
- )
- else:
- raise errors.GentoolkitNoMatches(query)
+ """Parse input and run the program"""
+
+ short_opts = "hme"
+ long_opts = ("help", "include-masked", "ebuild")
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Module %s" % err))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ for query in (Query(x) for x in queries):
+ matches = query.find(
+ include_masked=QUERY_OPTS["include_masked"], in_installed=False
+ )
+ if matches:
+ pkg = sorted(matches).pop()
+ ebuild_path = pkg.ebuild_path()
+ if ebuild_path:
+ pp.uprint(os.path.normpath(ebuild_path))
+ if QUERY_OPTS["ebuild"]:
+ print_ebuild(ebuild_path)
+ else:
+ sys.stderr.write(pp.warn("No ebuilds to satisfy %s" % pkg.cpv))
+ else:
+ raise errors.GentoolkitNoMatches(query)
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/errors.py b/pym/gentoolkit/errors.py
index 15fef24..ffb79e0 100644
--- a/pym/gentoolkit/errors.py
+++ b/pym/gentoolkit/errors.py
@@ -5,153 +5,170 @@
"""Exception classes for gentoolkit"""
__all__ = (
- 'GentoolkitException',
- 'GentoolkitFatalError',
- 'GentoolkitAmbiguousPackage',
- 'GentoolkitInvalidAtom',
- 'GentoolkitInvalidCategory',
- 'GentoolkitInvalidPackage',
- 'GentoolkitInvalidCPV',
- 'GentoolkitInvalidRegex',
- 'GentoolkitInvalidVersion',
- 'GentoolkitNoMatches',
- 'GentoolkitSetNotFound',
- 'GentoolkitUnknownKeyword',
- 'GentoolkitNonZeroExit'
+ "GentoolkitException",
+ "GentoolkitFatalError",
+ "GentoolkitAmbiguousPackage",
+ "GentoolkitInvalidAtom",
+ "GentoolkitInvalidCategory",
+ "GentoolkitInvalidPackage",
+ "GentoolkitInvalidCPV",
+ "GentoolkitInvalidRegex",
+ "GentoolkitInvalidVersion",
+ "GentoolkitNoMatches",
+ "GentoolkitSetNotFound",
+ "GentoolkitUnknownKeyword",
+ "GentoolkitNonZeroExit",
)
# ==========
# Exceptions
# ==========
+
class GentoolkitException(Exception):
- """Base class for gentoolkit exceptions."""
- def __init__(self, is_serious=True):
- self.is_serious = is_serious
+ """Base class for gentoolkit exceptions."""
+
+ def __init__(self, is_serious=True):
+ self.is_serious = is_serious
class GentoolkitFatalError(GentoolkitException):
- """A fatal error occurred. Usually used to catch Portage exceptions."""
- def __init__(self, err, is_serious=True):
- GentoolkitException.__init__(self, is_serious=is_serious)
- self.err = err
+ """A fatal error occurred. Usually used to catch Portage exceptions."""
- def __str__(self):
- return "Fatal error: %s" % self.err
+ def __init__(self, err, is_serious=True):
+ GentoolkitException.__init__(self, is_serious=is_serious)
+ self.err = err
+
+ def __str__(self):
+ return "Fatal error: %s" % self.err
class GentoolkitAmbiguousPackage(GentoolkitException):
- """Got an ambiguous package name."""
- def __init__(self, choices, is_serious=False):
- GentoolkitException.__init__(self, is_serious=is_serious)
- self.choices = choices
+ """Got an ambiguous package name."""
+
+ def __init__(self, choices, is_serious=False):
+ GentoolkitException.__init__(self, is_serious=is_serious)
+ self.choices = choices
- def __str__(self):
- choices = '\n'.join(" %s" % x for x in self.choices)
- return '\n'.join(("Ambiguous package name. Choose from:", choices))
+ def __str__(self):
+ choices = "\n".join(" %s" % x for x in self.choices)
+ return "\n".join(("Ambiguous package name. Choose from:", choices))
class GentoolkitInvalidAtom(GentoolkitException):
- """Got a malformed package atom."""
- def __init__(self, atom, is_serious=False):
- GentoolkitException.__init__(self, is_serious=is_serious)
- self.atom = atom
+ """Got a malformed package atom."""
- def __str__(self):
- return "Invalid atom: '%s'" % self.atom
+ def __init__(self, atom, is_serious=False):
+ GentoolkitException.__init__(self, is_serious=is_serious)
+ self.atom = atom
+
+ def __str__(self):
+ return "Invalid atom: '%s'" % self.atom
class GentoolkitSetNotFound(GentoolkitException):
- """Got unknown set."""
- def __init__(self, setname, is_serious=False):
- GentoolkitException.__init__(self, is_serious=is_serious)
- self.setname = setname
+ """Got unknown set."""
+
+ def __init__(self, setname, is_serious=False):
+ GentoolkitException.__init__(self, is_serious=is_serious)
+ self.setname = setname
- def __str__(self):
- return "Unknown set: '%s'" % self.setname
+ def __str__(self):
+ return "Unknown set: '%s'" % self.setname
class GentoolkitInvalidCategory(GentoolkitException):
- """The category was not listed in portage.settings.categories."""
- def __init__(self, category, is_serious=False):
- GentoolkitException.__init__(self, is_serious=is_serious)
- self.category = category
+ """The category was not listed in portage.settings.categories."""
- def __str__(self):
- return "Invalid category: '%s'" % self.category
+ def __init__(self, category, is_serious=False):
+ GentoolkitException.__init__(self, is_serious=is_serious)
+ self.category = category
+
+ def __str__(self):
+ return "Invalid category: '%s'" % self.category
class GentoolkitInvalidPackage(GentoolkitException):
- """Got an unknown or invalid package."""
- def __init__(self, package, is_serious=False):
- GentoolkitException.__init__(self, is_serious=is_serious)
- self.package = package
+ """Got an unknown or invalid package."""
+
+ def __init__(self, package, is_serious=False):
+ GentoolkitException.__init__(self, is_serious=is_serious)
+ self.package = package
- def __str__(self):
- return "Invalid package: '%s'" % self.package
+ def __str__(self):
+ return "Invalid package: '%s'" % self.package
class GentoolkitInvalidCPV(GentoolkitException):
- """Got an invalid category/package-ver string."""
- def __init__(self, cpv, is_serious=False):
- GentoolkitException.__init__(self, is_serious=is_serious)
- self.cpv = cpv
+ """Got an invalid category/package-ver string."""
- def __str__(self):
- return "Invalid CPV: '%s'" % self.cpv
+ def __init__(self, cpv, is_serious=False):
+ GentoolkitException.__init__(self, is_serious=is_serious)
+ self.cpv = cpv
+
+ def __str__(self):
+ return "Invalid CPV: '%s'" % self.cpv
class GentoolkitInvalidRegex(GentoolkitException):
- """The regex could not be compiled."""
- def __init__(self, regex, is_serious=False):
- GentoolkitException.__init__(self, is_serious=is_serious)
- self.regex = regex
+ """The regex could not be compiled."""
+
+ def __init__(self, regex, is_serious=False):
+ GentoolkitException.__init__(self, is_serious=is_serious)
+ self.regex = regex
- def __str__(self):
- return "Invalid regex: '%s'" % self.regex
+ def __str__(self):
+ return "Invalid regex: '%s'" % self.regex
class GentoolkitInvalidVersion(GentoolkitException):
- """Got a malformed version."""
- def __init__(self, version, is_serious=False):
- GentoolkitException.__init__(self, is_serious=is_serious)
- self.version = version
+ """Got a malformed version."""
- def __str__(self):
- return "Malformed version: '%s'" % self.version
+ def __init__(self, version, is_serious=False):
+ GentoolkitException.__init__(self, is_serious=is_serious)
+ self.version = version
+
+ def __str__(self):
+ return "Malformed version: '%s'" % self.version
class GentoolkitNoMatches(GentoolkitException):
- """No packages were found matching the search query."""
- def __init__(self, query, in_installed=False, is_serious=False):
- GentoolkitException.__init__(self, is_serious=is_serious)
- self.query = query
- self.in_installed = in_installed
+ """No packages were found matching the search query."""
+
+ def __init__(self, query, in_installed=False, is_serious=False):
+ GentoolkitException.__init__(self, is_serious=is_serious)
+ self.query = query
+ self.in_installed = in_installed
- def __str__(self):
- inst = 'installed ' if self.in_installed else ''
- return "No %spackages matching '%s'" % (inst, self.query)
+ def __str__(self):
+ inst = "installed " if self.in_installed else ""
+ return "No %spackages matching '%s'" % (inst, self.query)
class GentoolkitUnknownKeyword(GentoolkitException):
- """No packages were found matching the search query."""
- def __init__(self, query, keywords, use, is_serious=True):
- GentoolkitException.__init__(self, is_serious=is_serious)
- self.query = query
- self.keywords = keywords
- self.use = use
+ """No packages were found matching the search query."""
- def __str__(self):
- return ("Unable to determine the install keyword for:\n" +
- "'%s', KEYWORDS = '%s'\nUSE flags = '%s'"
- % (self.query, self.keywords, self.use))
+ def __init__(self, query, keywords, use, is_serious=True):
+ GentoolkitException.__init__(self, is_serious=is_serious)
+ self.query = query
+ self.keywords = keywords
+ self.use = use
+
+ def __str__(self):
+ return (
+ "Unable to determine the install keyword for:\n"
+ + "'%s', KEYWORDS = '%s'\nUSE flags = '%s'"
+ % (self.query, self.keywords, self.use)
+ )
class GentoolkitNonZeroExit(GentoolkitException):
- """Used to signal, that a non-fatal, no warning error occurred.
- The primary use case is for not returning any data."""
- def __init__(self, return_code=1, is_serious=False):
- GentoolkitException.__init__(self, is_serious=is_serious)
- self.return_code = return_code
+ """Used to signal, that a non-fatal, no warning error occurred.
+ The primary use case is for not returning any data."""
+
+ def __init__(self, return_code=1, is_serious=False):
+ GentoolkitException.__init__(self, is_serious=is_serious)
+ self.return_code = return_code
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/eshowkw/__init__.py b/pym/gentoolkit/eshowkw/__init__.py
index 707c266..ba6c076 100644
--- a/pym/gentoolkit/eshowkw/__init__.py
+++ b/pym/gentoolkit/eshowkw/__init__.py
@@ -1,8 +1,8 @@
-# vim:fileencoding=utf-8
+# vim:fileencoding=utf-8
# Copyright 2010-2016 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
-__package__ = 'gentoolkit.eshowkw'
+__package__ = "gentoolkit.eshowkw"
__version__ = "git"
__author__ = "Tomáš Chvátal <scarabeus@gentoo.org>"
@@ -20,137 +20,193 @@ from gentoolkit.eshowkw.display_pretty import display
ignore_slots = False
bold = False
-order = 'bottom'
-topper = 'versionlist'
+order = "bottom"
+topper = "versionlist"
+
def process_display(package, keywords, dbapi):
- portdata = keywords_content(package, keywords.keywords, dbapi, ignore_slots, order, bold, topper)
- if topper == 'archlist':
- header = string_rotator().rotateContent(keywords.content, keywords.length, bold)
- extra = string_rotator().rotateContent(keywords.extra, keywords.length, bold, False)
- # -1 : space is taken in account and appended by us
- filler = ''.ljust(portdata.slot_length-1)
- header = ['%s%s%s' % (x, filler, y) for x, y in zip(header, extra)]
- content = portdata.content
- header_length = portdata.version_length
- content_length = keywords.length
- else:
- header = string_rotator().rotateContent(portdata.content, portdata.content_length, bold)
- content = keywords.content
- sep = [''.ljust(keywords.length) for x in range(portdata.slot_length-1)]
- content.extend(sep)
- content.extend(keywords.extra)
- header_length = keywords.length
- content_length = portdata.version_length
- display(content, header, header_length, content_length, portdata.cp, topper)
+ portdata = keywords_content(
+ package, keywords.keywords, dbapi, ignore_slots, order, bold, topper
+ )
+ if topper == "archlist":
+ header = string_rotator().rotateContent(keywords.content, keywords.length, bold)
+ extra = string_rotator().rotateContent(
+ keywords.extra, keywords.length, bold, False
+ )
+ # -1 : space is taken in account and appended by us
+ filler = "".ljust(portdata.slot_length - 1)
+ header = ["%s%s%s" % (x, filler, y) for x, y in zip(header, extra)]
+ content = portdata.content
+ header_length = portdata.version_length
+ content_length = keywords.length
+ else:
+ header = string_rotator().rotateContent(
+ portdata.content, portdata.content_length, bold
+ )
+ content = keywords.content
+ sep = ["".ljust(keywords.length) for x in range(portdata.slot_length - 1)]
+ content.extend(sep)
+ content.extend(keywords.extra)
+ header_length = keywords.length
+ content_length = portdata.version_length
+ display(content, header, header_length, content_length, portdata.cp, topper)
+
def process_args(argv):
- """Option parsing via argc"""
- parser = argparse.ArgumentParser(prog=__package__,
- formatter_class=argparse.ArgumentDefaultsHelpFormatter,
- description='Display keywords for specified package or for package that is in pwd.')
-
- parser.add_argument('-v', '--version', action='version', version=__version__, help='show package version and exit')
-
- parser.add_argument('package', nargs='*', default=None, help='Packages to check.')
-
- parser.add_argument('-a', '--arch', nargs=1, default=[], help='Display only specified arch(s)')
-
- parser.add_argument('-A', '--align', nargs='?', default='bottom', choices=['top', 'bottom'],
- help='Specify alignment for descriptions.')
- parser.add_argument('-T', '--top-position', nargs='?', default='archlist', choices=['archlist', 'versionlist'],
- help='Specify which fields we want to have in top listing.')
-
- parser.add_argument('-B', '--bold', action='store_true', default=False,
- help='Print out each other column in bold for easier visual separation.')
- parser.add_argument('-C', '--color', action='store_true', default=False,
- help='Force colored output')
- parser.add_argument('-O', '--overlays', action='store_true', default=False,
- help='Search also overlays')
- parser.add_argument('-P', '--prefix', action='store_true', default=False,
- help='Display prefix keywords in output.')
- parser.add_argument('-S', '--ignore-slot', action='store_true', default=False,
- help='Treat slots as irelevant during detection of redundant packages.')
-
- return parser.parse_args(args=argv)
-
-def main(argv, indirect = False):
- global ignore_slots, bold, order, topper
-
- #opts parsing
- opts = process_args(argv)
- ignore_slots = opts.ignore_slot
- use_overlays = opts.overlays
- highlight_arch = ''.join(opts.arch).split(',')
- bold = opts.bold
- order = opts.align
- topper = opts.top_position
- prefix = opts.prefix
- color = opts.color
- package = opts.package
-
- # equery support
- if indirect and len(package) <= 0:
- msg_err = 'No packages specified'
- raise SystemExit(msg_err)
-
- # disable colors when redirected and they are not forced on
- if not color and not sys.stdout.isatty():
- # disable colors
- porto.nocolor()
-
- # Imply prefix if user specified any architectures (Bug 578496)
- if len(opts.arch) > 0:
- prefix = True
-
- keywords = keywords_header(prefix, highlight_arch, order)
- if len(package) > 0:
- mysettings = portc(local_config=False)
- dbapi = portdbapi(mysettings=mysettings)
- if not use_overlays:
- dbapi.porttrees = [dbapi.porttree_root]
- for pkg in package:
- process_display(pkg, keywords, dbapi)
- else:
- currdir = os.getcwd()
- # check if there are actualy some ebuilds
- ebuilds = ['%s' % x for x in os.listdir(currdir)
- if fnmatch.fnmatch(x, '*.ebuild')]
- if len(ebuilds) <= 0:
- msg_err = 'No ebuilds at "%s"' % currdir
- raise SystemExit(msg_err)
- package= '%s/%s' % (os.path.basename(os.path.abspath('../')), os.path.basename(currdir))
- ourtree = os.path.realpath('../..')
- ourstat = os.stat(ourtree)
- ourstat = (ourstat.st_ino, ourstat.st_dev)
- for repo in ports.repositories:
- try:
- repostat = os.stat(repo.location)
- except OSError:
- continue
- if ourstat == (repostat.st_ino, repostat.st_dev):
- dbapi = portdbapi(mysettings=portc(local_config=False))
- break
- else:
- repos = {}
- for repo in ports.repositories:
- repos[repo.name] = repo.location
-
- with open(os.path.join(ourtree, 'profiles', 'repo_name'),
- 'rt') as f:
- repo_name = f.readline().strip()
-
- repos[repo_name] = ourtree
- repos = ''.join('[{}]\nlocation={}\n'.format(k, v)
- for k, v in repos.items())
- mysettings = portc(local_config=False,
- env={'PORTAGE_REPOSITORIES': repos})
- dbapi = portdbapi(mysettings=mysettings)
- # specify that we want just our nice tree we are in cwd
- dbapi.porttrees = [ourtree]
- process_display(package, keywords, dbapi)
- return 0
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
+ """Option parsing via argc"""
+ parser = argparse.ArgumentParser(
+ prog=__package__,
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+ description="Display keywords for specified package or for package that is in pwd.",
+ )
+
+ parser.add_argument(
+ "-v",
+ "--version",
+ action="version",
+ version=__version__,
+ help="show package version and exit",
+ )
+
+ parser.add_argument("package", nargs="*", default=None, help="Packages to check.")
+
+ parser.add_argument(
+ "-a", "--arch", nargs=1, default=[], help="Display only specified arch(s)"
+ )
+
+ parser.add_argument(
+ "-A",
+ "--align",
+ nargs="?",
+ default="bottom",
+ choices=["top", "bottom"],
+ help="Specify alignment for descriptions.",
+ )
+ parser.add_argument(
+ "-T",
+ "--top-position",
+ nargs="?",
+ default="archlist",
+ choices=["archlist", "versionlist"],
+ help="Specify which fields we want to have in top listing.",
+ )
+
+ parser.add_argument(
+ "-B",
+ "--bold",
+ action="store_true",
+ default=False,
+ help="Print out each other column in bold for easier visual separation.",
+ )
+ parser.add_argument(
+ "-C", "--color", action="store_true", default=False, help="Force colored output"
+ )
+ parser.add_argument(
+ "-O",
+ "--overlays",
+ action="store_true",
+ default=False,
+ help="Search also overlays",
+ )
+ parser.add_argument(
+ "-P",
+ "--prefix",
+ action="store_true",
+ default=False,
+ help="Display prefix keywords in output.",
+ )
+ parser.add_argument(
+ "-S",
+ "--ignore-slot",
+ action="store_true",
+ default=False,
+ help="Treat slots as irelevant during detection of redundant packages.",
+ )
+
+ return parser.parse_args(args=argv)
+
+
+def main(argv, indirect=False):
+ global ignore_slots, bold, order, topper
+
+ # opts parsing
+ opts = process_args(argv)
+ ignore_slots = opts.ignore_slot
+ use_overlays = opts.overlays
+ highlight_arch = "".join(opts.arch).split(",")
+ bold = opts.bold
+ order = opts.align
+ topper = opts.top_position
+ prefix = opts.prefix
+ color = opts.color
+ package = opts.package
+
+ # equery support
+ if indirect and len(package) <= 0:
+ msg_err = "No packages specified"
+ raise SystemExit(msg_err)
+
+ # disable colors when redirected and they are not forced on
+ if not color and not sys.stdout.isatty():
+ # disable colors
+ porto.nocolor()
+
+ # Imply prefix if user specified any architectures (Bug 578496)
+ if len(opts.arch) > 0:
+ prefix = True
+
+ keywords = keywords_header(prefix, highlight_arch, order)
+ if len(package) > 0:
+ mysettings = portc(local_config=False)
+ dbapi = portdbapi(mysettings=mysettings)
+ if not use_overlays:
+ dbapi.porttrees = [dbapi.porttree_root]
+ for pkg in package:
+ process_display(pkg, keywords, dbapi)
+ else:
+ currdir = os.getcwd()
+ # check if there are actualy some ebuilds
+ ebuilds = [
+ "%s" % x for x in os.listdir(currdir) if fnmatch.fnmatch(x, "*.ebuild")
+ ]
+ if len(ebuilds) <= 0:
+ msg_err = 'No ebuilds at "%s"' % currdir
+ raise SystemExit(msg_err)
+ package = "%s/%s" % (
+ os.path.basename(os.path.abspath("../")),
+ os.path.basename(currdir),
+ )
+ ourtree = os.path.realpath("../..")
+ ourstat = os.stat(ourtree)
+ ourstat = (ourstat.st_ino, ourstat.st_dev)
+ for repo in ports.repositories:
+ try:
+ repostat = os.stat(repo.location)
+ except OSError:
+ continue
+ if ourstat == (repostat.st_ino, repostat.st_dev):
+ dbapi = portdbapi(mysettings=portc(local_config=False))
+ break
+ else:
+ repos = {}
+ for repo in ports.repositories:
+ repos[repo.name] = repo.location
+
+ with open(os.path.join(ourtree, "profiles", "repo_name"), "rt") as f:
+ repo_name = f.readline().strip()
+
+ repos[repo_name] = ourtree
+ repos = "".join(
+ "[{}]\nlocation={}\n".format(k, v) for k, v in repos.items()
+ )
+ mysettings = portc(local_config=False, env={"PORTAGE_REPOSITORIES": repos})
+ dbapi = portdbapi(mysettings=mysettings)
+ # specify that we want just our nice tree we are in cwd
+ dbapi.porttrees = [ourtree]
+ process_display(package, keywords, dbapi)
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv[1:]))
diff --git a/pym/gentoolkit/eshowkw/display_pretty.py b/pym/gentoolkit/eshowkw/display_pretty.py
index beca5f4..d58036a 100644
--- a/pym/gentoolkit/eshowkw/display_pretty.py
+++ b/pym/gentoolkit/eshowkw/display_pretty.py
@@ -1,106 +1,130 @@
-# vim:fileencoding=utf-8
+# vim:fileencoding=utf-8
# Copyright 2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
from portage.output import colorize
-try: # newer python versions
- from itertools import zip_longest
-except ImportError: # older python naming
- from itertools import izip_longest as zip_longest
-
-__all__ = ['string_rotator', 'colorize_string', 'align_string', 'rotate_dash', 'print_content', 'display']
-
-def display(plain_list, rotated_list, plain_width, rotated_height, cp, toplist = 'archlist'):
- """Render defauld display to show the keywords listing"""
- # header
- output = []
- output.append('Keywords for %s:' % colorize('blue', cp))
- # data
- corner_image = [''.ljust(plain_width) for x in range(rotated_height)]
- if toplist != 'archlist':
- corner_image.extend(plain_list)
- data_printout = ['%s%s' % (x, y)
- for x, y in zip_longest(corner_image, rotated_list, fillvalue=corner_image[0])]
- if toplist == 'archlist':
- data_printout.extend(plain_list)
- output.extend(data_printout)
- print(print_content(output))
+
+try: # newer python versions
+ from itertools import zip_longest
+except ImportError: # older python naming
+ from itertools import izip_longest as zip_longest
+
+__all__ = [
+ "string_rotator",
+ "colorize_string",
+ "align_string",
+ "rotate_dash",
+ "print_content",
+ "display",
+]
+
+
+def display(
+ plain_list, rotated_list, plain_width, rotated_height, cp, toplist="archlist"
+):
+ """Render defauld display to show the keywords listing"""
+ # header
+ output = []
+ output.append("Keywords for %s:" % colorize("blue", cp))
+ # data
+ corner_image = ["".ljust(plain_width) for x in range(rotated_height)]
+ if toplist != "archlist":
+ corner_image.extend(plain_list)
+ data_printout = [
+ "%s%s" % (x, y)
+ for x, y in zip_longest(corner_image, rotated_list, fillvalue=corner_image[0])
+ ]
+ if toplist == "archlist":
+ data_printout.extend(plain_list)
+ output.extend(data_printout)
+ print(print_content(output))
+
def align_string(string, align, length):
- """Align string to the specified alignment (left or right, and after rotation it becomes top and bottom)"""
- if align == 'top' or align == 'left':
- string = string.ljust(length)
- else:
- string = string.rjust(length)
- return string
+ """Align string to the specified alignment (left or right, and after rotation it becomes top and bottom)"""
+ if align == "top" or align == "left":
+ string = string.ljust(length)
+ else:
+ string = string.rjust(length)
+ return string
+
def colorize_string(color, string):
- """Add coloring for specified string. Due to rotation we need to do that per character rather than per-line"""
- tmp = []
- for char in list(string):
- # % is whitespace separator so we wont color that :)
- if char != '%':
- tmp.append(colorize(color, char))
- else:
- tmp.append(char)
- return ''.join(tmp)
+ """Add coloring for specified string. Due to rotation we need to do that per character rather than per-line"""
+ tmp = []
+ for char in list(string):
+ # % is whitespace separator so we wont color that :)
+ if char != "%":
+ tmp.append(colorize(color, char))
+ else:
+ tmp.append(char)
+ return "".join(tmp)
+
def rotate_dash(string):
- """Rotate special strings over 90 degrees for better readability."""
- chars = ['-', '|']
- subs = ['|', '-']
- out = string
- for x,y in zip(chars, subs):
- if string.find(x) != -1:
- out = out.replace(x, y)
- return out
+ """Rotate special strings over 90 degrees for better readability."""
+ chars = ["-", "|"]
+ subs = ["|", "-"]
+ out = string
+ for x, y in zip(chars, subs):
+ if string.find(x) != -1:
+ out = out.replace(x, y)
+ return out
+
def print_content(content):
- """Print out content (strip it out of the temporary %)"""
- return '\n'.join(content).replace('%','')
+ """Print out content (strip it out of the temporary %)"""
+ return "\n".join(content).replace("%", "")
+
class string_rotator:
- __DASH_COUNT = 0
- def __getChar(self, string, position, line, bold_separator = False):
- """Return specified character from the string position"""
-
- # first figure out what character we want to work with
- # based on order and position in the string
- isdash = False
- if string.startswith('|') or string.startswith('-') or string.startswith('+'):
- split = list(string)
- isdash = True
- self.__DASH_COUNT += 1
- else:
- split = string.split('%')
- char = split[position]
- # bolding
- if not isdash and bold_separator \
- and (line-self.__DASH_COUNT)%2 == 0 \
- and char != ' ':
- char = colorize('bold', char)
- return char
-
- def rotateContent(self, elements, length, bold_separator = False, strip = True):
- """
- Rotate string over 90 degrees:
- string -> s
- t
- r
- i
- n
- g
- """
- # join used to have list of lines rather than list of chars
- tmp = []
- for position in range(length):
- x = ''
- for i, string in enumerate(elements):
- x += ' ' + self.__getChar(rotate_dash(string), position, i, bold_separator)
- # spaces on dashed line should be dashed too
- if x.find('+ -') != -1:
- x = x.replace(' ', '-')
- # strip all chars and remove empty lines
- if not strip or len(x.strip(' |-')) > 0:
- tmp.append(x)
- return tmp
+ __DASH_COUNT = 0
+
+ def __getChar(self, string, position, line, bold_separator=False):
+ """Return specified character from the string position"""
+
+ # first figure out what character we want to work with
+ # based on order and position in the string
+ isdash = False
+ if string.startswith("|") or string.startswith("-") or string.startswith("+"):
+ split = list(string)
+ isdash = True
+ self.__DASH_COUNT += 1
+ else:
+ split = string.split("%")
+ char = split[position]
+ # bolding
+ if (
+ not isdash
+ and bold_separator
+ and (line - self.__DASH_COUNT) % 2 == 0
+ and char != " "
+ ):
+ char = colorize("bold", char)
+ return char
+
+ def rotateContent(self, elements, length, bold_separator=False, strip=True):
+ """
+ Rotate string over 90 degrees:
+ string -> s
+ t
+ r
+ i
+ n
+ g
+ """
+ # join used to have list of lines rather than list of chars
+ tmp = []
+ for position in range(length):
+ x = ""
+ for i, string in enumerate(elements):
+ x += " " + self.__getChar(
+ rotate_dash(string), position, i, bold_separator
+ )
+ # spaces on dashed line should be dashed too
+ if x.find("+ -") != -1:
+ x = x.replace(" ", "-")
+ # strip all chars and remove empty lines
+ if not strip or len(x.strip(" |-")) > 0:
+ tmp.append(x)
+ return tmp
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])
diff --git a/pym/gentoolkit/eshowkw/keywords_header.py b/pym/gentoolkit/eshowkw/keywords_header.py
index 00ecb27..5ca892e 100644
--- a/pym/gentoolkit/eshowkw/keywords_header.py
+++ b/pym/gentoolkit/eshowkw/keywords_header.py
@@ -1,8 +1,8 @@
-# vim:fileencoding=utf-8
+# vim:fileencoding=utf-8
# Copyright 2001-2018 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
-__all__ = ['keywords_header']
+__all__ = ["keywords_header"]
from portage import settings as ports
from gentoolkit.eshowkw.display_pretty import colorize_string
@@ -11,136 +11,143 @@ from gentoolkit.profile import load_profile_data
def gen_arch_list(status):
- _arch_status = load_profile_data()
- if status == "stable":
- return [arch for arch in _arch_status if _arch_status[arch][0] == "stable"]
- elif status == "dev":
- return [arch for arch in _arch_status if _arch_status[arch][0] == "dev"]
- elif status == "exp":
- return [arch for arch in _arch_status if _arch_status[arch][0] == "exp"]
- elif status == "arch":
- return [arch for arch in _arch_status if _arch_status[arch][1] == "arch"]
- elif status == "~arch":
- return [arch for arch in _arch_status if _arch_status[arch][1] == "~arch"]
- else:
- raise TypeError
+ _arch_status = load_profile_data()
+ if status == "stable":
+ return [arch for arch in _arch_status if _arch_status[arch][0] == "stable"]
+ elif status == "dev":
+ return [arch for arch in _arch_status if _arch_status[arch][0] == "dev"]
+ elif status == "exp":
+ return [arch for arch in _arch_status if _arch_status[arch][0] == "exp"]
+ elif status == "arch":
+ return [arch for arch in _arch_status if _arch_status[arch][1] == "arch"]
+ elif status == "~arch":
+ return [arch for arch in _arch_status if _arch_status[arch][1] == "~arch"]
+ else:
+ raise TypeError
+
class keywords_header:
- __IMPARCHS = gen_arch_list("stable")
- __DEV_ARCHS = gen_arch_list("dev")
- __EXP_ARCHS = gen_arch_list("exp")
- __TESTING_KW_ARCHS = gen_arch_list("~arch")
- __ADDITIONAL_FIELDS = [ 'eapi', 'unused', 'slot' ]
- __EXTRA_FIELDS = [ 'repo' ]
-
- @staticmethod
- def __readKeywords():
- """Read all available keywords from portage."""
- return [x for x in ports.archlist()
- if not x.startswith('~')]
-
- @staticmethod
- def __isPrefix(k):
- spl = k.split('-')
- # *-fbsd are not prefix
- return len(spl) > 1 and spl[1] != 'fbsd'
-
- def __sortKeywords(self, keywords, prefix = False, required_keywords = []):
- """Sort keywords: order by status (IMP, then DEV, then EXP, then
- prefix), then by name."""
-
- # user specified only some keywords to display
- if len(required_keywords) != 0:
- tmpkeywords = [k for k in keywords
- if k in required_keywords]
- # idiots might specify non-existant archs
- if len(tmpkeywords) != 0:
- keywords = tmpkeywords
-
- normal = [k for k in keywords if not self.__isPrefix(k)]
- if prefix:
- longer = [k for k in keywords if self.__isPrefix(k)]
- normal.extend(longer)
-
- lists = (self.__IMPARCHS + self.__DEV_ARCHS), self.__EXP_ARCHS
- levels = {}
- for kw in normal:
- for level, ls in enumerate(lists):
- if kw in ls:
- levels[kw] = level
- break
-
- # sort by, in order (to match Bugzilla):
- # 1. non-prefix, then prefix (stable output between -P and not)
- # 2. arch, then ~arch
- # 3. profile stability
- # 4. short keywords, then long (prefix, fbsd)
- # 5. keyword name in reverse component order
- normal.sort(key=lambda kw: (self.__isPrefix(kw),
- kw in self.__TESTING_KW_ARCHS,
- levels.get(kw, 99),
- kw.count('-'),
- list(reversed(kw.split('-')))))
- return normal
-
- def __readAdditionalFields(self):
- """Prepare list of aditional fileds displayed by eshowkw (2nd part)"""
- return self.__ADDITIONAL_FIELDS
-
- def __readExtraFields(self):
- """Prepare list of extra fileds displayed by eshowkw (3rd part)"""
- return self.__EXTRA_FIELDS
-
- def __formatKeywords(self, keywords, align, length):
- """Append colors and align keywords properly"""
- tmp = []
- for keyword in keywords:
- tmp2 = keyword
- keyword = align_string(keyword, align, length)
- # % are used as separators for further split so we wont loose spaces and coloring
- keyword = '%'.join(list(keyword))
- if tmp2 in self.__IMPARCHS:
- tmp.append(colorize_string('darkyellow', keyword))
- elif tmp2 in self.__EXP_ARCHS:
- tmp.append(colorize_string('darkgray', keyword))
- else:
- tmp.append(keyword)
- return tmp
-
- @staticmethod
- def __formatAdditional(additional, align, length):
- """Align additional items properly"""
- # % are used as separators for further split so we wont loose spaces and coloring
- return ['%'.join(align_string(x, align, length)) for x in additional]
-
- def __prepareExtra(self, extra, align, length):
- content = []
- content.append(''.ljust(length, '-'))
- content.extend(self.__formatAdditional(extra, align, length))
- return content
-
- def __prepareResult(self, keywords, additional, align, length):
- """Parse keywords and additional fields into one list with proper separators"""
- content = []
- content.append(''.ljust(length, '-'))
- content.extend(self.__formatKeywords(keywords, align, length))
- content.append(''.ljust(length, '-'))
- content.extend(self.__formatAdditional(additional, align, length))
- return content
-
- def __init__(self, prefix = False, required_keywords = [], keywords_align = 'bottom'):
- """Initialize keywords header."""
- additional = self.__readAdditionalFields()
- extra = self.__readExtraFields()
- self.keywords = self.__sortKeywords(self.__readKeywords(), prefix, required_keywords)
- self.length = max(
- max([len(x) for x in self.keywords]),
- max([len(x) for x in additional]),
- max([len(x) for x in extra])
- )
- #len(max([max(self.keywords, key=len), max(additional, key=len)], key=len))
- self.keywords_count = len(self.keywords)
- self.additional_count = len(additional)
- self.extra_count = len(extra)
- self.content = self.__prepareResult(self.keywords, additional, keywords_align, self.length)
- self.extra = self.__prepareExtra(extra, keywords_align, self.length)
+ __IMPARCHS = gen_arch_list("stable")
+ __DEV_ARCHS = gen_arch_list("dev")
+ __EXP_ARCHS = gen_arch_list("exp")
+ __TESTING_KW_ARCHS = gen_arch_list("~arch")
+ __ADDITIONAL_FIELDS = ["eapi", "unused", "slot"]
+ __EXTRA_FIELDS = ["repo"]
+
+ @staticmethod
+ def __readKeywords():
+ """Read all available keywords from portage."""
+ return [x for x in ports.archlist() if not x.startswith("~")]
+
+ @staticmethod
+ def __isPrefix(k):
+ spl = k.split("-")
+ # *-fbsd are not prefix
+ return len(spl) > 1 and spl[1] != "fbsd"
+
+ def __sortKeywords(self, keywords, prefix=False, required_keywords=[]):
+ """Sort keywords: order by status (IMP, then DEV, then EXP, then
+ prefix), then by name."""
+
+ # user specified only some keywords to display
+ if len(required_keywords) != 0:
+ tmpkeywords = [k for k in keywords if k in required_keywords]
+ # idiots might specify non-existant archs
+ if len(tmpkeywords) != 0:
+ keywords = tmpkeywords
+
+ normal = [k for k in keywords if not self.__isPrefix(k)]
+ if prefix:
+ longer = [k for k in keywords if self.__isPrefix(k)]
+ normal.extend(longer)
+
+ lists = (self.__IMPARCHS + self.__DEV_ARCHS), self.__EXP_ARCHS
+ levels = {}
+ for kw in normal:
+ for level, ls in enumerate(lists):
+ if kw in ls:
+ levels[kw] = level
+ break
+
+ # sort by, in order (to match Bugzilla):
+ # 1. non-prefix, then prefix (stable output between -P and not)
+ # 2. arch, then ~arch
+ # 3. profile stability
+ # 4. short keywords, then long (prefix, fbsd)
+ # 5. keyword name in reverse component order
+ normal.sort(
+ key=lambda kw: (
+ self.__isPrefix(kw),
+ kw in self.__TESTING_KW_ARCHS,
+ levels.get(kw, 99),
+ kw.count("-"),
+ list(reversed(kw.split("-"))),
+ )
+ )
+ return normal
+
+ def __readAdditionalFields(self):
+ """Prepare list of aditional fileds displayed by eshowkw (2nd part)"""
+ return self.__ADDITIONAL_FIELDS
+
+ def __readExtraFields(self):
+ """Prepare list of extra fileds displayed by eshowkw (3rd part)"""
+ return self.__EXTRA_FIELDS
+
+ def __formatKeywords(self, keywords, align, length):
+ """Append colors and align keywords properly"""
+ tmp = []
+ for keyword in keywords:
+ tmp2 = keyword
+ keyword = align_string(keyword, align, length)
+ # % are used as separators for further split so we wont loose spaces and coloring
+ keyword = "%".join(list(keyword))
+ if tmp2 in self.__IMPARCHS:
+ tmp.append(colorize_string("darkyellow", keyword))
+ elif tmp2 in self.__EXP_ARCHS:
+ tmp.append(colorize_string("darkgray", keyword))
+ else:
+ tmp.append(keyword)
+ return tmp
+
+ @staticmethod
+ def __formatAdditional(additional, align, length):
+ """Align additional items properly"""
+ # % are used as separators for further split so we wont loose spaces and coloring
+ return ["%".join(align_string(x, align, length)) for x in additional]
+
+ def __prepareExtra(self, extra, align, length):
+ content = []
+ content.append("".ljust(length, "-"))
+ content.extend(self.__formatAdditional(extra, align, length))
+ return content
+
+ def __prepareResult(self, keywords, additional, align, length):
+ """Parse keywords and additional fields into one list with proper separators"""
+ content = []
+ content.append("".ljust(length, "-"))
+ content.extend(self.__formatKeywords(keywords, align, length))
+ content.append("".ljust(length, "-"))
+ content.extend(self.__formatAdditional(additional, align, length))
+ return content
+
+ def __init__(self, prefix=False, required_keywords=[], keywords_align="bottom"):
+ """Initialize keywords header."""
+ additional = self.__readAdditionalFields()
+ extra = self.__readExtraFields()
+ self.keywords = self.__sortKeywords(
+ self.__readKeywords(), prefix, required_keywords
+ )
+ self.length = max(
+ max([len(x) for x in self.keywords]),
+ max([len(x) for x in additional]),
+ max([len(x) for x in extra]),
+ )
+ # len(max([max(self.keywords, key=len), max(additional, key=len)], key=len))
+ self.keywords_count = len(self.keywords)
+ self.additional_count = len(additional)
+ self.extra_count = len(extra)
+ self.content = self.__prepareResult(
+ self.keywords, additional, keywords_align, self.length
+ )
+ self.extra = self.__prepareExtra(extra, keywords_align, self.length)
diff --git a/pym/gentoolkit/flag.py b/pym/gentoolkit/flag.py
index 42e8196..20ba855 100644
--- a/pym/gentoolkit/flag.py
+++ b/pym/gentoolkit/flag.py
@@ -9,14 +9,14 @@
__all__ = (
- 'get_iuse',
- 'get_installed_use',
- 'reduce_flag',
- 'reduce_flags',
- 'defaulted_flags',
- 'filter_flags',
- 'get_all_cpv_use',
- 'get_flags'
+ "get_iuse",
+ "get_installed_use",
+ "reduce_flag",
+ "reduce_flags",
+ "defaulted_flags",
+ "filter_flags",
+ "get_all_cpv_use",
+ "get_flags",
)
@@ -24,156 +24,160 @@ import portage
def get_iuse(cpv):
- """Gets the current IUSE flags from the tree
-
- To be used when a gentoolkit package object is not needed
- @type: cpv: string
- @param cpv: cat/pkg-ver
- @rtype list
- @returns [] or the list of IUSE flags
- """
- try:
- # aux_get might return dupes, so run them through set() to remove them
- iuse = set(portage.db[portage.root]["porttree"].dbapi.aux_get(cpv, ["IUSE"])[0].split())
- # there could still be dupes due to IUSE defaults
- iuse = [x for x in iuse if '+'+x not in iuse and '-'+x not in iuse]
- return list(iuse)
- except:
- return []
+ """Gets the current IUSE flags from the tree
+
+ To be used when a gentoolkit package object is not needed
+ @type: cpv: string
+ @param cpv: cat/pkg-ver
+ @rtype list
+ @returns [] or the list of IUSE flags
+ """
+ try:
+ # aux_get might return dupes, so run them through set() to remove them
+ iuse = set(
+ portage.db[portage.root]["porttree"].dbapi.aux_get(cpv, ["IUSE"])[0].split()
+ )
+ # there could still be dupes due to IUSE defaults
+ iuse = [x for x in iuse if "+" + x not in iuse and "-" + x not in iuse]
+ return list(iuse)
+ except:
+ return []
def get_installed_use(cpv, use="USE"):
- """Gets the installed USE flags from the VARDB
+ """Gets the installed USE flags from the VARDB
- To be used when a gentoolkit package object is not needed
- @type: cpv: string
- @param cpv: cat/pkg-ver
- @type use: string
- @param use: 1 of ["USE", "PKGUSE"]
- @rtype list
- @returns [] or the list of IUSE flags
- """
- return portage.db[portage.root]["vartree"].dbapi.aux_get(cpv,[use])[0].split()
+ To be used when a gentoolkit package object is not needed
+ @type: cpv: string
+ @param cpv: cat/pkg-ver
+ @type use: string
+ @param use: 1 of ["USE", "PKGUSE"]
+ @rtype list
+ @returns [] or the list of IUSE flags
+ """
+ return portage.db[portage.root]["vartree"].dbapi.aux_get(cpv, [use])[0].split()
def reduce_flag(flag):
- """Absolute value function for a USE flag
+ """Absolute value function for a USE flag
- @type flag: string
- @param flag: the use flag to absolute.
- @rtype: string
- @return absolute USE flag
- """
- if flag[0] in ["+","-"]:
- return flag[1:]
- else:
- return flag
+ @type flag: string
+ @param flag: the use flag to absolute.
+ @rtype: string
+ @return absolute USE flag
+ """
+ if flag[0] in ["+", "-"]:
+ return flag[1:]
+ else:
+ return flag
def reduce_flags(the_list):
- """Absolute value function for a USE flag list
+ """Absolute value function for a USE flag list
- @type the_list: list
- @param the_list: the use flags to absolute.
- @rtype: list
- @return absolute USE flags
- """
- r=[]
- for member in the_list:
- r.append(reduce_flag(member))
- return r
+ @type the_list: list
+ @param the_list: the use flags to absolute.
+ @rtype: list
+ @return absolute USE flags
+ """
+ r = []
+ for member in the_list:
+ r.append(reduce_flag(member))
+ return r
def defaulted_flags(the_list):
- """Absolute value function for a USE flag list
+ """Absolute value function for a USE flag list
- @type the_list: list
- @param the_list: the use flags to get defaulted ones from.
- @rtype: dict of lists
- @return defaulted USE flags {'+': [...], '-': [...]}
- """
- r={"+":[], "-": []}
- for member in the_list:
- if member[0] in ["+","-"]:
- r[member[0]].append(member[1:])
- return r
+ @type the_list: list
+ @param the_list: the use flags to get defaulted ones from.
+ @rtype: dict of lists
+ @return defaulted USE flags {'+': [...], '-': [...]}
+ """
+ r = {"+": [], "-": []}
+ for member in the_list:
+ if member[0] in ["+", "-"]:
+ r[member[0]].append(member[1:])
+ return r
def filter_flags(use, use_expand_hidden, usemasked, useforced):
- """Filter function to remove hidden or otherwise not normally
- visible USE flags from a list.
-
- @type use: list
- @param use: the USE flag list to be filtered.
- @type use_expand_hidden: list
- @param use_expand_hidden: list of flags hidden.
- @type usemasked: list
- @param usemasked: list of masked USE flags.
- @type useforced: list
- @param useforced: the forced USE flags.
- @rtype: list
- @return the filtered USE flags.
- """
- # clean out some environment flags, since they will most probably
- # be confusing for the user
- use = dict((reduce_flag(flag), flag) for flag in use)
- for f in use_expand_hidden:
- f=f.lower() + "_"
- for x in list(use):
- if x.startswith(f):
- del use[x]
- # clean out any arch's
- archlist = portage.settings["PORTAGE_ARCHLIST"].split()
- for a in archlist:
- use.pop(a, None)
- # dbl check if any from usemasked or useforced are still there
- masked = usemasked + useforced
- for a in masked:
- use.pop(a, None)
- return list(use.values())
+ """Filter function to remove hidden or otherwise not normally
+ visible USE flags from a list.
+
+ @type use: list
+ @param use: the USE flag list to be filtered.
+ @type use_expand_hidden: list
+ @param use_expand_hidden: list of flags hidden.
+ @type usemasked: list
+ @param usemasked: list of masked USE flags.
+ @type useforced: list
+ @param useforced: the forced USE flags.
+ @rtype: list
+ @return the filtered USE flags.
+ """
+ # clean out some environment flags, since they will most probably
+ # be confusing for the user
+ use = dict((reduce_flag(flag), flag) for flag in use)
+ for f in use_expand_hidden:
+ f = f.lower() + "_"
+ for x in list(use):
+ if x.startswith(f):
+ del use[x]
+ # clean out any arch's
+ archlist = portage.settings["PORTAGE_ARCHLIST"].split()
+ for a in archlist:
+ use.pop(a, None)
+ # dbl check if any from usemasked or useforced are still there
+ masked = usemasked + useforced
+ for a in masked:
+ use.pop(a, None)
+ return list(use.values())
def get_all_cpv_use(cpv):
- """Uses portage to determine final USE flags and settings for an emerge
-
- @type cpv: string
- @param cpv: eg cat/pkg-ver
- @rtype: lists
- @return use, use_expand_hidden, usemask, useforce
- """
- use = None
- portage.db[portage.root]["porttree"].dbapi.settings.unlock()
- try:
- portage.db[portage.root]["porttree"].dbapi.settings.setcpv(cpv, mydb=portage.portdb)
- use = portage.settings['PORTAGE_USE'].split()
- use_expand_hidden = portage.settings["USE_EXPAND_HIDDEN"].split()
- usemask = list(portage.db[portage.root]["porttree"].dbapi.settings.usemask)
- useforce = list(portage.db[portage.root]["porttree"].dbapi.settings.useforce)
- except KeyError:
- portage.db[portage.root]["porttree"].dbapi.settings.reset()
- portage.db[portage.root]["porttree"].dbapi.settings.lock()
- return [], [], [], []
- # reset cpv filter
- portage.db[portage.root]["porttree"].dbapi.settings.reset()
- portage.db[portage.root]["porttree"].dbapi.settings.lock()
- return use, use_expand_hidden, usemask, useforce
+ """Uses portage to determine final USE flags and settings for an emerge
+
+ @type cpv: string
+ @param cpv: eg cat/pkg-ver
+ @rtype: lists
+ @return use, use_expand_hidden, usemask, useforce
+ """
+ use = None
+ portage.db[portage.root]["porttree"].dbapi.settings.unlock()
+ try:
+ portage.db[portage.root]["porttree"].dbapi.settings.setcpv(
+ cpv, mydb=portage.portdb
+ )
+ use = portage.settings["PORTAGE_USE"].split()
+ use_expand_hidden = portage.settings["USE_EXPAND_HIDDEN"].split()
+ usemask = list(portage.db[portage.root]["porttree"].dbapi.settings.usemask)
+ useforce = list(portage.db[portage.root]["porttree"].dbapi.settings.useforce)
+ except KeyError:
+ portage.db[portage.root]["porttree"].dbapi.settings.reset()
+ portage.db[portage.root]["porttree"].dbapi.settings.lock()
+ return [], [], [], []
+ # reset cpv filter
+ portage.db[portage.root]["porttree"].dbapi.settings.reset()
+ portage.db[portage.root]["porttree"].dbapi.settings.lock()
+ return use, use_expand_hidden, usemask, useforce
def get_flags(cpv, final_setting=False):
- """Retrieves all information needed to filter out hidded, masked, etc.
- USE flags for a given package.
-
- @type cpv: string
- @param cpv: eg. cat/pkg-ver
- @type final_setting: boolean
- @param final_setting: used to also determine the final
- enviroment USE flag settings and return them as well.
- @rtype: list or list, list
- @return IUSE or IUSE, final_flags
- """
- final_use, use_expand_hidden, usemasked, useforced = get_all_cpv_use(cpv)
- iuse_flags = filter_flags(get_iuse(cpv), use_expand_hidden, usemasked, useforced)
- if final_setting:
- final_flags = filter_flags(final_use, use_expand_hidden, usemasked, useforced)
- return iuse_flags, final_flags
- return iuse_flags
+ """Retrieves all information needed to filter out hidded, masked, etc.
+ USE flags for a given package.
+
+ @type cpv: string
+ @param cpv: eg. cat/pkg-ver
+ @type final_setting: boolean
+ @param final_setting: used to also determine the final
+ enviroment USE flag settings and return them as well.
+ @rtype: list or list, list
+ @return IUSE or IUSE, final_flags
+ """
+ final_use, use_expand_hidden, usemasked, useforced = get_all_cpv_use(cpv)
+ iuse_flags = filter_flags(get_iuse(cpv), use_expand_hidden, usemasked, useforced)
+ if final_setting:
+ final_flags = filter_flags(final_use, use_expand_hidden, usemasked, useforced)
+ return iuse_flags, final_flags
+ return iuse_flags
diff --git a/pym/gentoolkit/formatters.py b/pym/gentoolkit/formatters.py
index 097c186..84c66ee 100644
--- a/pym/gentoolkit/formatters.py
+++ b/pym/gentoolkit/formatters.py
@@ -13,123 +13,118 @@ import gentoolkit.pprinter as pp
def format_options(options):
- """Format module options.
-
- @type options: list
- @param options: [('option 1', 'description 1'), ('option 2', 'des... )]
- @rtype: str
- @return: formatted options string
- """
-
- result = []
- twrap = TextWrapper(width=gentoolkit.CONFIG['termWidth'])
- opts = (x[0] for x in options)
- descs = (x[1] for x in options)
- for opt, desc in zip(opts, descs):
- twrap.initial_indent = pp.emph(opt.ljust(25))
- twrap.subsequent_indent = " " * 25
- result.append(twrap.fill(desc))
- return '\n'.join(result)
-
-
-def format_filetype(path, fdesc, show_type=False, show_md5=False,
- show_timestamp=False):
- """Format a path for printing.
-
- @type path: str
- @param path: the path
- @type fdesc: list
- @param fdesc: [file_type, timestamp, MD5 sum/symlink target]
- file_type is one of dev, dir, obj, sym.
- If file_type is dir, there is no timestamp or MD5 sum.
- If file_type is sym, fdesc[2] is the target of the symlink.
- @type show_type: bool
- @param show_type: if True, prepend the file's type to the formatted string
- @type show_md5: bool
- @param show_md5: if True, append MD5 sum to the formatted string
- @type show_timestamp: bool
- @param show_timestamp: if True, append time-of-creation after pathname
- @rtype: str
- @return: formatted pathname with optional added information
- """
-
- ftype = fpath = stamp = md5sum = ""
- if fdesc[0] == "obj":
- ftype = "file"
- fpath = path
- stamp = format_timestamp(fdesc[1])
- md5sum = fdesc[2]
- elif fdesc[0] == "dir":
- ftype = "dir"
- fpath = pp.path(path)
- elif fdesc[0] == "sym":
- ftype = "sym"
- stamp = format_timestamp(fdesc[1])
- tgt = fdesc[2].split()[0]
- if gentoolkit.CONFIG["piping"]:
- fpath = path
- else:
- fpath = pp.path_symlink(path + " -> " + tgt)
- elif fdesc[0] == "dev":
- ftype = "dev"
- fpath = path
- else:
- sys.stderr.write(
- pp.error("%s has unknown type: %s" % (path, fdesc[0]))
- )
- result = ""
- if show_type:
- result += "%4s " % ftype
- result += fpath
- if show_timestamp:
- result += " " + stamp
- if show_md5:
- result += " " + md5sum
- return result
-
+ """Format module options.
+
+ @type options: list
+ @param options: [('option 1', 'description 1'), ('option 2', 'des... )]
+ @rtype: str
+ @return: formatted options string
+ """
+
+ result = []
+ twrap = TextWrapper(width=gentoolkit.CONFIG["termWidth"])
+ opts = (x[0] for x in options)
+ descs = (x[1] for x in options)
+ for opt, desc in zip(opts, descs):
+ twrap.initial_indent = pp.emph(opt.ljust(25))
+ twrap.subsequent_indent = " " * 25
+ result.append(twrap.fill(desc))
+ return "\n".join(result)
+
+
+def format_filetype(path, fdesc, show_type=False, show_md5=False, show_timestamp=False):
+ """Format a path for printing.
+
+ @type path: str
+ @param path: the path
+ @type fdesc: list
+ @param fdesc: [file_type, timestamp, MD5 sum/symlink target]
+ file_type is one of dev, dir, obj, sym.
+ If file_type is dir, there is no timestamp or MD5 sum.
+ If file_type is sym, fdesc[2] is the target of the symlink.
+ @type show_type: bool
+ @param show_type: if True, prepend the file's type to the formatted string
+ @type show_md5: bool
+ @param show_md5: if True, append MD5 sum to the formatted string
+ @type show_timestamp: bool
+ @param show_timestamp: if True, append time-of-creation after pathname
+ @rtype: str
+ @return: formatted pathname with optional added information
+ """
+
+ ftype = fpath = stamp = md5sum = ""
+ if fdesc[0] == "obj":
+ ftype = "file"
+ fpath = path
+ stamp = format_timestamp(fdesc[1])
+ md5sum = fdesc[2]
+ elif fdesc[0] == "dir":
+ ftype = "dir"
+ fpath = pp.path(path)
+ elif fdesc[0] == "sym":
+ ftype = "sym"
+ stamp = format_timestamp(fdesc[1])
+ tgt = fdesc[2].split()[0]
+ if gentoolkit.CONFIG["piping"]:
+ fpath = path
+ else:
+ fpath = pp.path_symlink(path + " -> " + tgt)
+ elif fdesc[0] == "dev":
+ ftype = "dev"
+ fpath = path
+ else:
+ sys.stderr.write(pp.error("%s has unknown type: %s" % (path, fdesc[0])))
+ result = ""
+ if show_type:
+ result += "%4s " % ftype
+ result += fpath
+ if show_timestamp:
+ result += " " + stamp
+ if show_md5:
+ result += " " + md5sum
+ return result
def format_timestamp(timestamp):
- """Format a timestamp into, e.g., '2009-01-31 21:19:44' format"""
-
- return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(timestamp)))
+ """Format a timestamp into, e.g., '2009-01-31 21:19:44' format"""
-class CpvValueWrapper:
- """Format a cpv and linewrap pre-formatted values"""
-
- def __init__(self, cpv_width=None, width=None):
- self.cpv_width = cpv_width
- if width is None:
- width = gentoolkit.CONFIG['termWidth']
- self.twrap = TextWrapper(width=width)
- #self.init_indent = len(self.spacer)
-
- def _format_values(self, key, values):
- """Format entry values ie. USE flags, keywords,...
-
- @type key: str
- @param key: a pre-formatted cpv
- @type values: list of pre-formatted strings
- @param values: ['flag1', 'flag2',...]
- @rtype: str
- @return: formatted options string
- """
-
- result = []
- if self.cpv_width > 1:
- _cpv = pp.cpv(key+'.'*(self.cpv_width-len(key)))
- if not len(values):
- return _cpv
- self.twrap.initial_indent = _cpv
- self.twrap.subsequent_indent = " " * (self.cpv_width+1)
- else:
- _cpv = pp.cpv(key+' ')
- if not len(values):
- return _cpv
- self.twrap.initial_indent = _cpv
- self.twrap.subsequent_indent = " " * (len(key)+1)
-
- result.append(self.twrap.fill(values))
- return '\n'.join(result)
+ return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(timestamp)))
+class CpvValueWrapper:
+ """Format a cpv and linewrap pre-formatted values"""
+
+ def __init__(self, cpv_width=None, width=None):
+ self.cpv_width = cpv_width
+ if width is None:
+ width = gentoolkit.CONFIG["termWidth"]
+ self.twrap = TextWrapper(width=width)
+ # self.init_indent = len(self.spacer)
+
+ def _format_values(self, key, values):
+ """Format entry values ie. USE flags, keywords,...
+
+ @type key: str
+ @param key: a pre-formatted cpv
+ @type values: list of pre-formatted strings
+ @param values: ['flag1', 'flag2',...]
+ @rtype: str
+ @return: formatted options string
+ """
+
+ result = []
+ if self.cpv_width > 1:
+ _cpv = pp.cpv(key + "." * (self.cpv_width - len(key)))
+ if not len(values):
+ return _cpv
+ self.twrap.initial_indent = _cpv
+ self.twrap.subsequent_indent = " " * (self.cpv_width + 1)
+ else:
+ _cpv = pp.cpv(key + " ")
+ if not len(values):
+ return _cpv
+ self.twrap.initial_indent = _cpv
+ self.twrap.subsequent_indent = " " * (len(key) + 1)
+
+ result.append(self.twrap.fill(values))
+ return "\n".join(result)
diff --git a/pym/gentoolkit/helpers.py b/pym/gentoolkit/helpers.py
index 236a379..15d959d 100644
--- a/pym/gentoolkit/helpers.py
+++ b/pym/gentoolkit/helpers.py
@@ -9,14 +9,14 @@
"""
__all__ = (
- 'FileOwner',
- 'get_cpvs',
- 'get_installed_cpvs',
- 'get_uninstalled_cpvs',
- 'get_bintree_cpvs',
- 'uniqify',
+ "FileOwner",
+ "get_cpvs",
+ "get_installed_cpvs",
+ "get_uninstalled_cpvs",
+ "get_bintree_cpvs",
+ "uniqify",
)
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
# =======
# Imports
@@ -35,280 +35,298 @@ from gentoolkit import errors
from gentoolkit.atom import Atom
from gentoolkit.cpv import CPV
from gentoolkit.versionmatch import VersionMatch
+
# This has to be imported below to stop circular import.
-#from gentoolkit.package import Package
+# from gentoolkit.package import Package
# =======
# Classes
# =======
+
class FileOwner:
- """Creates a function for locating the owner of filename queries.
-
- Example usage:
- >>> from gentoolkit.helpers import FileOwner
- >>> findowner = FileOwner()
- >>> findowner(('/bin/grep',))
- [(<Package 'sys-apps/grep-2.12'>, '/bin/grep')]
- """
- def __init__(self, is_regex=False, early_out=False, printer_fn=None):
- """Instantiate function.
-
- @type is_regex: bool
- @param is_regex: funtion args are regular expressions
- @type early_out: bool
- @param early_out: return when first result is found (safe)
- @type printer_fn: callable
- @param printer_fn: If defined, will be passed useful information for
- printing each result as it is found.
- """
- self.is_regex = is_regex
- self.early_out = early_out
- self.printer_fn = printer_fn
-
- def __call__(self, queries):
- """Run the function.
-
- @type queries: iterable
- @param queries: filepaths or filepath regexes
- """
- query_re_string = self._prepare_search_regex(queries)
- try:
- query_re = re.compile(query_re_string)
- except (TypeError, re.error) as err:
- raise errors.GentoolkitInvalidRegex(err)
-
- use_match = False
- if ((self.is_regex or query_re_string.startswith(r'^\/'))
- and '|' not in query_re_string ):
- # If we were passed a regex or a single path starting with root,
- # we can use re.match, else use re.search.
- use_match = True
-
- pkgset = get_installed_cpvs()
-
- return self.find_owners(query_re, use_match=use_match, pkgset=pkgset)
-
- def find_owners(self, query_re, use_match=False, pkgset=None):
- """Find owners and feed data to supplied output function.
-
- @type query_re: _sre.SRE_Pattern
- @param query_re: file regex
- @type use_match: bool
- @param use_match: use re.match or re.search
- @type pkgset: iterable or None
- @param pkgset: list of packages to look through
- """
- # FIXME: Remove when lazyimport supports objects:
- from gentoolkit.package import Package
-
- if use_match:
- query_fn = query_re.match
- else:
- query_fn = query_re.search
-
- results = []
- found_match = False
- for pkg in sorted([Package(x) for x in pkgset]):
- files = pkg.parsed_contents()
- for cfile in files:
- match = query_fn(cfile)
- if match:
- results.append((pkg, cfile))
- if self.printer_fn is not None:
- self.printer_fn(pkg, cfile)
- if self.early_out:
- found_match = True
- break
- if found_match:
- break
- return results
-
- @staticmethod
- def expand_abspaths(paths):
- """Expand any relative paths (./file) to their absolute paths.
-
- @type paths: list
- @param paths: file path strs
- @rtype: list
- @return: the original list with any relative paths expanded
- @raise AttributeError: if paths does not have attribute 'extend'
- """
-
- osp = os.path
- expanded_paths = []
- for path in paths:
- if path.startswith('./'):
- expanded_paths.append(osp.abspath(path))
- else:
- expanded_paths.append(path)
-
- return expanded_paths
-
- @staticmethod
- def extend_realpaths(paths):
- """Extend a list of paths with the realpaths for any symlinks.
-
- @type paths: list
- @param paths: file path strs
- @rtype: list
- @return: the original list plus the realpaths for any symlinks
- so long as the realpath doesn't already exist in the list
- @raise AttributeError: if paths does not have attribute 'extend'
- """
-
- osp = os.path
- paths.extend([osp.realpath(x) for x in paths
- if osp.realpath(x) not in paths])
-
- return paths
-
- def _prepare_search_regex(self, queries):
- """Create a regex out of the queries"""
-
- queries = list(queries)
- if self.is_regex:
- return '|'.join(queries)
- else:
- result = []
- # Trim trailing and multiple slashes from queries
- slashes = re.compile(r'/+')
- queries = self.expand_abspaths(queries)
- queries = self.extend_realpaths(queries)
- for query in queries:
- query = slashes.sub('/', query).rstrip('/')
- if query.startswith('/'):
- query = "^%s$" % re.escape(query)
- else:
- query = "/%s$" % re.escape(query)
- result.append(query)
- result = "|".join(result)
- return result
+ """Creates a function for locating the owner of filename queries.
+
+ Example usage:
+ >>> from gentoolkit.helpers import FileOwner
+ >>> findowner = FileOwner()
+ >>> findowner(('/bin/grep',))
+ [(<Package 'sys-apps/grep-2.12'>, '/bin/grep')]
+ """
+
+ def __init__(self, is_regex=False, early_out=False, printer_fn=None):
+ """Instantiate function.
+
+ @type is_regex: bool
+ @param is_regex: funtion args are regular expressions
+ @type early_out: bool
+ @param early_out: return when first result is found (safe)
+ @type printer_fn: callable
+ @param printer_fn: If defined, will be passed useful information for
+ printing each result as it is found.
+ """
+ self.is_regex = is_regex
+ self.early_out = early_out
+ self.printer_fn = printer_fn
+
+ def __call__(self, queries):
+ """Run the function.
+
+ @type queries: iterable
+ @param queries: filepaths or filepath regexes
+ """
+ query_re_string = self._prepare_search_regex(queries)
+ try:
+ query_re = re.compile(query_re_string)
+ except (TypeError, re.error) as err:
+ raise errors.GentoolkitInvalidRegex(err)
+
+ use_match = False
+ if (
+ self.is_regex or query_re_string.startswith(r"^\/")
+ ) and "|" not in query_re_string:
+ # If we were passed a regex or a single path starting with root,
+ # we can use re.match, else use re.search.
+ use_match = True
+
+ pkgset = get_installed_cpvs()
+
+ return self.find_owners(query_re, use_match=use_match, pkgset=pkgset)
+
+ def find_owners(self, query_re, use_match=False, pkgset=None):
+ """Find owners and feed data to supplied output function.
+
+ @type query_re: _sre.SRE_Pattern
+ @param query_re: file regex
+ @type use_match: bool
+ @param use_match: use re.match or re.search
+ @type pkgset: iterable or None
+ @param pkgset: list of packages to look through
+ """
+ # FIXME: Remove when lazyimport supports objects:
+ from gentoolkit.package import Package
+
+ if use_match:
+ query_fn = query_re.match
+ else:
+ query_fn = query_re.search
+
+ results = []
+ found_match = False
+ for pkg in sorted([Package(x) for x in pkgset]):
+ files = pkg.parsed_contents()
+ for cfile in files:
+ match = query_fn(cfile)
+ if match:
+ results.append((pkg, cfile))
+ if self.printer_fn is not None:
+ self.printer_fn(pkg, cfile)
+ if self.early_out:
+ found_match = True
+ break
+ if found_match:
+ break
+ return results
+
+ @staticmethod
+ def expand_abspaths(paths):
+ """Expand any relative paths (./file) to their absolute paths.
+
+ @type paths: list
+ @param paths: file path strs
+ @rtype: list
+ @return: the original list with any relative paths expanded
+ @raise AttributeError: if paths does not have attribute 'extend'
+ """
+
+ osp = os.path
+ expanded_paths = []
+ for path in paths:
+ if path.startswith("./"):
+ expanded_paths.append(osp.abspath(path))
+ else:
+ expanded_paths.append(path)
+
+ return expanded_paths
+
+ @staticmethod
+ def extend_realpaths(paths):
+ """Extend a list of paths with the realpaths for any symlinks.
+
+ @type paths: list
+ @param paths: file path strs
+ @rtype: list
+ @return: the original list plus the realpaths for any symlinks
+ so long as the realpath doesn't already exist in the list
+ @raise AttributeError: if paths does not have attribute 'extend'
+ """
+
+ osp = os.path
+ paths.extend([osp.realpath(x) for x in paths if osp.realpath(x) not in paths])
+
+ return paths
+
+ def _prepare_search_regex(self, queries):
+ """Create a regex out of the queries"""
+
+ queries = list(queries)
+ if self.is_regex:
+ return "|".join(queries)
+ else:
+ result = []
+ # Trim trailing and multiple slashes from queries
+ slashes = re.compile(r"/+")
+ queries = self.expand_abspaths(queries)
+ queries = self.extend_realpaths(queries)
+ for query in queries:
+ query = slashes.sub("/", query).rstrip("/")
+ if query.startswith("/"):
+ query = "^%s$" % re.escape(query)
+ else:
+ query = "/%s$" % re.escape(query)
+ result.append(query)
+ result = "|".join(result)
+ return result
+
# =========
# Functions
# =========
+
def get_cpvs(predicate=None, include_installed=True):
- """Get all packages in the Portage tree and overlays. Optionally apply a
- predicate.
-
- Example usage:
- >>> from gentoolkit.helpers import get_cpvs
- >>> len(set(get_cpvs()))
- 33518
- >>> fn = lambda x: x.startswith('app-portage')
- >>> len(set(get_cpvs(fn, include_installed=False)))
- 137
-
- @type predicate: function
- @param predicate: a function to filter the package list with
- @type include_installed: bool
- @param include_installed:
- If True: Return the union of all_cpvs and all_installed_cpvs
- If False: Return the difference of all_cpvs and all_installed_cpvs
- @rtype: generator
- @return: a generator that yields unsorted cat/pkg-ver strings from the
- Portage tree
- """
-
- if not predicate:
- predicate = lambda x: x
-
- all_cps = portage.db[portage.root]["porttree"].dbapi.cp_all()
-
- all_cpvs = iter(x for x in chain.from_iterable(
- portage.db[portage.root]["porttree"].dbapi.cp_list(x)
- for x in all_cps) if predicate(x))
-
- all_installed_cpvs = set(get_installed_cpvs(predicate))
-
- if include_installed:
- for cpv in all_cpvs:
- if cpv in all_installed_cpvs:
- all_installed_cpvs.remove(cpv)
- yield cpv
- for cpv in all_installed_cpvs:
- yield cpv
- else:
- for cpv in all_cpvs:
- if cpv not in all_installed_cpvs:
- yield cpv
+ """Get all packages in the Portage tree and overlays. Optionally apply a
+ predicate.
+
+ Example usage:
+ >>> from gentoolkit.helpers import get_cpvs
+ >>> len(set(get_cpvs()))
+ 33518
+ >>> fn = lambda x: x.startswith('app-portage')
+ >>> len(set(get_cpvs(fn, include_installed=False)))
+ 137
+
+ @type predicate: function
+ @param predicate: a function to filter the package list with
+ @type include_installed: bool
+ @param include_installed:
+ If True: Return the union of all_cpvs and all_installed_cpvs
+ If False: Return the difference of all_cpvs and all_installed_cpvs
+ @rtype: generator
+ @return: a generator that yields unsorted cat/pkg-ver strings from the
+ Portage tree
+ """
+
+ if not predicate:
+ predicate = lambda x: x
+
+ all_cps = portage.db[portage.root]["porttree"].dbapi.cp_all()
+
+ all_cpvs = iter(
+ x
+ for x in chain.from_iterable(
+ portage.db[portage.root]["porttree"].dbapi.cp_list(x) for x in all_cps
+ )
+ if predicate(x)
+ )
+
+ all_installed_cpvs = set(get_installed_cpvs(predicate))
+
+ if include_installed:
+ for cpv in all_cpvs:
+ if cpv in all_installed_cpvs:
+ all_installed_cpvs.remove(cpv)
+ yield cpv
+ for cpv in all_installed_cpvs:
+ yield cpv
+ else:
+ for cpv in all_cpvs:
+ if cpv not in all_installed_cpvs:
+ yield cpv
get_uninstalled_cpvs = partial(get_cpvs, include_installed=False)
def get_installed_cpvs(predicate=None):
- """Get all installed packages. Optionally apply a predicate.
+ """Get all installed packages. Optionally apply a predicate.
- @type predicate: function
- @param predicate: a function to filter the package list with
- @rtype: generator
- @return: a generator that yields unsorted installed cat/pkg-ver strings
- from VARDB
- """
+ @type predicate: function
+ @param predicate: a function to filter the package list with
+ @rtype: generator
+ @return: a generator that yields unsorted installed cat/pkg-ver strings
+ from VARDB
+ """
- if not predicate:
- predicate = lambda x: x
+ if not predicate:
+ predicate = lambda x: x
- installed_cps = portage.db[portage.root]["vartree"].dbapi.cp_all()
+ installed_cps = portage.db[portage.root]["vartree"].dbapi.cp_all()
- installed_cpvs = iter(x for x in chain.from_iterable(
- portage.db[portage.root]["vartree"].dbapi.cp_list(x)
- for x in installed_cps) if predicate(x))
+ installed_cpvs = iter(
+ x
+ for x in chain.from_iterable(
+ portage.db[portage.root]["vartree"].dbapi.cp_list(x) for x in installed_cps
+ )
+ if predicate(x)
+ )
- for cpv in installed_cpvs:
- yield cpv
+ for cpv in installed_cpvs:
+ yield cpv
def get_bintree_cpvs(predicate=None):
- """Get all binary packages available. Optionally apply a predicate.
+ """Get all binary packages available. Optionally apply a predicate.
- @type predicate: function
- @param predicate: a function to filter the package list with
- @rtype: generator
- @return: a generator that yields unsorted binary package cat/pkg-ver strings
- from BINDB
- """
+ @type predicate: function
+ @param predicate: a function to filter the package list with
+ @rtype: generator
+ @return: a generator that yields unsorted binary package cat/pkg-ver strings
+ from BINDB
+ """
- if not predicate:
- predicate = lambda x: x
+ if not predicate:
+ predicate = lambda x: x
- installed_cps = portage.db[portage.root]["bintree"].dbapi.cp_all()
+ installed_cps = portage.db[portage.root]["bintree"].dbapi.cp_all()
- installed_cpvs = iter(x for x in chain.from_iterable(
- portage.db[portage.root]["bintree"].dbapi.cp_list(x)
- for x in installed_cps) if predicate(x))
+ installed_cpvs = iter(
+ x
+ for x in chain.from_iterable(
+ portage.db[portage.root]["bintree"].dbapi.cp_list(x) for x in installed_cps
+ )
+ if predicate(x)
+ )
- for cpv in installed_cpvs:
- yield cpv
+ for cpv in installed_cpvs:
+ yield cpv
def print_file(path):
- """Display the contents of a file."""
+ """Display the contents of a file."""
- with open(_unicode_encode(path, encoding=_encodings['fs']), mode="rb") as open_file:
- lines = open_file.read()
- pp.uprint(lines.strip())
+ with open(_unicode_encode(path, encoding=_encodings["fs"]), mode="rb") as open_file:
+ lines = open_file.read()
+ pp.uprint(lines.strip())
def print_sequence(seq):
- """Print every item of a sequence."""
+ """Print every item of a sequence."""
- for item in seq:
- pp.uprint(item)
+ for item in seq:
+ pp.uprint(item)
def uniqify(seq, preserve_order=True):
- """Return a uniqified list. Optionally preserve order."""
+ """Return a uniqified list. Optionally preserve order."""
+
+ if preserve_order:
+ seen = set()
+ result = [x for x in seq if x not in seen and not seen.add(x)]
+ else:
+ result = list(set(seq))
- if preserve_order:
- seen = set()
- result = [x for x in seq if x not in seen and not seen.add(x)]
- else:
- result = list(set(seq))
+ return result
- return result
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/imlate/imlate.py b/pym/gentoolkit/imlate/imlate.py
index 3e22791..87b8ef1 100755
--- a/pym/gentoolkit/imlate/imlate.py
+++ b/pym/gentoolkit/imlate/imlate.py
@@ -7,8 +7,8 @@
__version__ = "git"
# works just with stable keywords!
-MAIN_ARCH = "auto" # can be overridden by -m ARCH
-TARGET_ARCH = "auto" # can be overridden by -t ARCH
+MAIN_ARCH = "auto" # can be overridden by -m ARCH
+TARGET_ARCH = "auto" # can be overridden by -t ARCH
# auto means e.g.:
# MAIN_ARCH = amd64
# TARGET_ARCH = ~amd64
@@ -25,6 +25,7 @@ from os import stat
from time import time
from xml.dom import minidom, NotFoundErr
from xml.parsers.expat import ExpatError
+
# TODO: just import needed stuff to safe memory/time and maybe use "as foo"
import portage
import portage.versions
@@ -33,450 +34,562 @@ from optparse import OptionParser
from time import gmtime, strftime
# override/change portage module settings
-def _portage_settings( var, value, settings = None ):
- if not settings:
- settings = portage.settings
- settings.unlock()
- settings[var] = value
- # backup_changes is very important since it can cause trouble,
- # if we do not backup our changes!
- settings.backup_changes( var )
- settings.lock()
+
+def _portage_settings(var, value, settings=None):
+ if not settings:
+ settings = portage.settings
+
+ settings.unlock()
+ settings[var] = value
+ # backup_changes is very important since it can cause trouble,
+ # if we do not backup our changes!
+ settings.backup_changes(var)
+ settings.lock()
+
# add stuff to our imlate dict
-def _add_ent( imlate, cat, pkg, ver, our_ver ):
- if not cat in list(imlate.keys()):
- imlate[cat] = {}
- if not pkg in list(imlate[cat].keys()):
- imlate[cat][pkg] = []
- imlate[cat][pkg].append( ver )
- imlate[cat][pkg].append( our_ver )
- return imlate
+def _add_ent(imlate, cat, pkg, ver, our_ver):
+ if not cat in list(imlate.keys()):
+ imlate[cat] = {}
+ if not pkg in list(imlate[cat].keys()):
+ imlate[cat][pkg] = []
+
+ imlate[cat][pkg].append(ver)
+ imlate[cat][pkg].append(our_ver)
+
+ return imlate
+
+
+def _fill(width, line, fill=" "):
+ while len(line) < width:
+ line = "%s%s" % (str(line), str(fill))
+ return line
-def _fill( width, line, fill = " " ):
- while len( line ) < width:
- line = "%s%s" % ( str( line ), str( fill ) )
- return line
# create a hopefully pretty result
-def show_result( conf, pkgs ):
- # X - len(colX) = space to fill
- col1 = -1
- col2 = -1
- for cat in pkgs:
- for pkg in pkgs[cat]:
- col1 = max(col1, len(("%s/%s" % (cat, pkg))))
- col2 = max(col2, len(pkgs[cat][pkg][1]))
- col1 += 1
- col2 += 1
-
- _header = "%s candidates for 'gentoo' on '%s'"
- _helper = "%s%s%s" % (_fill(col1, "category/package[:SLOT])"),
- _fill(col2, "our version"), "best version")
- _cand = ""
- header = ""
-
- if conf["FILE"] == "stdout":
- out = stdout
- elif conf["FILE"] == "stderr":
- out = stderr
- else:
- out = open( conf["FILE"], "w" )
-
- if conf["STABLE"] and conf["KEYWORD"]:
- _cand = "%i Stable and %i Keyword(~)" % ( conf["STABLE_SUM"],
- conf["KEYWORD_SUM"] )
- elif conf["STABLE"]:
- _cand = "%i Stable" % conf["STABLE_SUM"]
- elif conf["KEYWORD"]:
- _cand = "%i Keyword(~)" % conf["KEYWORD_SUM"]
-
- header = _header % ( _cand, conf["MAIN_ARCH"] )
-
- print("Generated on: %s" % conf["TIME"], file=out)
- print(_fill( len( header ), "", "=" ), file=out)
- print(header, file=out)
- print(_fill( len( header ), "", "=" ), file=out)
- print(file=out)
-
- print(_helper, file=out)
- print(_fill( len( _helper ), "", "-" ), file=out)
-
- for cat in sorted( pkgs.keys() ):
- for pkg in sorted( pkgs[cat].keys() ):
- print("%s%s%s" % (_fill(col1, ("%s/%s" % (cat, pkg))),
- _fill(col2, pkgs[cat][pkg][1]),
- pkgs[cat][pkg][0] ), file=out)
-
- if conf["FILE"] != "stdout":
- out.close()
+
+
+def show_result(conf, pkgs):
+ # X - len(colX) = space to fill
+ col1 = -1
+ col2 = -1
+ for cat in pkgs:
+ for pkg in pkgs[cat]:
+ col1 = max(col1, len(("%s/%s" % (cat, pkg))))
+ col2 = max(col2, len(pkgs[cat][pkg][1]))
+ col1 += 1
+ col2 += 1
+
+ _header = "%s candidates for 'gentoo' on '%s'"
+ _helper = "%s%s%s" % (
+ _fill(col1, "category/package[:SLOT])"),
+ _fill(col2, "our version"),
+ "best version",
+ )
+ _cand = ""
+ header = ""
+
+ if conf["FILE"] == "stdout":
+ out = stdout
+ elif conf["FILE"] == "stderr":
+ out = stderr
+ else:
+ out = open(conf["FILE"], "w")
+
+ if conf["STABLE"] and conf["KEYWORD"]:
+ _cand = "%i Stable and %i Keyword(~)" % (
+ conf["STABLE_SUM"],
+ conf["KEYWORD_SUM"],
+ )
+ elif conf["STABLE"]:
+ _cand = "%i Stable" % conf["STABLE_SUM"]
+ elif conf["KEYWORD"]:
+ _cand = "%i Keyword(~)" % conf["KEYWORD_SUM"]
+
+ header = _header % (_cand, conf["MAIN_ARCH"])
+
+ print("Generated on: %s" % conf["TIME"], file=out)
+ print(_fill(len(header), "", "="), file=out)
+ print(header, file=out)
+ print(_fill(len(header), "", "="), file=out)
+ print(file=out)
+
+ print(_helper, file=out)
+ print(_fill(len(_helper), "", "-"), file=out)
+
+ for cat in sorted(pkgs.keys()):
+ for pkg in sorted(pkgs[cat].keys()):
+ print(
+ "%s%s%s"
+ % (
+ _fill(col1, ("%s/%s" % (cat, pkg))),
+ _fill(col2, pkgs[cat][pkg][1]),
+ pkgs[cat][pkg][0],
+ ),
+ file=out,
+ )
+
+ if conf["FILE"] != "stdout":
+ out.close()
+
def _get_metadata(metadata, element, tag):
- values = []
-
- try:
- metadatadom = minidom.parse(metadata)
- except ExpatError as e:
- raise ExpatError("%s: %s" % (metadata, e,))
-
- try:
- elements = metadatadom.getElementsByTagName(element)
- if not elements:
- return values
- except NotFoundErr:
- return values
-
- try:
- for _element in elements:
- node = _element.getElementsByTagName(tag)
-
- if tag == "herd" and (not node or not node[0].childNodes):
-# print >> stderr, "'%s' is missing a <herd> tag or it is empty," % metadata
-# print >> stderr, "please file a bug at https://bugs.gentoo.org and refer to http://www.gentoo.org/proj/en/devrel/handbook/handbook.xml?part=2&chap=4"
- values.append("no-herd")
- continue
-
- try:
- values.append(node[0].childNodes[0].data)
- except IndexError:
- pass
- except NotFoundErr:
- raise NotFoundErr("%s: Malformed input: missing 'flag' tag(s)" % (metadata))
-
- metadatadom.unlink()
- return values
+ values = []
+
+ try:
+ metadatadom = minidom.parse(metadata)
+ except ExpatError as e:
+ raise ExpatError(
+ "%s: %s"
+ % (
+ metadata,
+ e,
+ )
+ )
+
+ try:
+ elements = metadatadom.getElementsByTagName(element)
+ if not elements:
+ return values
+ except NotFoundErr:
+ return values
+
+ try:
+ for _element in elements:
+ node = _element.getElementsByTagName(tag)
+
+ if tag == "herd" and (not node or not node[0].childNodes):
+ # print >> stderr, "'%s' is missing a <herd> tag or it is empty," % metadata
+ # print >> stderr, "please file a bug at https://bugs.gentoo.org and refer to http://www.gentoo.org/proj/en/devrel/handbook/handbook.xml?part=2&chap=4"
+ values.append("no-herd")
+ continue
+
+ try:
+ values.append(node[0].childNodes[0].data)
+ except IndexError:
+ pass
+ except NotFoundErr:
+ raise NotFoundErr("%s: Malformed input: missing 'flag' tag(s)" % (metadata))
+
+ metadatadom.unlink()
+ return values
+
def is_maintainer(maintainer, metadata):
- data = []
+ data = []
+
+ if maintainer == None:
+ return True
- if maintainer == None:
- return True
+ mtainer = maintainer.split(",")
- mtainer = maintainer.split(",")
+ data = _get_metadata(metadata, "maintainer", "email")
- data = _get_metadata(metadata, "maintainer", "email")
+ if not data and len(maintainer) == 0:
+ return True
+ elif not data and len(maintainer) > 0:
+ return False
+ else:
+ for addy in data:
+ for contact in mtainer:
+ if addy == contact:
+ return True
+ if addy.startswith(contact):
+ return True
+ return False
- if not data and len(maintainer) == 0:
- return True
- elif not data and len(maintainer) > 0:
- return False
- else:
- for addy in data:
- for contact in mtainer:
- if addy == contact:
- return True
- if addy.startswith(contact):
- return True
- return False
def is_herd(herd, metadata):
- data = []
+ data = []
- if herd == None:
- return True
+ if herd == None:
+ return True
- hrd = herd.split(",")
- data = _get_metadata(metadata, "pkgmetadata", "herd")
+ hrd = herd.split(",")
+ data = _get_metadata(metadata, "pkgmetadata", "herd")
- if not data and len(herd) == 0:
- return True
- elif not data and len(herd) > 0:
- return False
- else:
- for hd in data:
- for hd2 in hrd:
- if hd == hd2:
- return True
- if hd.startswith(hd2):
- return True
+ if not data and len(herd) == 0:
+ return True
+ elif not data and len(herd) > 0:
+ return False
+ else:
+ for hd in data:
+ for hd2 in hrd:
+ if hd == hd2:
+ return True
+ if hd.startswith(hd2):
+ return True
- return False
+ return False
# fetch a list of arch (just stable) packages
# -* is important to be sure that just arch is used
-def get_packages( conf ):
- _pkgs = {}
+def get_packages(conf):
+ _pkgs = {}
+
+ _portage_settings(
+ "ACCEPT_KEYWORDS", ("-* %s" % str(conf["TARGET_ARCH"])), conf["portdb"].settings
+ )
- _portage_settings( "ACCEPT_KEYWORDS", ( "-* %s" % str( conf["TARGET_ARCH"] ) ),
- conf["portdb"].settings )
+ for cp in conf["portdb"].dbapi.cp_all():
+ cpvrs = []
+ slots = {}
- for cp in conf["portdb"].dbapi.cp_all():
- cpvrs = []
- slots = {}
+ if conf["USER_PKGS"]:
+ if not cp in conf["USER_PKGS"] and not basename(cp) in conf["USER_PKGS"]:
+ continue
- if conf["USER_PKGS"]:
- if not cp in conf["USER_PKGS"] and not basename(cp) in conf["USER_PKGS"]:
- continue
+ # None is important to match also on empty string
+ if conf["MAINTAINER"] != None:
+ if not is_maintainer(
+ conf["MAINTAINER"], join(conf["PORTDIR"], cp, "metadata.xml")
+ ):
+ continue
+ if conf["HERD"] != None:
+ if not is_herd(conf["HERD"], join(conf["PORTDIR"], cp, "metadata.xml")):
+ continue
- # None is important to match also on empty string
- if conf["MAINTAINER"] != None:
- if not is_maintainer(conf["MAINTAINER"], join(conf["PORTDIR"], cp, "metadata.xml")):
- continue
- if conf["HERD"] != None:
- if not is_herd(conf["HERD"], join(conf["PORTDIR"], cp, "metadata.xml")):
- continue
+ cpvrs = conf["portdb"].dbapi.match(cp)
- cpvrs = conf["portdb"].dbapi.match( cp )
+ for cpvr in cpvrs:
+ slot = conf["portdb"].dbapi.aux_get(cpvr, ["SLOT"])[0]
+ if not slot in slots:
+ slots[slot] = []
+ slots[slot].append(cpvr)
- for cpvr in cpvrs:
- slot = conf["portdb"].dbapi.aux_get( cpvr, ["SLOT"] )[0]
- if not slot in slots:
- slots[slot] = []
- slots[slot].append(cpvr)
+ for slot in sorted(slots):
+ cpvr = portage.versions.best(slots[slot])
- for slot in sorted(slots):
- cpvr = portage.versions.best( slots[slot] )
+ if cpvr:
+ (cat, pkg, ver, rev) = portage.versions.catpkgsplit(cpvr)
- if cpvr:
- ( cat, pkg, ver, rev ) = portage.versions.catpkgsplit( cpvr )
+ if not cat in list(_pkgs.keys()):
+ _pkgs[cat] = {}
+ if not pkg in list(_pkgs[cat].keys()):
+ _pkgs[cat][pkg] = []
- if not cat in list(_pkgs.keys()):
- _pkgs[cat] = {}
- if not pkg in list(_pkgs[cat].keys()):
- _pkgs[cat][pkg] = []
+ if rev != "r0":
+ ver = "%s-%s" % (ver, rev)
- if rev != "r0":
- ver = "%s-%s" % ( ver, rev )
+ _pkgs[cat][pkg].append(ver)
- _pkgs[cat][pkg].append( ver )
+ return _pkgs
- return _pkgs
# compare get_packages() against MAIN_ARCH
-def get_imlate( conf, pkgs ):
- _portage_settings( "ACCEPT_KEYWORDS", ( "-* %s" % str( conf["MAIN_ARCH"] ) ),
- conf["portdb"].settings )
-
- stable = str( conf["MAIN_ARCH"].lstrip("~") )
- testing = "~%s" % stable
- exclude = "-%s" % stable
- exclude_all = "-*"
-
- imlate = {}
-
- for cat in sorted( pkgs.keys() ):
- for pkg in sorted( pkgs[cat].keys() ):
- for vr in pkgs[cat][pkg]:
- cpvr = ""
- abs_pkg = ""
- kwds = ""
- our = ""
- our_ver = ""
- mtime = 0
- slot = 0
-
- # 0 = none(default), 1 = testing(~arch), 2 = stable(arch),
- # 3 = exclude(-arch), 4 = exclude_all(-*)
- # -* would be overridden by ~arch or arch
- kwd_type = 0
-
- cpvr = "%s/%s-%s" % ( cat, pkg, vr )
-
- # absolute ebuild path for mtime check
- abs_pkg = join( conf["PORTDIR"], cat, pkg, basename( cpvr ) )
- abs_pkg = "%s.ebuild" % str( abs_pkg )
-
- kwds = conf["portdb"].dbapi.aux_get( cpvr, ["KEYWORDS"] )[0]
-
- # FIXME: %s is bad.. maybe even cast it, else there are issues because its unicode
- slot = ":%s" % conf["portdb"].dbapi.aux_get( cpvr, ["SLOT"] )[0]
- if slot == ":0":
- slot = ""
-
- # sorted() to keep the right order
- # e.g. -* first, -arch second, arch third and ~arch fourth
- # -* -foo ~arch
- # example: -* would be overridden by ~arch
- for kwd in sorted( kwds.split() ):
- if kwd == stable:
- kwd_type = 2
- break
- elif kwd == exclude:
- kwd_type = 3
- break
- elif kwd == exclude_all:
- kwd_type = 4
- elif kwd == testing:
- kwd_type = 1
- break
-
- # ignore -arch and already stabilized packages
- if kwd_type == 3 or kwd_type == 2:
- continue
- # drop packages with -* and without ~arch or arch
- # even if there is another version which includes arch or ~arch
- if kwd_type == 4:
- continue
- # drop "stable candidates" with mtime < 30 days
- # Shall we use gmtime/UTC here?
- if kwd_type == 1:
- mtime = int( ( time() - stat( abs_pkg ).st_mtime ) / 60 / 60 / 24 )
- if mtime < conf["MTIME"]:
- continue
-
- # look for an existing stable version
- our = portage.versions.best( conf["portdb"].dbapi.match( "%s/%s%s" % ( cat, pkg, slot ) ) )
- if our:
- _foo = portage.versions.pkgsplit( our )
- our_ver = _foo[1]
- if _foo[2] != "r0":
- our_ver = "%s-%s" % ( our_ver, _foo[2] )
- else:
- our_ver = ""
-
- # we just need the version if > our_ver
- if our_ver:
- if portage.versions.vercmp( our_ver, vr ) >= 0:
- continue
-
- if kwd_type == 1 and conf["STABLE"]:
- imlate = _add_ent( imlate, cat, ("%s%s" % (pkg, slot)), vr, our_ver )
- conf["STABLE_SUM"] += 1
- elif kwd_type == 0 and conf["KEYWORD"]:
- conf["KEYWORD_SUM"] += 1
- imlate = _add_ent( imlate, cat, ( "~%s%s" % (pkg, slot) ),
- vr, our_ver )
-
- return imlate
+
+
+def get_imlate(conf, pkgs):
+ _portage_settings(
+ "ACCEPT_KEYWORDS", ("-* %s" % str(conf["MAIN_ARCH"])), conf["portdb"].settings
+ )
+
+ stable = str(conf["MAIN_ARCH"].lstrip("~"))
+ testing = "~%s" % stable
+ exclude = "-%s" % stable
+ exclude_all = "-*"
+
+ imlate = {}
+
+ for cat in sorted(pkgs.keys()):
+ for pkg in sorted(pkgs[cat].keys()):
+ for vr in pkgs[cat][pkg]:
+ cpvr = ""
+ abs_pkg = ""
+ kwds = ""
+ our = ""
+ our_ver = ""
+ mtime = 0
+ slot = 0
+
+ # 0 = none(default), 1 = testing(~arch), 2 = stable(arch),
+ # 3 = exclude(-arch), 4 = exclude_all(-*)
+ # -* would be overridden by ~arch or arch
+ kwd_type = 0
+
+ cpvr = "%s/%s-%s" % (cat, pkg, vr)
+
+ # absolute ebuild path for mtime check
+ abs_pkg = join(conf["PORTDIR"], cat, pkg, basename(cpvr))
+ abs_pkg = "%s.ebuild" % str(abs_pkg)
+
+ kwds = conf["portdb"].dbapi.aux_get(cpvr, ["KEYWORDS"])[0]
+
+ # FIXME: %s is bad.. maybe even cast it, else there are issues because its unicode
+ slot = ":%s" % conf["portdb"].dbapi.aux_get(cpvr, ["SLOT"])[0]
+ if slot == ":0":
+ slot = ""
+
+ # sorted() to keep the right order
+ # e.g. -* first, -arch second, arch third and ~arch fourth
+ # -* -foo ~arch
+ # example: -* would be overridden by ~arch
+ for kwd in sorted(kwds.split()):
+ if kwd == stable:
+ kwd_type = 2
+ break
+ elif kwd == exclude:
+ kwd_type = 3
+ break
+ elif kwd == exclude_all:
+ kwd_type = 4
+ elif kwd == testing:
+ kwd_type = 1
+ break
+
+ # ignore -arch and already stabilized packages
+ if kwd_type == 3 or kwd_type == 2:
+ continue
+ # drop packages with -* and without ~arch or arch
+ # even if there is another version which includes arch or ~arch
+ if kwd_type == 4:
+ continue
+ # drop "stable candidates" with mtime < 30 days
+ # Shall we use gmtime/UTC here?
+ if kwd_type == 1:
+ mtime = int((time() - stat(abs_pkg).st_mtime) / 60 / 60 / 24)
+ if mtime < conf["MTIME"]:
+ continue
+
+ # look for an existing stable version
+ our = portage.versions.best(
+ conf["portdb"].dbapi.match("%s/%s%s" % (cat, pkg, slot))
+ )
+ if our:
+ _foo = portage.versions.pkgsplit(our)
+ our_ver = _foo[1]
+ if _foo[2] != "r0":
+ our_ver = "%s-%s" % (our_ver, _foo[2])
+ else:
+ our_ver = ""
+
+ # we just need the version if > our_ver
+ if our_ver:
+ if portage.versions.vercmp(our_ver, vr) >= 0:
+ continue
+
+ if kwd_type == 1 and conf["STABLE"]:
+ imlate = _add_ent(imlate, cat, ("%s%s" % (pkg, slot)), vr, our_ver)
+ conf["STABLE_SUM"] += 1
+ elif kwd_type == 0 and conf["KEYWORD"]:
+ conf["KEYWORD_SUM"] += 1
+ imlate = _add_ent(imlate, cat, ("~%s%s" % (pkg, slot)), vr, our_ver)
+
+ return imlate
+
# fetch portage related settings
-def get_settings( conf = None ):
- if not isinstance( conf, dict ) and conf:
- raise TypeError("conf must be dict() or None")
- if not conf:
- conf = {}
-
- # TODO: maybe we should improve it a bit ;)
- mysettings = portage.config( config_incrementals = portage.const.INCREMENTALS, local_config = False )
-
- if conf["MAIN_ARCH"] == "auto":
- conf["MAIN_ARCH"] = "%s" % mysettings["ACCEPT_KEYWORDS"].split(" ")[0].lstrip("~")
- if conf["TARGET_ARCH"] == "auto":
- conf["TARGET_ARCH"] = "~%s" % mysettings["ACCEPT_KEYWORDS"].split(" ")[0].lstrip("~")
-
- # TODO: exclude overlay categories from check
- if conf["CATEGORIES"]:
- _mycats = []
- for _cat in conf["CATEGORIES"].split(","):
- _cat = _cat.strip()
- _mycats.append(_cat )
- if _cat not in mysettings.categories:
- raise ValueError("invalid category for -C switch '%s'" % _cat)
- mysettings.categories = _mycats
-
- # maybe thats not necessary because we override porttrees below..
- _portage_settings( "PORTDIR_OVERLAY", "", mysettings )
- trees = portage.create_trees()
- trees["/"]["porttree"].settings = mysettings
- portdb = trees["/"]["porttree"]
- portdb.dbapi.settings = mysettings
- portdb.dbapi.porttrees = [portage.portdb.porttree_root]
- # does it make sense to remove _all_ useless stuff or just leave it as it is?
- #portdb.dbapi._aux_cache_keys.clear()
- #portdb.dbapi._aux_cache_keys.update(["EAPI", "KEYWORDS", "SLOT"])
-
- conf["PORTDIR"] = portage.settings["PORTDIR"]
- conf["portdb"] = portdb
-
- return conf
+
+
+def get_settings(conf=None):
+ if not isinstance(conf, dict) and conf:
+ raise TypeError("conf must be dict() or None")
+ if not conf:
+ conf = {}
+
+ # TODO: maybe we should improve it a bit ;)
+ mysettings = portage.config(
+ config_incrementals=portage.const.INCREMENTALS, local_config=False
+ )
+
+ if conf["MAIN_ARCH"] == "auto":
+ conf["MAIN_ARCH"] = "%s" % mysettings["ACCEPT_KEYWORDS"].split(" ")[0].lstrip(
+ "~"
+ )
+ if conf["TARGET_ARCH"] == "auto":
+ conf["TARGET_ARCH"] = "~%s" % mysettings["ACCEPT_KEYWORDS"].split(" ")[
+ 0
+ ].lstrip("~")
+
+ # TODO: exclude overlay categories from check
+ if conf["CATEGORIES"]:
+ _mycats = []
+ for _cat in conf["CATEGORIES"].split(","):
+ _cat = _cat.strip()
+ _mycats.append(_cat)
+ if _cat not in mysettings.categories:
+ raise ValueError("invalid category for -C switch '%s'" % _cat)
+ mysettings.categories = _mycats
+
+ # maybe thats not necessary because we override porttrees below..
+ _portage_settings("PORTDIR_OVERLAY", "", mysettings)
+ trees = portage.create_trees()
+ trees["/"]["porttree"].settings = mysettings
+ portdb = trees["/"]["porttree"]
+ portdb.dbapi.settings = mysettings
+ portdb.dbapi.porttrees = [portage.portdb.porttree_root]
+ # does it make sense to remove _all_ useless stuff or just leave it as it is?
+ # portdb.dbapi._aux_cache_keys.clear()
+ # portdb.dbapi._aux_cache_keys.update(["EAPI", "KEYWORDS", "SLOT"])
+
+ conf["PORTDIR"] = portage.settings["PORTDIR"]
+ conf["portdb"] = portdb
+
+ return conf
# just for standalone
def main():
- conf = {}
- pkgs = {}
-
- parser = OptionParser( version = "%prog " + __version__ )
- parser.usage = "%prog [options] [category/package] ..."
- parser.disable_interspersed_args()
-
- parser.add_option( "-f", "--file", dest = "filename", action = "store", type = "string",
- help = "write result into FILE [default: %default]", metavar = "FILE", default = "stdout" )
- parser.add_option( "-m", "--main", dest = "main_arch", action = "store", type = "string",
- help = "set main ARCH (e.g. your arch) [default: %default]", metavar = "ARCH", default = MAIN_ARCH )
- parser.add_option( "-t", "--target", dest = "target_arch", action = "store", type = "string",
- help = "set target ARCH (e.g. x86) [default: %default]", metavar = "ARCH", default = TARGET_ARCH )
- parser.add_option( "--mtime", dest = "mtime", action = "store", type = "int",
- help = "set minimum MTIME in days [default: %default]", metavar = "MTIME", default = 30 )
-
- # TODO: leave a good comment here (about True/False) :)
- parser.add_option( "-s", "--stable", dest = "stable", action = "store_true", default = False,
- help = "just show stable candidates (e.g. -s and -k is the default result) [default: True]" )
- parser.add_option( "-k", "--keyword", dest = "keyword", action = "store_true", default = False,
- help = "just show keyword candidates (e.g. -s and -k is the default result) [default: True]" )
-
- parser.add_option( "-M", "--maintainer", dest = "maintainer", action = "store", type = "string",
- help = "Show only packages from the specified maintainer", metavar = "MAINTAINER", default = None)
-
- parser.add_option( "-H", "--herd", dest = "herd", action = "store", type = "string",
- help = "Show only packages from the specified herd", metavar = "HERD", default = None)
-
-# # EXPERIMENTAL
-# parser.add_option( "-e", "--experimental", dest = "experimental", action = "store_true", default = False,
-# help = "enables experimental functions/features (have a look for # EXPERIMENTAL comments in the source) [default: %default]" )
-
- parser.add_option( "-C", "--category", "--categories", dest = "categories", action = "store", default = None,
- metavar = "CATEGORIES",
- help = "just check in the specified category/categories (comma separated) [default: %default]")
-
- ( options, args ) = parser.parse_args()
-
- if len( args ) > 0:
- conf["USER_PKGS"] = args
- else:
- conf["USER_PKGS"] = []
-
- # cleanup optparse
- try:
- parser.destroy()
- except AttributeError:
- # to be at least python 2.4 compatible
- del parser._short_opt
- del parser._long_opt
- del parser.defaults
-
- # generated timestamp (UTC)
- conf["TIME"] = strftime( "%a %b %d %H:%M:%S %Z %Y", gmtime() )
-
- # package counter
- conf["KEYWORD_SUM"] = 0
- conf["STABLE_SUM"] = 0
-
- if not options.main_arch in portage.archlist and options.main_arch != "auto":
- raise ValueError("invalid MAIN ARCH defined!")
- if not options.target_arch in portage.archlist and options.target_arch != "auto":
- raise ValueError("invalid TARGET ARCH defined!")
-
- conf["MAIN_ARCH"] = options.main_arch
- conf["TARGET_ARCH"] = options.target_arch
-
- conf["FILE"] = options.filename
- conf["MTIME"] = options.mtime
-
- if not options.stable and not options.keyword:
- conf["STABLE"] = True
- conf["KEYWORD"] = True
- else:
- conf["STABLE"] = options.stable
- conf["KEYWORD"] = options.keyword
-
-# conf["EXPERIMENTAL"] = options.experimental
- conf["CATEGORIES"] = options.categories
-
- conf["MAINTAINER"] = options.maintainer
- conf["HERD"] = options.herd
-
- # append to our existing
- conf = get_settings( conf )
- pkgs = get_packages( conf )
- pkgs = get_imlate( conf, pkgs )
-
- show_result( conf, pkgs )
+ conf = {}
+ pkgs = {}
+
+ parser = OptionParser(version="%prog " + __version__)
+ parser.usage = "%prog [options] [category/package] ..."
+ parser.disable_interspersed_args()
+
+ parser.add_option(
+ "-f",
+ "--file",
+ dest="filename",
+ action="store",
+ type="string",
+ help="write result into FILE [default: %default]",
+ metavar="FILE",
+ default="stdout",
+ )
+ parser.add_option(
+ "-m",
+ "--main",
+ dest="main_arch",
+ action="store",
+ type="string",
+ help="set main ARCH (e.g. your arch) [default: %default]",
+ metavar="ARCH",
+ default=MAIN_ARCH,
+ )
+ parser.add_option(
+ "-t",
+ "--target",
+ dest="target_arch",
+ action="store",
+ type="string",
+ help="set target ARCH (e.g. x86) [default: %default]",
+ metavar="ARCH",
+ default=TARGET_ARCH,
+ )
+ parser.add_option(
+ "--mtime",
+ dest="mtime",
+ action="store",
+ type="int",
+ help="set minimum MTIME in days [default: %default]",
+ metavar="MTIME",
+ default=30,
+ )
+
+ # TODO: leave a good comment here (about True/False) :)
+ parser.add_option(
+ "-s",
+ "--stable",
+ dest="stable",
+ action="store_true",
+ default=False,
+ help="just show stable candidates (e.g. -s and -k is the default result) [default: True]",
+ )
+ parser.add_option(
+ "-k",
+ "--keyword",
+ dest="keyword",
+ action="store_true",
+ default=False,
+ help="just show keyword candidates (e.g. -s and -k is the default result) [default: True]",
+ )
+
+ parser.add_option(
+ "-M",
+ "--maintainer",
+ dest="maintainer",
+ action="store",
+ type="string",
+ help="Show only packages from the specified maintainer",
+ metavar="MAINTAINER",
+ default=None,
+ )
+
+ parser.add_option(
+ "-H",
+ "--herd",
+ dest="herd",
+ action="store",
+ type="string",
+ help="Show only packages from the specified herd",
+ metavar="HERD",
+ default=None,
+ )
+
+ # # EXPERIMENTAL
+ # parser.add_option( "-e", "--experimental", dest = "experimental", action = "store_true", default = False,
+ # help = "enables experimental functions/features (have a look for # EXPERIMENTAL comments in the source) [default: %default]" )
+
+ parser.add_option(
+ "-C",
+ "--category",
+ "--categories",
+ dest="categories",
+ action="store",
+ default=None,
+ metavar="CATEGORIES",
+ help="just check in the specified category/categories (comma separated) [default: %default]",
+ )
+
+ (options, args) = parser.parse_args()
+
+ if len(args) > 0:
+ conf["USER_PKGS"] = args
+ else:
+ conf["USER_PKGS"] = []
+
+ # cleanup optparse
+ try:
+ parser.destroy()
+ except AttributeError:
+ # to be at least python 2.4 compatible
+ del parser._short_opt
+ del parser._long_opt
+ del parser.defaults
+
+ # generated timestamp (UTC)
+ conf["TIME"] = strftime("%a %b %d %H:%M:%S %Z %Y", gmtime())
+
+ # package counter
+ conf["KEYWORD_SUM"] = 0
+ conf["STABLE_SUM"] = 0
+
+ if not options.main_arch in portage.archlist and options.main_arch != "auto":
+ raise ValueError("invalid MAIN ARCH defined!")
+ if not options.target_arch in portage.archlist and options.target_arch != "auto":
+ raise ValueError("invalid TARGET ARCH defined!")
+
+ conf["MAIN_ARCH"] = options.main_arch
+ conf["TARGET_ARCH"] = options.target_arch
+
+ conf["FILE"] = options.filename
+ conf["MTIME"] = options.mtime
+
+ if not options.stable and not options.keyword:
+ conf["STABLE"] = True
+ conf["KEYWORD"] = True
+ else:
+ conf["STABLE"] = options.stable
+ conf["KEYWORD"] = options.keyword
+
+ # conf["EXPERIMENTAL"] = options.experimental
+ conf["CATEGORIES"] = options.categories
+
+ conf["MAINTAINER"] = options.maintainer
+ conf["HERD"] = options.herd
+
+ # append to our existing
+ conf = get_settings(conf)
+ pkgs = get_packages(conf)
+ pkgs = get_imlate(conf, pkgs)
+
+ show_result(conf, pkgs)
-if __name__ == "__main__":
- main()
+if __name__ == "__main__":
+ main()
diff --git a/pym/gentoolkit/keyword.py b/pym/gentoolkit/keyword.py
index e997efe..4160781 100644
--- a/pym/gentoolkit/keyword.py
+++ b/pym/gentoolkit/keyword.py
@@ -7,12 +7,7 @@
http://www.gentoo.org/proj/en/glep/glep-0053.html
"""
-__all__ = (
- 'Keyword',
- 'compare_strs',
- 'reduce_keywords',
- 'determine_keyword'
-)
+__all__ = ("Keyword", "compare_strs", "reduce_keywords", "determine_keyword")
# =======
# Imports
@@ -23,87 +18,90 @@ __all__ = (
# Classes
# =======
+
class Keyword:
- """Provides common methods on a GLEP 53 keyword."""
+ """Provides common methods on a GLEP 53 keyword."""
+
+ def __init__(self, keyword):
+ self.keyword = keyword
+ arch, sep, os = keyword.partition("-")
+ self.arch = arch
+ self.os = os
- def __init__(self, keyword):
- self.keyword = keyword
- arch, sep, os = keyword.partition('-')
- self.arch = arch
- self.os = os
+ def __eq__(self, other):
+ if not isinstance(other, self.__class__):
+ return False
+ return self.keyword == other.keyword
- def __eq__(self, other):
- if not isinstance(other, self.__class__):
- return False
- return self.keyword == other.keyword
+ def __ne__(self, other):
+ return not self == other
- def __ne__(self, other):
- return not self == other
+ def __lt__(self, other):
+ if not isinstance(other, self.__class__):
+ raise TypeError(
+ "other isn't of %s type, is %s" % (self.__class__, other.__class__)
+ )
+ if self.os < other.os:
+ return True
+ return self.arch < other.arch
- def __lt__(self, other):
- if not isinstance(other, self.__class__):
- raise TypeError("other isn't of %s type, is %s" % (
- self.__class__, other.__class__)
- )
- if self.os < other.os:
- return True
- return self.arch < other.arch
+ def __le__(self, other):
+ return self == other or self < other
- def __le__(self, other):
- return self == other or self < other
+ def __gt__(self, other):
+ return not self <= other
- def __gt__(self, other):
- return not self <= other
+ def __ge__(self, other):
+ return self == other or self > other
- def __ge__(self, other):
- return self == other or self > other
+ def __str__(self):
+ return self.keyword
- def __str__(self):
- return self.keyword
+ def __repr__(self):
+ return "<{0.__class__.__name__} {0.keyword!r}>".format(self)
- def __repr__(self):
- return "<{0.__class__.__name__} {0.keyword!r}>".format(self)
# =========
# Functions
# =========
+
def compare_strs(kw1, kw2):
- """Similar to the builtin cmp, but for keyword strings. Usually called
- as: keyword_list.sort(keyword.compare_strs)
+ """Similar to the builtin cmp, but for keyword strings. Usually called
+ as: keyword_list.sort(keyword.compare_strs)
- An alternative is to use the Keyword descriptor directly:
- >>> keyword_list = ['~x86', '~amd64', 'x86']
- >>> kwds = sorted(Keyword(x) for x in keyword_list)
+ An alternative is to use the Keyword descriptor directly:
+ >>> keyword_list = ['~x86', '~amd64', 'x86']
+ >>> kwds = sorted(Keyword(x) for x in keyword_list)
- @see: >>> help(cmp)
- """
+ @see: >>> help(cmp)
+ """
- kw1_arch, sep, kw1_os = kw1.partition('-')
- kw2_arch, sep, kw2_os = kw2.partition('-')
- if kw1_arch != kw2_arch:
- if kw1_os != kw2_os:
- return -1 if kw1_os < kw2_os else 1
- return -1 if kw1_arch < kw2_arch else 1
- if kw1_os == kw2_os:
- return 0
- return -1 if kw1_os < kw2_os else 1
+ kw1_arch, sep, kw1_os = kw1.partition("-")
+ kw2_arch, sep, kw2_os = kw2.partition("-")
+ if kw1_arch != kw2_arch:
+ if kw1_os != kw2_os:
+ return -1 if kw1_os < kw2_os else 1
+ return -1 if kw1_arch < kw2_arch else 1
+ if kw1_os == kw2_os:
+ return 0
+ return -1 if kw1_os < kw2_os else 1
def reduce_keywords(keywords):
- """Reduce a list of keywords to a unique set of stable keywords.
+ """Reduce a list of keywords to a unique set of stable keywords.
- Example usage:
- >>> kw = reduce_keywords(['~amd64', 'x86', '~x86'])
- >>> isinstance(kw, set)
- True
- >>> sorted(kw)
- ['amd64', 'x86']
+ Example usage:
+ >>> kw = reduce_keywords(['~amd64', 'x86', '~x86'])
+ >>> isinstance(kw, set)
+ True
+ >>> sorted(kw)
+ ['amd64', 'x86']
- @type keywords: array
- @rtype: set
- """
- return set(x.lstrip('~') for x in keywords)
+ @type keywords: array
+ @rtype: set
+ """
+ return set(x.lstrip("~") for x in keywords)
abs_keywords = reduce_keywords
@@ -114,31 +112,31 @@ abs_keywords = reduce_keywords
# I was trying to avoid a 2nd use of determine_keyword name (in analyse.lib)
# but that one is a little different and not suitable for this task.
def determine_keyword(arch, accepted, keywords):
- """Determine a keyword from matching a dep's KEYWORDS
- list against the ARCH & ACCEPT_KEYWORDS provided.
-
- @type arch: string
- @param arch: portage.settings["ARCH"]
- @type accepted: string
- @param accepted: portage.settings["ACCEPT_KEYWORDS"]
- @type keywords: string
- @param keywords: the pkg ebuilds keywords
- """
- if not keywords:
- return ''
- keys = keywords.split()
- if arch in keys:
- return arch
- keyworded = "~" + arch
- if keyworded in keys:
- return keyworded
- match = list(set(accepted.split(" ")).intersection(keys))
- if len(match) > 1:
- if arch in match:
- return arch
- if keyworded in match:
- return keyworded
- return 'unknown'
- if match:
- return match[0]
- return 'unknown'
+ """Determine a keyword from matching a dep's KEYWORDS
+ list against the ARCH & ACCEPT_KEYWORDS provided.
+
+ @type arch: string
+ @param arch: portage.settings["ARCH"]
+ @type accepted: string
+ @param accepted: portage.settings["ACCEPT_KEYWORDS"]
+ @type keywords: string
+ @param keywords: the pkg ebuilds keywords
+ """
+ if not keywords:
+ return ""
+ keys = keywords.split()
+ if arch in keys:
+ return arch
+ keyworded = "~" + arch
+ if keyworded in keys:
+ return keyworded
+ match = list(set(accepted.split(" ")).intersection(keys))
+ if len(match) > 1:
+ if arch in match:
+ return arch
+ if keyworded in match:
+ return keyworded
+ return "unknown"
+ if match:
+ return match[0]
+ return "unknown"
diff --git a/pym/gentoolkit/metadata.py b/pym/gentoolkit/metadata.py
index 9dc9619..2678611 100644
--- a/pym/gentoolkit/metadata.py
+++ b/pym/gentoolkit/metadata.py
@@ -31,8 +31,8 @@
'Thomas Mills Hinkle'
"""
-__all__ = ('MetaData',)
-__docformat__ = 'epytext'
+__all__ = ("MetaData",)
+__docformat__ = "epytext"
# =======
# Imports
@@ -48,260 +48,262 @@ from portage import settings
# Classes
# =======
+
class _Maintainer:
- """An object for representing one maintainer.
-
- @type email: str or None
- @ivar email: Maintainer's email address. Used for both Gentoo and upstream.
- @type name: str or None
- @ivar name: Maintainer's name. Used for both Gentoo and upstream.
- @type description: str or None
- @ivar description: Description of what a maintainer does. Gentoo only.
- @type restrict: str or None
- @ivar restrict: e.g. &gt;=portage-2.2 means only maintains versions
- of Portage greater than 2.2. Should be DEPEND string with < and >
- converted to &lt; and &gt; respectively.
- @type status: str or None
- @ivar status: If set, either 'active' or 'inactive'. Upstream only.
- """
-
- def __init__(self, node):
- self.email = None
- self.name = None
- self.description = None
- self.restrict = node.get('restrict')
- self.status = node.get('status')
- for attr in node.iter():
- setattr(self, attr.tag, attr.text)
-
- def __repr__(self):
- return "<%s %r>" % (self.__class__.__name__, self.email)
+ """An object for representing one maintainer.
+
+ @type email: str or None
+ @ivar email: Maintainer's email address. Used for both Gentoo and upstream.
+ @type name: str or None
+ @ivar name: Maintainer's name. Used for both Gentoo and upstream.
+ @type description: str or None
+ @ivar description: Description of what a maintainer does. Gentoo only.
+ @type restrict: str or None
+ @ivar restrict: e.g. &gt;=portage-2.2 means only maintains versions
+ of Portage greater than 2.2. Should be DEPEND string with < and >
+ converted to &lt; and &gt; respectively.
+ @type status: str or None
+ @ivar status: If set, either 'active' or 'inactive'. Upstream only.
+ """
+
+ def __init__(self, node):
+ self.email = None
+ self.name = None
+ self.description = None
+ self.restrict = node.get("restrict")
+ self.status = node.get("status")
+ for attr in node.iter():
+ setattr(self, attr.tag, attr.text)
+
+ def __repr__(self):
+ return "<%s %r>" % (self.__class__.__name__, self.email)
class _Useflag:
- """An object for representing one USE flag.
-
- @todo: Is there any way to have a keyword option to leave in
- <pkg> and <cat> for later processing?
- @type name: str or None
- @ivar name: USE flag
- @type restrict: str or None
- @ivar restrict: e.g. &gt;=portage-2.2 means flag is only avaiable in
- versions greater than 2.2
- @type description: str
- @ivar description: description of the USE flag
- """
-
- def __init__(self, node):
- self.name = node.get('name')
- self.restrict = node.get('restrict')
- _desc = ''
- if node.text:
- _desc = node.text
- for child in node.iter():
- # prevent duplicate text
- if child.text and child.text not in _desc:
- _desc += child.text
- if child.tail and not child.tail in _desc:
- _desc += child.tail
- # This takes care of tabs and newlines left from the file
- self.description = re.sub(r'\s+', ' ', _desc)
-
- def __repr__(self):
- return "<%s %r>" % (self.__class__.__name__, self.name)
+ """An object for representing one USE flag.
+
+ @todo: Is there any way to have a keyword option to leave in
+ <pkg> and <cat> for later processing?
+ @type name: str or None
+ @ivar name: USE flag
+ @type restrict: str or None
+ @ivar restrict: e.g. &gt;=portage-2.2 means flag is only avaiable in
+ versions greater than 2.2
+ @type description: str
+ @ivar description: description of the USE flag
+ """
+
+ def __init__(self, node):
+ self.name = node.get("name")
+ self.restrict = node.get("restrict")
+ _desc = ""
+ if node.text:
+ _desc = node.text
+ for child in node.iter():
+ # prevent duplicate text
+ if child.text and child.text not in _desc:
+ _desc += child.text
+ if child.tail and not child.tail in _desc:
+ _desc += child.tail
+ # This takes care of tabs and newlines left from the file
+ self.description = re.sub(r"\s+", " ", _desc)
+
+ def __repr__(self):
+ return "<%s %r>" % (self.__class__.__name__, self.name)
class _Upstream:
- """An object for representing one package's upstream.
-
- @type maintainers: list
- @ivar maintainers: L{_Maintainer} objects for each upstream maintainer
- @type changelogs: list
- @ivar changelogs: URLs to upstream's ChangeLog file in str format
- @type docs: list
- @ivar docs: Sequence of tuples containing URLs to upstream documentation
- in the first slot and 'lang' attribute in the second, e.g.,
- [('http.../docs/en/tut.html', None), ('http.../doc/fr/tut.html', 'fr')]
- @type bugtrackers: list
- @ivar bugtrackers: URLs to upstream's bugtracker. May also contain an email
- address if prepended with 'mailto:'
- @type remoteids: list
- @ivar remoteids: Sequence of tuples containing the project's hosting site
- name in the first slot and the project's ID name or number for that
- site in the second, e.g., [('sourceforge', 'systemrescuecd')]
- """
-
- def __init__(self, node):
- self.node = node
- self.maintainers = self.upstream_maintainers()
- self.changelogs = self.upstream_changelogs()
- self.docs = self.upstream_documentation()
- self.bugtrackers = self.upstream_bugtrackers()
- self.remoteids = self.upstream_remoteids()
-
- def __repr__(self):
- return "<%s %r>" % (self.__class__.__name__, self.__dict__)
-
- def upstream_bugtrackers(self):
- """Retrieve upstream bugtracker location from xml node."""
- return [e.text for e in self.node.findall('bugs-to')]
-
- def upstream_changelogs(self):
- """Retrieve upstream changelog location from xml node."""
- return [e.text for e in self.node.findall('changelog')]
-
- def upstream_documentation(self):
- """Retrieve upstream documentation location from xml node."""
- result = []
- for elem in self.node.findall('doc'):
- lang = elem.get('lang')
- result.append((elem.text, lang))
- return result
-
- def upstream_maintainers(self):
- """Retrieve upstream maintainer information from xml node."""
- return [_Maintainer(m) for m in self.node.findall('maintainer')]
-
- def upstream_remoteids(self):
- """Retrieve upstream remote ID from xml node."""
- return [(e.text, e.get('type')) for e in self.node.findall('remote-id')]
+ """An object for representing one package's upstream.
+
+ @type maintainers: list
+ @ivar maintainers: L{_Maintainer} objects for each upstream maintainer
+ @type changelogs: list
+ @ivar changelogs: URLs to upstream's ChangeLog file in str format
+ @type docs: list
+ @ivar docs: Sequence of tuples containing URLs to upstream documentation
+ in the first slot and 'lang' attribute in the second, e.g.,
+ [('http.../docs/en/tut.html', None), ('http.../doc/fr/tut.html', 'fr')]
+ @type bugtrackers: list
+ @ivar bugtrackers: URLs to upstream's bugtracker. May also contain an email
+ address if prepended with 'mailto:'
+ @type remoteids: list
+ @ivar remoteids: Sequence of tuples containing the project's hosting site
+ name in the first slot and the project's ID name or number for that
+ site in the second, e.g., [('sourceforge', 'systemrescuecd')]
+ """
+
+ def __init__(self, node):
+ self.node = node
+ self.maintainers = self.upstream_maintainers()
+ self.changelogs = self.upstream_changelogs()
+ self.docs = self.upstream_documentation()
+ self.bugtrackers = self.upstream_bugtrackers()
+ self.remoteids = self.upstream_remoteids()
+
+ def __repr__(self):
+ return "<%s %r>" % (self.__class__.__name__, self.__dict__)
+
+ def upstream_bugtrackers(self):
+ """Retrieve upstream bugtracker location from xml node."""
+ return [e.text for e in self.node.findall("bugs-to")]
+
+ def upstream_changelogs(self):
+ """Retrieve upstream changelog location from xml node."""
+ return [e.text for e in self.node.findall("changelog")]
+
+ def upstream_documentation(self):
+ """Retrieve upstream documentation location from xml node."""
+ result = []
+ for elem in self.node.findall("doc"):
+ lang = elem.get("lang")
+ result.append((elem.text, lang))
+ return result
+
+ def upstream_maintainers(self):
+ """Retrieve upstream maintainer information from xml node."""
+ return [_Maintainer(m) for m in self.node.findall("maintainer")]
+
+ def upstream_remoteids(self):
+ """Retrieve upstream remote ID from xml node."""
+ return [(e.text, e.get("type")) for e in self.node.findall("remote-id")]
class MetaData:
- """Access metadata.xml"""
-
- def __init__(self, metadata_path):
- """Parse a valid metadata.xml file.
-
- @type metadata_path: str
- @param metadata_path: path to a valid metadata.xml file
- @raise IOError: if C{metadata_path} can not be read
- """
-
- self.metadata_path = metadata_path
- self._xml_tree = etree.parse(metadata_path)
-
- # Used for caching
- self._herdstree = None
- self._descriptions = None
- self._maintainers = None
- self._useflags = None
- self._upstream = None
-
- def __repr__(self):
- return "<%s %r>" % (self.__class__.__name__, self.metadata_path)
+ """Access metadata.xml"""
+
+ def __init__(self, metadata_path):
+ """Parse a valid metadata.xml file.
+
+ @type metadata_path: str
+ @param metadata_path: path to a valid metadata.xml file
+ @raise IOError: if C{metadata_path} can not be read
+ """
+
+ self.metadata_path = metadata_path
+ self._xml_tree = etree.parse(metadata_path)
+
+ # Used for caching
+ self._herdstree = None
+ self._descriptions = None
+ self._maintainers = None
+ self._useflags = None
+ self._upstream = None
+
+ def __repr__(self):
+ return "<%s %r>" % (self.__class__.__name__, self.metadata_path)
+
+ def _get_herd_email(self, herd):
+ """Get a herd's email address.
+
+ @type herd: str
+ @param herd: herd whose email you want
+ @rtype: str or None
+ @return: email address or None if herd is not in herds.xml
+ @raise IOError: if $PORTDIR/metadata/herds.xml can not be read
+ """
+
+ if self._herdstree is None:
+ herds_path = os.path.join(settings["PORTDIR"], "metadata/herds.xml")
+ try:
+ self._herdstree = etree.parse(herds_path)
+ except IOError:
+ # For some trees, herds.xml may not exist. Bug #300108.
+ return None
+
+ # Some special herds are not listed in herds.xml
+ if herd in ("no-herd", "maintainer-wanted", "maintainer-needed"):
+ return None
+
+ for node in self._herdstree.iter("herd"):
+ if node.findtext("name") == herd:
+ return node.findtext("email")
+
+ def herds(self, include_email=False):
+ """Return a list of text nodes for <herd>.
+
+ @type include_email: bool
+ @keyword include_email: if True, also look up the herd's email
+ @rtype: list
+ @return: if include_email is False, return a list of strings;
+ if include_email is True, return a list of tuples containing:
+ [('herd1', 'herd1@gentoo.org'), ('no-herd', None);
+ """
+
+ result = []
+ for elem in self._xml_tree.findall("herd"):
+ text = elem.text
+ if text is None:
+ text = ""
+ if include_email:
+ herd_mail = self._get_herd_email(text)
+ result.append((text, herd_mail))
+ else:
+ result.append(text)
- def _get_herd_email(self, herd):
- """Get a herd's email address.
-
- @type herd: str
- @param herd: herd whose email you want
- @rtype: str or None
- @return: email address or None if herd is not in herds.xml
- @raise IOError: if $PORTDIR/metadata/herds.xml can not be read
- """
-
- if self._herdstree is None:
- herds_path = os.path.join(settings['PORTDIR'], 'metadata/herds.xml')
- try:
- self._herdstree = etree.parse(herds_path)
- except IOError:
- # For some trees, herds.xml may not exist. Bug #300108.
- return None
+ return result
- # Some special herds are not listed in herds.xml
- if herd in ('no-herd', 'maintainer-wanted', 'maintainer-needed'):
- return None
+ def descriptions(self):
+ """Return a list of text nodes for <longdescription>.
- for node in self._herdstree.iter('herd'):
- if node.findtext('name') == herd:
- return node.findtext('email')
+ @rtype: list
+ @return: package description in string format
+ @todo: Support the C{lang} attribute
+ """
- def herds(self, include_email=False):
- """Return a list of text nodes for <herd>.
+ if self._descriptions is not None:
+ return self._descriptions
- @type include_email: bool
- @keyword include_email: if True, also look up the herd's email
- @rtype: list
- @return: if include_email is False, return a list of strings;
- if include_email is True, return a list of tuples containing:
- [('herd1', 'herd1@gentoo.org'), ('no-herd', None);
- """
+ long_descriptions = self._xml_tree.findall("longdescription")
+ self._descriptions = [e.text for e in long_descriptions]
+ return self._descriptions
- result = []
- for elem in self._xml_tree.findall('herd'):
- text = elem.text
- if text is None:
- text = ''
- if include_email:
- herd_mail = self._get_herd_email(text)
- result.append((text, herd_mail))
- else:
- result.append(text)
+ def maintainers(self):
+ """Get maintainers' name, email and description.
- return result
+ @rtype: list
+ @return: a sequence of L{_Maintainer} objects in document order.
+ """
- def descriptions(self):
- """Return a list of text nodes for <longdescription>.
+ if self._maintainers is not None:
+ return self._maintainers
- @rtype: list
- @return: package description in string format
- @todo: Support the C{lang} attribute
- """
+ self._maintainers = []
+ for node in self._xml_tree.findall("maintainer"):
+ self._maintainers.append(_Maintainer(node))
- if self._descriptions is not None:
- return self._descriptions
+ return self._maintainers
- long_descriptions = self._xml_tree.findall("longdescription")
- self._descriptions = [e.text for e in long_descriptions]
- return self._descriptions
+ def use(self):
+ """Get names and descriptions for USE flags defined in metadata.
- def maintainers(self):
- """Get maintainers' name, email and description.
+ @rtype: list
+ @return: a sequence of L{_Useflag} objects in document order.
+ """
- @rtype: list
- @return: a sequence of L{_Maintainer} objects in document order.
- """
+ if self._useflags is not None:
+ return self._useflags
- if self._maintainers is not None:
- return self._maintainers
+ self._useflags = []
+ for node in self._xml_tree.iter("flag"):
+ self._useflags.append(_Useflag(node))
- self._maintainers = []
- for node in self._xml_tree.findall('maintainer'):
- self._maintainers.append(_Maintainer(node))
+ return self._useflags
- return self._maintainers
-
- def use(self):
- """Get names and descriptions for USE flags defined in metadata.
-
- @rtype: list
- @return: a sequence of L{_Useflag} objects in document order.
- """
-
- if self._useflags is not None:
- return self._useflags
-
- self._useflags = []
- for node in self._xml_tree.iter('flag'):
- self._useflags.append(_Useflag(node))
+ def upstream(self):
+ """Get upstream contact information.
- return self._useflags
+ @rtype: list
+ @return: a sequence of L{_Upstream} objects in document order.
+ """
- def upstream(self):
- """Get upstream contact information.
+ if self._upstream is not None:
+ return self._upstream
- @rtype: list
- @return: a sequence of L{_Upstream} objects in document order.
- """
-
- if self._upstream is not None:
- return self._upstream
+ self._upstream = []
+ for node in self._xml_tree.findall("upstream"):
+ self._upstream.append(_Upstream(node))
- self._upstream = []
- for node in self._xml_tree.findall('upstream'):
- self._upstream.append(_Upstream(node))
+ return self._upstream
- return self._upstream
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/module_base.py b/pym/gentoolkit/module_base.py
index 0632469..e6e668e 100644
--- a/pym/gentoolkit/module_base.py
+++ b/pym/gentoolkit/module_base.py
@@ -7,7 +7,7 @@
"""General Base Module class to hold common module operation functions
"""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
import sys
@@ -17,135 +17,143 @@ import gentoolkit.pprinter as pp
from gentoolkit.formatters import format_options
from gentoolkit.base import mod_usage
+
class ModuleBase:
- """E-app base module class to parse module options print module help, etc.."""
-
- def __init__(self):
- self.module_name = None
- self.options = {}
- self.formatted_options = None
- self.short_opts = None
- self.long_opts = None
- self.module_opts = {}
- self.warning = None
- self.need_queries = True
- self.saved_verbose = None
-
-
- def print_help(self, with_description=True):
- """Print description, usage and a detailed help message.
-
- @type with_description: bool
- @param with_description: if true, print module's __doc__ string
- """
-
- if with_description:
- print()
- print(__doc__.strip())
- print()
- if self.warning:
- print()
- for line in self.warning:
- sys.stderr.write(pp.warn(line))
- print()
- print(mod_usage(mod_name=self.module_name, arg=self.arg_spec, optional=self.arg_option))
- print()
- print(pp.command("options"))
- print(format_options( self.formatted_options ))
- if self.formatted_args:
- print()
- print(pp.command(self.arg_spec))
- print(format_options(self.formatted_args))
- print()
-
- def parse_module_options(self, module_opts):
- """Parse module options and update self.options"""
- opts = (x[0] for x in module_opts)
- posargs = (x[1] for x in module_opts)
- for opt, posarg in zip(opts, posargs):
- if opt in ('-h', '--help'):
- self.print_help()
- sys.exit(0)
- opt_name, opt_type, opt_setting = self.module_opts[opt]
- if opt_type == 'boolean':
- self.options[opt_name] = opt_setting
- elif opt_type == 'int':
- if posarg.isdigit():
- val = int(posarg)
- else:
- print()
- err = "Module option %s requires integer (got '%s')"
- sys.stdout.write(pp.error(err % (opt,posarg)))
- print()
- self.print_help(with_description=False)
- sys.exit(2)
- self.options[opt_name] = val
- elif opt_type == 'char':
- self.options[opt_name] = posarg
-
- def set_quiet(self, quiet):
- """sets the class option["quiet"] and option["verbose"] accordingly"""
- if quiet == self.options['quiet']:
- return
- if self.saved_verbose:
- # detected a switch
- verbose = self.options['verbose']
- self.options['verbose'] = self.saved_verbose
- self.saved_verbose = verbose
- elif quiet:
- self.saved_verbose = self.options['verbose']
- self.options['verbose'] = False
- self.options['quiet'] = quiet
- return
-
- def validate_query(self, query, depth=0):
- """check that the query meets the modules TargetSpec
- If not it attempts to reduce it to a valid TargetSpec
- or prints the help message and exits
- """
- if depth > 1:
- return []
- if len(query) > 1:
- query = list(set(self.arg_options).intersection(query))
- #print "reduced query =", query
- query = self.validate_query(query, depth+1)
- if isinstance(query, list):
- query = query[0]
- if query not in self.arg_options:
- print()
- print(pp.error(
- "Error starting module. Incorrect or No TargetSpec specified!"
- ))
- print("query = ", query)
- self.print_help()
- sys.exit(2)
- return query
-
-
- def main_setup(self, input_args):
- """Parse input and prepares the program"""
-
- try:
- module_opts, queries = gnu_getopt(input_args, self.short_opts, self.long_opts)
- except GetoptError as err:
- sys.stderr.write(pp.error("Module %s" % err))
- print()
- self.print_help(with_description=False)
- sys.exit(2)
- self.parse_module_options(module_opts)
- if self.need_queries and not queries:
- self.print_help()
- sys.exit(2)
- return queries
-
-
- def not_implemented(self, target):
- """Prints a standard module not implemented message"""
- print()
- print(pp.error(
- "Sorry %s module and/or target is not implenented yet."
- % pp.emph(self.command_name)))
- print("module: %s, target: %s" %(pp.emph(self.module_name), pp.emph(target)))
- print()
+ """E-app base module class to parse module options print module help, etc.."""
+
+ def __init__(self):
+ self.module_name = None
+ self.options = {}
+ self.formatted_options = None
+ self.short_opts = None
+ self.long_opts = None
+ self.module_opts = {}
+ self.warning = None
+ self.need_queries = True
+ self.saved_verbose = None
+
+ def print_help(self, with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print()
+ print(__doc__.strip())
+ print()
+ if self.warning:
+ print()
+ for line in self.warning:
+ sys.stderr.write(pp.warn(line))
+ print()
+ print(
+ mod_usage(
+ mod_name=self.module_name, arg=self.arg_spec, optional=self.arg_option
+ )
+ )
+ print()
+ print(pp.command("options"))
+ print(format_options(self.formatted_options))
+ if self.formatted_args:
+ print()
+ print(pp.command(self.arg_spec))
+ print(format_options(self.formatted_args))
+ print()
+
+ def parse_module_options(self, module_opts):
+ """Parse module options and update self.options"""
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ("-h", "--help"):
+ self.print_help()
+ sys.exit(0)
+ opt_name, opt_type, opt_setting = self.module_opts[opt]
+ if opt_type == "boolean":
+ self.options[opt_name] = opt_setting
+ elif opt_type == "int":
+ if posarg.isdigit():
+ val = int(posarg)
+ else:
+ print()
+ err = "Module option %s requires integer (got '%s')"
+ sys.stdout.write(pp.error(err % (opt, posarg)))
+ print()
+ self.print_help(with_description=False)
+ sys.exit(2)
+ self.options[opt_name] = val
+ elif opt_type == "char":
+ self.options[opt_name] = posarg
+
+ def set_quiet(self, quiet):
+ """sets the class option["quiet"] and option["verbose"] accordingly"""
+ if quiet == self.options["quiet"]:
+ return
+ if self.saved_verbose:
+ # detected a switch
+ verbose = self.options["verbose"]
+ self.options["verbose"] = self.saved_verbose
+ self.saved_verbose = verbose
+ elif quiet:
+ self.saved_verbose = self.options["verbose"]
+ self.options["verbose"] = False
+ self.options["quiet"] = quiet
+ return
+
+ def validate_query(self, query, depth=0):
+ """check that the query meets the modules TargetSpec
+ If not it attempts to reduce it to a valid TargetSpec
+ or prints the help message and exits
+ """
+ if depth > 1:
+ return []
+ if len(query) > 1:
+ query = list(set(self.arg_options).intersection(query))
+ # print "reduced query =", query
+ query = self.validate_query(query, depth + 1)
+ if isinstance(query, list):
+ query = query[0]
+ if query not in self.arg_options:
+ print()
+ print(
+ pp.error("Error starting module. Incorrect or No TargetSpec specified!")
+ )
+ print("query = ", query)
+ self.print_help()
+ sys.exit(2)
+ return query
+
+ def main_setup(self, input_args):
+ """Parse input and prepares the program"""
+
+ try:
+ module_opts, queries = gnu_getopt(
+ input_args, self.short_opts, self.long_opts
+ )
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Module %s" % err))
+ print()
+ self.print_help(with_description=False)
+ sys.exit(2)
+ self.parse_module_options(module_opts)
+ if self.need_queries and not queries:
+ self.print_help()
+ sys.exit(2)
+ return queries
+
+ def not_implemented(self, target):
+ """Prints a standard module not implemented message"""
+ print()
+ print(
+ pp.error(
+ "Sorry %s module and/or target is not implenented yet."
+ % pp.emph(self.command_name)
+ )
+ )
+ print("module: %s, target: %s" % (pp.emph(self.module_name), pp.emph(target)))
+ print()
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/package.py b/pym/gentoolkit/package.py
index 4c851bc..92bc3a3 100644
--- a/pym/gentoolkit/package.py
+++ b/pym/gentoolkit/package.py
@@ -20,19 +20,26 @@ Example usage:
False
"""
-__all__ = (
- 'Package',
- 'PackageFormatter',
- 'FORMAT_TMPL_VARS'
-)
+__all__ = ("Package", "PackageFormatter", "FORMAT_TMPL_VARS")
# =======
# Globals
# =======
FORMAT_TMPL_VARS = (
- '$location', '$mask', '$mask2', '$cp', '$cpv', '$category', '$name',
- '$version', '$revision', '$fullversion', '$slot', '$repo', '$keywords'
+ "$location",
+ "$mask",
+ "$mask2",
+ "$cp",
+ "$cpv",
+ "$category",
+ "$name",
+ "$version",
+ "$revision",
+ "$fullversion",
+ "$slot",
+ "$repo",
+ "$keywords",
)
# =======
@@ -57,13 +64,18 @@ from gentoolkit.eprefix import EPREFIX
# Settings
# =======
+
def _NewPortageConfig(local_config):
- ret = portage.config(local_config=local_config,
- eprefix=EPREFIX if EPREFIX else None,
- config_root=os.environ.get('PORTAGE_CONFIGROOT', None),
- target_root=os.environ.get('ROOT', None))
- ret.lock()
- return ret
+ ret = portage.config(
+ local_config=local_config,
+ eprefix=EPREFIX if EPREFIX else None,
+ config_root=os.environ.get("PORTAGE_CONFIGROOT", None),
+ target_root=os.environ.get("ROOT", None),
+ )
+ ret.lock()
+ return ret
+
+
default_settings = _NewPortageConfig(local_config=True)
nolocal_settings = _NewPortageConfig(local_config=False)
@@ -71,555 +83,555 @@ nolocal_settings = _NewPortageConfig(local_config=False)
# Classes
# =======
-class Package(CPV):
- """Exposes the state of a given CPV."""
-
- def __init__(self, cpv, validate=False, local_config=True):
- if isinstance(cpv, CPV):
- self.__dict__.update(cpv.__dict__)
- else:
- CPV.__init__(self, cpv, validate=validate)
-
- if validate and not all(
- hasattr(self, x) for x in ('category', 'version')
- ):
- # CPV allows some things that Package must not
- raise errors.GentoolkitInvalidPackage(self.cpv)
-
- if local_config:
- self._settings = default_settings
- else:
- self._settings = nolocal_settings
-
- # Set dynamically
- self._package_path = None
- self._dblink = None
- self._metadata = None
- self._deps = None
- self._portdir_path = None
-
- def __repr__(self):
- return "<%s %r>" % (self.__class__.__name__, self.cpv)
-
- def __hash__(self):
- return hash(self.cpv)
-
- def __contains__(self, key):
- return key in self.cpv
-
- def __str__(self):
- return str(self.cpv)
-
- @property
- def metadata(self):
- """Instantiate a L{gentoolkit.metadata.MetaData} object here."""
-
- from gentoolkit.metadata import MetaData
-
- if self._metadata is None:
- metadata_path = os.path.join(
- self.package_path(), 'metadata.xml'
- )
- try:
- self._metadata = MetaData(metadata_path)
- except IOError as error:
- import errno
- if error.errno != errno.ENOENT:
- raise
- return None
-
- return self._metadata
-
- @property
- def dblink(self):
- """Instantiate a L{portage.dbapi.vartree.dblink} object here."""
-
- if self._dblink is None:
- self._dblink = portage.dblink(
- self.category,
- "%s-%s" % (self.name, self.fullversion),
- self._settings["ROOT"],
- self._settings
- )
-
- return self._dblink
-
- @property
- def deps(self):
- """Instantiate a L{gentoolkit.dependencies.Dependencies} object here."""
-
- from gentoolkit.dependencies import Dependencies
-
- if self._deps is None:
- self._deps = Dependencies(self.cpv)
-
- return self._deps
-
- def environment(self, envvars, prefer_vdb=True, fallback=True):
- """Returns one or more of the predefined environment variables.
-
- Some available envvars are:
- ----------------------
- BINPKGMD5 COUNTER FEATURES LICENSE SRC_URI
- CATEGORY CXXFLAGS HOMEPAGE PDEPEND USE
- CBUILD DEFINED_PHASES INHERITED PF
- CFLAGS DEPEND IUSE PROVIDE
- CHOST DESCRIPTION KEYWORDS RDEPEND
- CONTENTS EAPI LDFLAGS SLOT
-
- Example usage:
- >>> pkg = Package('sys-apps/portage-9999')
- >>> pkg.environment('USE')
- ''
- >>> pkg.environment(('USE', 'IUSE'))
- ... # doctest: +NORMALIZE_WHITESPACE
- ['', 'build doc epydoc +ipc pypy1_9 python2 python3
- selinux xattr']
-
- @type envvars: str or array
- @param envvars: one or more of (DEPEND, SRC_URI, etc.)
- @type prefer_vdb: bool
- @keyword prefer_vdb: if True, look in the vardb before portdb, else
- reverse order. Specifically KEYWORDS will get more recent
- information by preferring portdb.
- @type fallback: bool
- @keyword fallback: query only the preferred db if False
- @rtype: str or list
- @return: str if envvars is str, list if envvars is array
- @raise KeyError: if key is not found in requested db(s)
- """
-
- got_string = False
- if isinstance(envvars, str):
- got_string = True
- envvars = (envvars,)
- if prefer_vdb:
- try:
- result = portage.db[portage.root][
- 'vartree'].dbapi.aux_get(
- self.cpv, envvars)
- except KeyError:
- try:
- if not fallback:
- raise KeyError
- result = portage.db[portage.root][
- 'porttree'].dbapi.aux_get(
- self.cpv, envvars)
- except KeyError:
- raise errors.GentoolkitFatalError(
- 'aux_get returned unexpected '
- 'results')
- else:
- try:
- result = portage.db[portage.root][
- 'porttree'].dbapi.aux_get(
- self.cpv, envvars)
- except KeyError:
- try:
- if not fallback:
- raise KeyError
- result = portage.db[portage.root][
- 'vartree'].dbapi.aux_get(
- self.cpv, envvars)
- except KeyError:
- raise errors.GentoolkitFatalError(
- 'aux_get returned unexpected '
- 'results')
-
- if got_string:
- return result[0]
- return result
-
- def exists(self):
- """Return True if package exists in the Portage tree, else False"""
-
- return bool(portage.db[portage.root]["porttree"].dbapi.cpv_exists(self.cpv))
-
- def settings(self, key):
- """Returns the value of the given key for this package (useful
- for package.* files."""
-
- if self._settings.locked:
- self._settings.unlock()
- try:
- result = self._settings[key]
- finally:
- self._settings.lock()
- return result
-
- def mask_status(self):
- """Shortcut to L{portage.getmaskingstatus}.
-
- @rtype: None or list
- @return: a list containing none or some of:
- 'profile'
- 'package.mask'
- license(s)
- "kmask" keyword
- 'missing keyword'
- """
-
- if self._settings.locked:
- self._settings.unlock()
- try:
- result = portage.getmaskingstatus(self.cpv,
- settings=self._settings,
- portdb=portage.db[portage.root]["porttree"].dbapi)
- except KeyError:
- # getmaskingstatus doesn't support packages without ebuilds in the
- # Portage tree.
- result = None
-
- return result
-
- def mask_reason(self):
- """Shortcut to L{portage.getmaskingreason}.
-
- @rtype: None or tuple
- @return: empty tuple if pkg not masked OR
- ('mask reason', 'mask location')
- """
-
- try:
- result = portage.getmaskingreason(self.cpv,
- settings=self._settings,
- portdb=portage.db[portage.root]["porttree"].dbapi,
- return_location=True)
- if result is None:
- result = tuple()
- except KeyError:
- # getmaskingstatus doesn't support packages without ebuilds in the
- # Portage tree.
- result = None
-
- return result
-
- def ebuild_path(self, in_vartree=False):
- """Returns the complete path to the .ebuild file.
-
- Example usage:
- >>> pkg = Package('sys-apps/portage-9999')
- >>> pkg.ebuild_path()
- '/usr/portage/sys-apps/portage/portage-9999.ebuild'
- >>> pkg.ebuild_path(in_vartree=True)
- '/var/db/pkg/sys-apps/portage-9999/portage-9999.ebuild'
- """
-
- if in_vartree:
- return portage.db[portage.root]["vartree"].dbapi.findname(self.cpv)
- return portage.db[portage.root]["porttree"].dbapi.findname(self.cpv)
-
- def package_path(self, in_vartree=False):
- """Return the path to where the ebuilds and other files reside."""
-
- if in_vartree:
- return self.dblink.getpath()
- return os.sep.join(self.ebuild_path().split(os.sep)[:-1])
-
- def repo_name(self, fallback=True):
- """Determine the repository name.
-
- @type fallback: bool
- @param fallback: if the repo_name file does not exist, return the
- repository name from the path
- @rtype: str
- @return: output of the repository metadata file, which stores the
- repo_name variable, or try to get the name of the repo from
- the path.
- @raise GentoolkitFatalError: if fallback is False and repo_name is
- not specified by the repository.
- """
-
- try:
- return self.environment('repository')
- except errors.GentoolkitFatalError:
- if fallback:
- return self.package_path().split(os.sep)[-3]
- raise
-
- def use(self):
- """Returns the USE flags active at time of installation."""
-
- return self.dblink.getstring("USE")
-
- def use_status(self):
- """Returns the USE flags active for installation."""
-
- iuse, final_flags = get_flags(self.cpv, final_setting=True)
- return final_flags
-
- def parsed_contents(self, prefix_root=False):
- """Returns the parsed CONTENTS file.
-
- @rtype: dict
- @return: {'/full/path/to/obj': ['type', 'timestamp', 'md5sum'], ...}
- """
-
- contents = self.dblink.getcontents()
-
- # Portage will automatically prepend ROOT. Undo that.
- if not prefix_root:
- myroot = self._settings["ROOT"]
- if myroot != '/':
- ret = {}
- for key, val in self.dblink.getcontents().items():
- ret['/' + os.path.relpath(key, myroot)] = val
- contents = ret
-
- return contents
-
- def size(self):
- """Estimates the installed size of the contents of this package.
-
- @rtype: tuple
- @return: (size, number of files in total, number of uncounted files)
- """
-
- seen = set()
- size = n_files = n_uncounted = 0
- for path in self.parsed_contents(prefix_root=True):
- try:
- st = os.lstat(_unicode_encode(path, encoding=_encodings['fs']))
- except OSError:
- continue
-
- # Remove hardlinks by checking for duplicate inodes. Bug #301026.
- file_inode = st.st_ino
- if file_inode in seen:
- continue
- seen.add(file_inode)
-
- try:
- size += st.st_size
- n_files += 1
- except OSError:
- n_uncounted += 1
-
- return (size, n_files, n_uncounted)
- def is_installed(self):
- """Returns True if this package is installed (merged)."""
-
- return self.dblink.exists()
+class Package(CPV):
+ """Exposes the state of a given CPV."""
+
+ def __init__(self, cpv, validate=False, local_config=True):
+ if isinstance(cpv, CPV):
+ self.__dict__.update(cpv.__dict__)
+ else:
+ CPV.__init__(self, cpv, validate=validate)
+
+ if validate and not all(hasattr(self, x) for x in ("category", "version")):
+ # CPV allows some things that Package must not
+ raise errors.GentoolkitInvalidPackage(self.cpv)
+
+ if local_config:
+ self._settings = default_settings
+ else:
+ self._settings = nolocal_settings
+
+ # Set dynamically
+ self._package_path = None
+ self._dblink = None
+ self._metadata = None
+ self._deps = None
+ self._portdir_path = None
+
+ def __repr__(self):
+ return "<%s %r>" % (self.__class__.__name__, self.cpv)
+
+ def __hash__(self):
+ return hash(self.cpv)
+
+ def __contains__(self, key):
+ return key in self.cpv
+
+ def __str__(self):
+ return str(self.cpv)
+
+ @property
+ def metadata(self):
+ """Instantiate a L{gentoolkit.metadata.MetaData} object here."""
+
+ from gentoolkit.metadata import MetaData
+
+ if self._metadata is None:
+ metadata_path = os.path.join(self.package_path(), "metadata.xml")
+ try:
+ self._metadata = MetaData(metadata_path)
+ except IOError as error:
+ import errno
+
+ if error.errno != errno.ENOENT:
+ raise
+ return None
+
+ return self._metadata
+
+ @property
+ def dblink(self):
+ """Instantiate a L{portage.dbapi.vartree.dblink} object here."""
+
+ if self._dblink is None:
+ self._dblink = portage.dblink(
+ self.category,
+ "%s-%s" % (self.name, self.fullversion),
+ self._settings["ROOT"],
+ self._settings,
+ )
+
+ return self._dblink
+
+ @property
+ def deps(self):
+ """Instantiate a L{gentoolkit.dependencies.Dependencies} object here."""
+
+ from gentoolkit.dependencies import Dependencies
+
+ if self._deps is None:
+ self._deps = Dependencies(self.cpv)
+
+ return self._deps
+
+ def environment(self, envvars, prefer_vdb=True, fallback=True):
+ """Returns one or more of the predefined environment variables.
+
+ Some available envvars are:
+ ----------------------
+ BINPKGMD5 COUNTER FEATURES LICENSE SRC_URI
+ CATEGORY CXXFLAGS HOMEPAGE PDEPEND USE
+ CBUILD DEFINED_PHASES INHERITED PF
+ CFLAGS DEPEND IUSE PROVIDE
+ CHOST DESCRIPTION KEYWORDS RDEPEND
+ CONTENTS EAPI LDFLAGS SLOT
+
+ Example usage:
+ >>> pkg = Package('sys-apps/portage-9999')
+ >>> pkg.environment('USE')
+ ''
+ >>> pkg.environment(('USE', 'IUSE'))
+ ... # doctest: +NORMALIZE_WHITESPACE
+ ['', 'build doc epydoc +ipc pypy1_9 python2 python3
+ selinux xattr']
+
+ @type envvars: str or array
+ @param envvars: one or more of (DEPEND, SRC_URI, etc.)
+ @type prefer_vdb: bool
+ @keyword prefer_vdb: if True, look in the vardb before portdb, else
+ reverse order. Specifically KEYWORDS will get more recent
+ information by preferring portdb.
+ @type fallback: bool
+ @keyword fallback: query only the preferred db if False
+ @rtype: str or list
+ @return: str if envvars is str, list if envvars is array
+ @raise KeyError: if key is not found in requested db(s)
+ """
+
+ got_string = False
+ if isinstance(envvars, str):
+ got_string = True
+ envvars = (envvars,)
+ if prefer_vdb:
+ try:
+ result = portage.db[portage.root]["vartree"].dbapi.aux_get(
+ self.cpv, envvars
+ )
+ except KeyError:
+ try:
+ if not fallback:
+ raise KeyError
+ result = portage.db[portage.root]["porttree"].dbapi.aux_get(
+ self.cpv, envvars
+ )
+ except KeyError:
+ raise errors.GentoolkitFatalError(
+ "aux_get returned unexpected " "results"
+ )
+ else:
+ try:
+ result = portage.db[portage.root]["porttree"].dbapi.aux_get(
+ self.cpv, envvars
+ )
+ except KeyError:
+ try:
+ if not fallback:
+ raise KeyError
+ result = portage.db[portage.root]["vartree"].dbapi.aux_get(
+ self.cpv, envvars
+ )
+ except KeyError:
+ raise errors.GentoolkitFatalError(
+ "aux_get returned unexpected " "results"
+ )
+
+ if got_string:
+ return result[0]
+ return result
+
+ def exists(self):
+ """Return True if package exists in the Portage tree, else False"""
+
+ return bool(portage.db[portage.root]["porttree"].dbapi.cpv_exists(self.cpv))
+
+ def settings(self, key):
+ """Returns the value of the given key for this package (useful
+ for package.* files."""
+
+ if self._settings.locked:
+ self._settings.unlock()
+ try:
+ result = self._settings[key]
+ finally:
+ self._settings.lock()
+ return result
+
+ def mask_status(self):
+ """Shortcut to L{portage.getmaskingstatus}.
+
+ @rtype: None or list
+ @return: a list containing none or some of:
+ 'profile'
+ 'package.mask'
+ license(s)
+ "kmask" keyword
+ 'missing keyword'
+ """
+
+ if self._settings.locked:
+ self._settings.unlock()
+ try:
+ result = portage.getmaskingstatus(
+ self.cpv,
+ settings=self._settings,
+ portdb=portage.db[portage.root]["porttree"].dbapi,
+ )
+ except KeyError:
+ # getmaskingstatus doesn't support packages without ebuilds in the
+ # Portage tree.
+ result = None
+
+ return result
+
+ def mask_reason(self):
+ """Shortcut to L{portage.getmaskingreason}.
+
+ @rtype: None or tuple
+ @return: empty tuple if pkg not masked OR
+ ('mask reason', 'mask location')
+ """
+
+ try:
+ result = portage.getmaskingreason(
+ self.cpv,
+ settings=self._settings,
+ portdb=portage.db[portage.root]["porttree"].dbapi,
+ return_location=True,
+ )
+ if result is None:
+ result = tuple()
+ except KeyError:
+ # getmaskingstatus doesn't support packages without ebuilds in the
+ # Portage tree.
+ result = None
+
+ return result
+
+ def ebuild_path(self, in_vartree=False):
+ """Returns the complete path to the .ebuild file.
+
+ Example usage:
+ >>> pkg = Package('sys-apps/portage-9999')
+ >>> pkg.ebuild_path()
+ '/usr/portage/sys-apps/portage/portage-9999.ebuild'
+ >>> pkg.ebuild_path(in_vartree=True)
+ '/var/db/pkg/sys-apps/portage-9999/portage-9999.ebuild'
+ """
+
+ if in_vartree:
+ return portage.db[portage.root]["vartree"].dbapi.findname(self.cpv)
+ return portage.db[portage.root]["porttree"].dbapi.findname(self.cpv)
+
+ def package_path(self, in_vartree=False):
+ """Return the path to where the ebuilds and other files reside."""
+
+ if in_vartree:
+ return self.dblink.getpath()
+ return os.sep.join(self.ebuild_path().split(os.sep)[:-1])
+
+ def repo_name(self, fallback=True):
+ """Determine the repository name.
+
+ @type fallback: bool
+ @param fallback: if the repo_name file does not exist, return the
+ repository name from the path
+ @rtype: str
+ @return: output of the repository metadata file, which stores the
+ repo_name variable, or try to get the name of the repo from
+ the path.
+ @raise GentoolkitFatalError: if fallback is False and repo_name is
+ not specified by the repository.
+ """
+
+ try:
+ return self.environment("repository")
+ except errors.GentoolkitFatalError:
+ if fallback:
+ return self.package_path().split(os.sep)[-3]
+ raise
+
+ def use(self):
+ """Returns the USE flags active at time of installation."""
+
+ return self.dblink.getstring("USE")
+
+ def use_status(self):
+ """Returns the USE flags active for installation."""
+
+ iuse, final_flags = get_flags(self.cpv, final_setting=True)
+ return final_flags
+
+ def parsed_contents(self, prefix_root=False):
+ """Returns the parsed CONTENTS file.
+
+ @rtype: dict
+ @return: {'/full/path/to/obj': ['type', 'timestamp', 'md5sum'], ...}
+ """
+
+ contents = self.dblink.getcontents()
+
+ # Portage will automatically prepend ROOT. Undo that.
+ if not prefix_root:
+ myroot = self._settings["ROOT"]
+ if myroot != "/":
+ ret = {}
+ for key, val in self.dblink.getcontents().items():
+ ret["/" + os.path.relpath(key, myroot)] = val
+ contents = ret
+
+ return contents
+
+ def size(self):
+ """Estimates the installed size of the contents of this package.
+
+ @rtype: tuple
+ @return: (size, number of files in total, number of uncounted files)
+ """
+
+ seen = set()
+ size = n_files = n_uncounted = 0
+ for path in self.parsed_contents(prefix_root=True):
+ try:
+ st = os.lstat(_unicode_encode(path, encoding=_encodings["fs"]))
+ except OSError:
+ continue
+
+ # Remove hardlinks by checking for duplicate inodes. Bug #301026.
+ file_inode = st.st_ino
+ if file_inode in seen:
+ continue
+ seen.add(file_inode)
+
+ try:
+ size += st.st_size
+ n_files += 1
+ except OSError:
+ n_uncounted += 1
+
+ return (size, n_files, n_uncounted)
+
+ def is_installed(self):
+ """Returns True if this package is installed (merged)."""
+
+ return self.dblink.exists()
- def is_overlay(self):
- """Returns True if the package is in an overlay."""
+ def is_overlay(self):
+ """Returns True if the package is in an overlay."""
- ebuild, tree = portage.db[portage.root]["porttree"].dbapi.findname2(self.cpv)
- if not ebuild:
- return None
- if self._portdir_path is None:
- self._portdir_path = os.path.realpath(self._settings["PORTDIR"])
- return (tree and tree != self._portdir_path)
+ ebuild, tree = portage.db[portage.root]["porttree"].dbapi.findname2(self.cpv)
+ if not ebuild:
+ return None
+ if self._portdir_path is None:
+ self._portdir_path = os.path.realpath(self._settings["PORTDIR"])
+ return tree and tree != self._portdir_path
- def is_masked(self):
- """Returns True if this package is masked against installation.
+ def is_masked(self):
+ """Returns True if this package is masked against installation.
- @note: We blindly assume that the package actually exists on disk.
- """
+ @note: We blindly assume that the package actually exists on disk.
+ """
- unmasked = portage.db[portage.root]['porttree'].dbapi.xmatch(
- 'match-visible', self.cpv)
- return self.cpv not in unmasked
+ unmasked = portage.db[portage.root]["porttree"].dbapi.xmatch(
+ "match-visible", self.cpv
+ )
+ return self.cpv not in unmasked
class PackageFormatter:
- """When applied to a L{gentoolkit.package.Package} object, determine the
- location (Portage Tree vs. overlay), install status and masked status. That
- information can then be easily formatted and displayed.
-
- Example usage:
- >>> from gentoolkit.query import Query
- >>> from gentoolkit.package import PackageFormatter
- >>> import portage.output
- >>> q = Query('gcc')
- >>> pkgs = [PackageFormatter(x) for x in q.find()]
- >>> havecolor = portage.output.havecolor
- >>> portage.output.havecolor = False
- >>> for pkg in pkgs:
- ... # Only print packages that are installed and from the Portage
- ... # tree
- ... if set('IP').issubset(pkg.location):
- ... print(pkg)
- ...
- [IP-] [ ] sys-devel/gcc-4.5.4:4.5
- >>> portage.output.havecolor = havecolor
-
- @type pkg: L{gentoolkit.package.Package}
- @param pkg: package to format
- @type do_format: bool
- @param do_format: Whether to format the package name or not.
- Essentially C{do_format} should be set to False when piping or when
- quiet output is desired. If C{do_format} is False, only the location
- attribute will be created to save time.
- """
-
- _tmpl_verbose = "[$location] [$mask] $cpv:$slot"
- _tmpl_quiet = "$cpv"
-
- def __init__(self, pkg, do_format=True, custom_format=None):
- self._pkg = None
- self._do_format = do_format
- self._str = None
- self._location = None
- if not custom_format:
- if do_format:
- custom_format = self._tmpl_verbose
- else:
- custom_format = self._tmpl_quiet
- self.tmpl = Template(custom_format)
- self.format_vars = LazyItemsDict()
- self.pkg = pkg
-
- def __repr__(self):
- return "<%s %s @%#8x>" % (self.__class__.__name__, self.pkg, id(self))
-
- def __str__(self):
- if self._str is None:
- self._str = self.tmpl.safe_substitute(self.format_vars)
- return self._str
-
- @property
- def location(self):
- if self._location is None:
- self._location = self.format_package_location()
- return self._location
-
- @property
- def pkg(self):
- """Package to format"""
- return self._pkg
-
- @pkg.setter
- def pkg(self, value):
- if self._pkg == value:
- return
- self._pkg = value
- self._location = None
-
- fmt_vars = self.format_vars
- self.format_vars.clear()
- fmt_vars.addLazySingleton("location",
- lambda: getattr(self, "location"))
- fmt_vars.addLazySingleton("mask", self.format_mask)
- fmt_vars.addLazySingleton("mask2", self.format_mask_status2)
- fmt_vars.addLazySingleton("cpv", self.format_cpv)
- fmt_vars.addLazySingleton("cp", self.format_cpv, "cp")
- fmt_vars.addLazySingleton("category", self.format_cpv, "category")
- fmt_vars.addLazySingleton("name", self.format_cpv, "name")
- fmt_vars.addLazySingleton("version", self.format_cpv, "version")
- fmt_vars.addLazySingleton("revision", self.format_cpv, "revision")
- fmt_vars.addLazySingleton("fullversion", self.format_cpv,
- "fullversion")
- fmt_vars.addLazySingleton("slot", self.format_slot)
- fmt_vars.addLazySingleton("repo", self.pkg.repo_name)
- fmt_vars.addLazySingleton("keywords", self.format_keywords)
-
- def format_package_location(self):
- """Get the install status (in /var/db/?) and origin (from an overlay
- and the Portage tree?).
-
- @rtype: str
- @return: one of:
- 'I--' : Installed but ebuild doesn't exist on system anymore
- '-P-' : Not installed and from the Portage tree
- '--O' : Not installed and from an overlay
- 'IP-' : Installed and from the Portage tree
- 'I-O' : Installed and from an overlay
- """
-
- result = ['-', '-', '-']
-
- if self.pkg.is_installed():
- result[0] = 'I'
-
- overlay = self.pkg.is_overlay()
- if overlay is None:
- pass
- elif overlay:
- result[2] = 'O'
- else:
- result[1] = 'P'
-
- return ''.join(result)
-
- def format_mask_status(self):
- """Get the mask status of a given package.
-
- @rtype: tuple: (int, list)
- @return: int = an index for this list:
- [" ", " ~", " -", "M ", "M~", "M-", "??"]
- 0 = not masked
- 1 = keyword masked
- 2 = arch masked
- 3 = hard masked
- 4 = hard and keyword masked,
- 5 = hard and arch masked
- 6 = ebuild doesn't exist on system anymore
-
- list = original output of portage.getmaskingstatus
- """
-
- result = 0
- masking_status = self.pkg.mask_status()
- if masking_status is None:
- return (6, [])
-
- if ("~%s keyword" % self.pkg.settings("ARCH")) in masking_status:
- result += 1
- if "missing keyword" in masking_status:
- result += 2
- if set(('profile', 'package.mask')).intersection(masking_status):
- result += 3
-
- return (result, masking_status)
-
- def format_mask_status2(self):
- """Get the mask status of a given package.
- """
- mask = self.pkg.mask_status()
- if mask:
- return pp.masking(mask)
- else:
- arch = self.pkg.settings("ARCH")
- keywords = self.pkg.environment('KEYWORDS')
- mask = [determine_keyword(arch,
- portage.settings["ACCEPT_KEYWORDS"],
- keywords)]
- return pp.masking(mask)
-
- def format_mask(self):
- maskmodes = [' ', ' ~', ' -', 'M ', 'M~', 'M-', '??']
- maskmode = maskmodes[self.format_mask_status()[0]]
- return pp.keyword(
- maskmode,
- stable=not maskmode.strip(),
- hard_masked=set(('M', '?', '-')).intersection(maskmode)
- )
-
- def format_cpv(self, attr=None):
- if attr is None:
- value = self.pkg.cpv
- else:
- value = getattr(self.pkg, attr)
- if self._do_format:
- return pp.cpv(value)
- else:
- return value
-
- def format_slot(self):
- value = self.pkg.environment("SLOT")
- if self._do_format:
- return pp.slot(value)
- else:
- return value
-
- def format_keywords(self):
- value = self.pkg.environment("KEYWORDS")
- if self._do_format:
- return pp.keyword(value)
- else:
- return value
+ """When applied to a L{gentoolkit.package.Package} object, determine the
+ location (Portage Tree vs. overlay), install status and masked status. That
+ information can then be easily formatted and displayed.
+
+ Example usage:
+ >>> from gentoolkit.query import Query
+ >>> from gentoolkit.package import PackageFormatter
+ >>> import portage.output
+ >>> q = Query('gcc')
+ >>> pkgs = [PackageFormatter(x) for x in q.find()]
+ >>> havecolor = portage.output.havecolor
+ >>> portage.output.havecolor = False
+ >>> for pkg in pkgs:
+ ... # Only print packages that are installed and from the Portage
+ ... # tree
+ ... if set('IP').issubset(pkg.location):
+ ... print(pkg)
+ ...
+ [IP-] [ ] sys-devel/gcc-4.5.4:4.5
+ >>> portage.output.havecolor = havecolor
+
+ @type pkg: L{gentoolkit.package.Package}
+ @param pkg: package to format
+ @type do_format: bool
+ @param do_format: Whether to format the package name or not.
+ Essentially C{do_format} should be set to False when piping or when
+ quiet output is desired. If C{do_format} is False, only the location
+ attribute will be created to save time.
+ """
+
+ _tmpl_verbose = "[$location] [$mask] $cpv:$slot"
+ _tmpl_quiet = "$cpv"
+
+ def __init__(self, pkg, do_format=True, custom_format=None):
+ self._pkg = None
+ self._do_format = do_format
+ self._str = None
+ self._location = None
+ if not custom_format:
+ if do_format:
+ custom_format = self._tmpl_verbose
+ else:
+ custom_format = self._tmpl_quiet
+ self.tmpl = Template(custom_format)
+ self.format_vars = LazyItemsDict()
+ self.pkg = pkg
+
+ def __repr__(self):
+ return "<%s %s @%#8x>" % (self.__class__.__name__, self.pkg, id(self))
+
+ def __str__(self):
+ if self._str is None:
+ self._str = self.tmpl.safe_substitute(self.format_vars)
+ return self._str
+
+ @property
+ def location(self):
+ if self._location is None:
+ self._location = self.format_package_location()
+ return self._location
+
+ @property
+ def pkg(self):
+ """Package to format"""
+ return self._pkg
+
+ @pkg.setter
+ def pkg(self, value):
+ if self._pkg == value:
+ return
+ self._pkg = value
+ self._location = None
+
+ fmt_vars = self.format_vars
+ self.format_vars.clear()
+ fmt_vars.addLazySingleton("location", lambda: getattr(self, "location"))
+ fmt_vars.addLazySingleton("mask", self.format_mask)
+ fmt_vars.addLazySingleton("mask2", self.format_mask_status2)
+ fmt_vars.addLazySingleton("cpv", self.format_cpv)
+ fmt_vars.addLazySingleton("cp", self.format_cpv, "cp")
+ fmt_vars.addLazySingleton("category", self.format_cpv, "category")
+ fmt_vars.addLazySingleton("name", self.format_cpv, "name")
+ fmt_vars.addLazySingleton("version", self.format_cpv, "version")
+ fmt_vars.addLazySingleton("revision", self.format_cpv, "revision")
+ fmt_vars.addLazySingleton("fullversion", self.format_cpv, "fullversion")
+ fmt_vars.addLazySingleton("slot", self.format_slot)
+ fmt_vars.addLazySingleton("repo", self.pkg.repo_name)
+ fmt_vars.addLazySingleton("keywords", self.format_keywords)
+
+ def format_package_location(self):
+ """Get the install status (in /var/db/?) and origin (from an overlay
+ and the Portage tree?).
+
+ @rtype: str
+ @return: one of:
+ 'I--' : Installed but ebuild doesn't exist on system anymore
+ '-P-' : Not installed and from the Portage tree
+ '--O' : Not installed and from an overlay
+ 'IP-' : Installed and from the Portage tree
+ 'I-O' : Installed and from an overlay
+ """
+
+ result = ["-", "-", "-"]
+
+ if self.pkg.is_installed():
+ result[0] = "I"
+
+ overlay = self.pkg.is_overlay()
+ if overlay is None:
+ pass
+ elif overlay:
+ result[2] = "O"
+ else:
+ result[1] = "P"
+
+ return "".join(result)
+
+ def format_mask_status(self):
+ """Get the mask status of a given package.
+
+ @rtype: tuple: (int, list)
+ @return: int = an index for this list:
+ [" ", " ~", " -", "M ", "M~", "M-", "??"]
+ 0 = not masked
+ 1 = keyword masked
+ 2 = arch masked
+ 3 = hard masked
+ 4 = hard and keyword masked,
+ 5 = hard and arch masked
+ 6 = ebuild doesn't exist on system anymore
+
+ list = original output of portage.getmaskingstatus
+ """
+
+ result = 0
+ masking_status = self.pkg.mask_status()
+ if masking_status is None:
+ return (6, [])
+
+ if ("~%s keyword" % self.pkg.settings("ARCH")) in masking_status:
+ result += 1
+ if "missing keyword" in masking_status:
+ result += 2
+ if set(("profile", "package.mask")).intersection(masking_status):
+ result += 3
+
+ return (result, masking_status)
+
+ def format_mask_status2(self):
+ """Get the mask status of a given package."""
+ mask = self.pkg.mask_status()
+ if mask:
+ return pp.masking(mask)
+ else:
+ arch = self.pkg.settings("ARCH")
+ keywords = self.pkg.environment("KEYWORDS")
+ mask = [
+ determine_keyword(arch, portage.settings["ACCEPT_KEYWORDS"], keywords)
+ ]
+ return pp.masking(mask)
+
+ def format_mask(self):
+ maskmodes = [" ", " ~", " -", "M ", "M~", "M-", "??"]
+ maskmode = maskmodes[self.format_mask_status()[0]]
+ return pp.keyword(
+ maskmode,
+ stable=not maskmode.strip(),
+ hard_masked=set(("M", "?", "-")).intersection(maskmode),
+ )
+
+ def format_cpv(self, attr=None):
+ if attr is None:
+ value = self.pkg.cpv
+ else:
+ value = getattr(self.pkg, attr)
+ if self._do_format:
+ return pp.cpv(value)
+ else:
+ return value
+
+ def format_slot(self):
+ value = self.pkg.environment("SLOT")
+ if self._do_format:
+ return pp.slot(value)
+ else:
+ return value
+
+ def format_keywords(self):
+ value = self.pkg.environment("KEYWORDS")
+ if self._do_format:
+ return pp.keyword(value)
+ else:
+ return value
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/pprinter.py b/pym/gentoolkit/pprinter.py
index 25e145b..c42c354 100644
--- a/pym/gentoolkit/pprinter.py
+++ b/pym/gentoolkit/pprinter.py
@@ -7,24 +7,24 @@
"""Provides a consistent color scheme for Gentoolkit scripts."""
__all__ = (
- 'command',
- 'cpv',
- 'die',
- 'emph',
- 'error',
- 'globaloption',
- 'localoption',
- 'number',
- 'path',
- 'path_symlink',
- 'pkgquery',
- 'productname',
- 'regexpquery',
- 'section',
- 'slot',
- 'subsection',
- 'useflag',
- 'warn'
+ "command",
+ "cpv",
+ "die",
+ "emph",
+ "error",
+ "globaloption",
+ "localoption",
+ "number",
+ "path",
+ "path_symlink",
+ "pkgquery",
+ "productname",
+ "regexpquery",
+ "section",
+ "slot",
+ "subsection",
+ "useflag",
+ "warn",
)
# =======
@@ -42,146 +42,169 @@ from portage import archlist
# Functions
# =========
+
def command(string):
- """Returns a program command string."""
- return output.green(string)
+ """Returns a program command string."""
+ return output.green(string)
+
def cpv(string):
- """Returns a category/package-<version> string."""
- return output.green(string)
+ """Returns a category/package-<version> string."""
+ return output.green(string)
+
def die(err, string):
- """Returns an error string and die with an error code."""
- sys.stderr.write(error(string))
- sys.exit(err)
+ """Returns an error string and die with an error code."""
+ sys.stderr.write(error(string))
+ sys.exit(err)
+
def emph(string):
- """Returns a string as emphasized."""
- return output.bold(string)
+ """Returns a string as emphasized."""
+ return output.bold(string)
+
def error(string):
- """Prints an error string."""
- return output.red("!!! ") + string + "\n"
+ """Prints an error string."""
+ return output.red("!!! ") + string + "\n"
+
def globaloption(string):
- """Returns a global option string, i.e. the program global options."""
- return output.yellow(string)
+ """Returns a global option string, i.e. the program global options."""
+ return output.yellow(string)
+
def localoption(string):
- """Returns a local option string, i.e. the program local options."""
- return output.green(string)
+ """Returns a local option string, i.e. the program local options."""
+ return output.green(string)
+
def number(string):
- """Returns a number string."""
- return output.turquoise(string)
+ """Returns a number string."""
+ return output.turquoise(string)
+
def path(string):
- """Returns a file or directory path string."""
- return output.bold(string)
+ """Returns a file or directory path string."""
+ return output.bold(string)
+
def path_symlink(string):
- """Returns a symlink string."""
- return output.turquoise(string)
+ """Returns a symlink string."""
+ return output.turquoise(string)
+
def pkgquery(string):
- """Returns a package query string."""
- return output.bold(string)
+ """Returns a package query string."""
+ return output.bold(string)
+
def productname(string):
- """Returns a product name string, i.e. the program name."""
- return output.turquoise(string)
+ """Returns a product name string, i.e. the program name."""
+ return output.turquoise(string)
+
def regexpquery(string):
- """Returns a regular expression string."""
- return output.bold(string)
+ """Returns a regular expression string."""
+ return output.bold(string)
+
def section(string):
- """Returns a string as a section header."""
- return output.turquoise(string)
+ """Returns a string as a section header."""
+ return output.turquoise(string)
+
def slot(string):
- """Returns a slot string"""
- return output.bold(string)
+ """Returns a slot string"""
+ return output.bold(string)
+
def subsection(string):
- """Returns a string as a subsection header."""
- return output.turquoise(string)
+ """Returns a string as a subsection header."""
+ return output.turquoise(string)
+
def useflag(string, enabled=True):
- """Returns a USE flag string."""
- return output.red(string) if enabled else output.blue(string)
+ """Returns a USE flag string."""
+ return output.red(string) if enabled else output.blue(string)
+
def keyword(string, stable=True, hard_masked=False):
- """Returns a keyword string."""
- if stable:
- return output.green(string)
- if hard_masked:
- return output.red(string)
- # keyword masked:
- return output.blue(string)
+ """Returns a keyword string."""
+ if stable:
+ return output.green(string)
+ if hard_masked:
+ return output.red(string)
+ # keyword masked:
+ return output.blue(string)
+
def masking(mask):
- """Returns a 'masked by' string."""
- if 'package.mask' in mask or 'profile' in mask:
- # use porthole wrap style to help clarify meaning
- return output.red("M["+mask[0]+"]")
- if mask is not []:
- for status in mask:
- if 'keyword' in status:
- # keyword masked | " [missing keyword] " <=looks better
- return output.blue("["+status+"]")
- if status in archlist:
- return output.green(status)
- if 'unknown' in status:
- return output.yellow(status)
- return output.red(status)
- return ''
+ """Returns a 'masked by' string."""
+ if "package.mask" in mask or "profile" in mask:
+ # use porthole wrap style to help clarify meaning
+ return output.red("M[" + mask[0] + "]")
+ if mask is not []:
+ for status in mask:
+ if "keyword" in status:
+ # keyword masked | " [missing keyword] " <=looks better
+ return output.blue("[" + status + "]")
+ if status in archlist:
+ return output.green(status)
+ if "unknown" in status:
+ return output.yellow(status)
+ return output.red(status)
+ return ""
+
def warn(string):
- """Returns a warning string."""
- return "!!! " + string + "\n"
+ """Returns a warning string."""
+ return "!!! " + string + "\n"
+
try:
- unicode
+ unicode
except NameError:
- unicode = str
+ unicode = str
+
def uprint(*args, **kw):
- """Replacement for the builtin print function.
-
- This version gracefully handles characters not representable in the
- user's current locale (through the errors='replace' handler).
-
- @see: >>> help(print)
- """
-
- sep = kw.pop('sep', ' ')
- end = kw.pop('end', '\n')
- file = kw.pop("file", sys.stdout)
- if kw:
- raise TypeError("got invalid keyword arguments: {0}".format(list(kw)))
- file = getattr(file, 'buffer', file)
-
- encoding = locale.getpreferredencoding()
- # Make sure that python knows the encoding. Bug 350156
- try:
- # We don't care about what is returned, we just want to
- # verify that we can find a codec.
- codecs.lookup(encoding)
- except LookupError:
- # Python does not know the encoding, so use utf-8.
- encoding = 'utf_8'
-
- def encoded_args():
- for arg in args:
- if isinstance(arg, bytes):
- yield arg
- else:
- yield unicode(arg).encode(encoding, 'replace')
-
- sep = sep.encode(encoding, 'replace')
- end = end.encode(encoding, 'replace')
- text = sep.join(encoded_args())
- file.write(text + end)
+ """Replacement for the builtin print function.
+
+ This version gracefully handles characters not representable in the
+ user's current locale (through the errors='replace' handler).
+
+ @see: >>> help(print)
+ """
+
+ sep = kw.pop("sep", " ")
+ end = kw.pop("end", "\n")
+ file = kw.pop("file", sys.stdout)
+ if kw:
+ raise TypeError("got invalid keyword arguments: {0}".format(list(kw)))
+ file = getattr(file, "buffer", file)
+
+ encoding = locale.getpreferredencoding()
+ # Make sure that python knows the encoding. Bug 350156
+ try:
+ # We don't care about what is returned, we just want to
+ # verify that we can find a codec.
+ codecs.lookup(encoding)
+ except LookupError:
+ # Python does not know the encoding, so use utf-8.
+ encoding = "utf_8"
+
+ def encoded_args():
+ for arg in args:
+ if isinstance(arg, bytes):
+ yield arg
+ else:
+ yield unicode(arg).encode(encoding, "replace")
+
+ sep = sep.encode(encoding, "replace")
+ end = end.encode(encoding, "replace")
+ text = sep.join(encoded_args())
+ file.write(text + end)
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/profile.py b/pym/gentoolkit/profile.py
index dcd02cc..f6943be 100644
--- a/pym/gentoolkit/profile.py
+++ b/pym/gentoolkit/profile.py
@@ -6,9 +6,7 @@
"""Routines to load profile information for ekeyword/eshowkw"""
-__all__ = (
- 'load_profile_data',
-)
+__all__ = ("load_profile_data",)
import os.path
@@ -19,93 +17,101 @@ from portage import _encodings, _unicode_encode
def warning(msg):
- """Write |msg| as a warning to stderr"""
- print('warning: %s' % msg, file=sys.stderr)
-
-
-def load_profile_data(portdir=None, repo='gentoo'):
- """Load the list of known arches from the tree
-
- Args:
- portdir: The repository to load all data from (and ignore |repo|)
- repo: Look up this repository by name to locate profile data
-
- Returns:
- A dict mapping the keyword to its preferred state:
- {'x86': ('stable', 'arch'), 'mips': ('dev', '~arch'), ...}
- """
- if portdir is None:
- portdir = portage.db[portage.root]['vartree'].settings.repositories[repo].location
-
- arch_status = {}
-
- try:
- arch_list = os.path.join(portdir, 'profiles', 'arch.list')
- with open(_unicode_encode(arch_list, encoding=_encodings['fs']),
- encoding=_encodings['content']) as f:
- for line in f:
- line = line.split('#', 1)[0].strip()
- if line:
- arch_status[line] = None
- except IOError:
- pass
-
- try:
- profile_status = {
- 'stable': 0,
- 'dev': 1,
- 'exp': 2,
- None: 3,
- }
- profiles_list = os.path.join(portdir, 'profiles', 'profiles.desc')
- with open(_unicode_encode(profiles_list, encoding=_encodings['fs']),
- encoding=_encodings['content']) as f:
- for line in f:
- line = line.split('#', 1)[0].split()
- if line:
- arch, _profile, status = line
- arch_status.setdefault(arch, status)
- curr_status = profile_status[arch_status[arch]]
- new_status = profile_status[status]
- if new_status < curr_status:
- arch_status[arch] = status
- except IOError:
- pass
-
- if arch_status:
- arch_status['all'] = None
- else:
- warning('could not read profile files: %s' % arch_list)
- warning('will not be able to verify args are correct')
-
- arches_desc = {}
- try:
- arches_list = os.path.join(portdir, 'profiles', 'arches.desc')
- with open(_unicode_encode(arches_list, encoding=_encodings['fs']),
- encoding=_encodings['content']) as f:
- for line in f:
- line = line.split('#', 1)[0].split()
- if line:
- arch, status = line
- arches_desc[arch] = status
- except IOError:
- # backwards compatibility
- arches_desc = {
- 'alpha': 'testing',
- 'ia64': 'testing',
- 'm68k': 'testing',
- 'mips': 'testing',
- 'riscv': 'testing',
- }
- for k in arch_status:
- if '-' in k:
- arches_desc[k] = 'testing'
-
- for k, v in arch_status.items():
- if arches_desc.get(k) == 'testing':
- arch_status[k] = (v, '~arch')
- else:
- # TODO: explicit distinction of transitional, bad values?
- arch_status[k] = (v, 'arch')
-
- return arch_status
+ """Write |msg| as a warning to stderr"""
+ print("warning: %s" % msg, file=sys.stderr)
+
+
+def load_profile_data(portdir=None, repo="gentoo"):
+ """Load the list of known arches from the tree
+
+ Args:
+ portdir: The repository to load all data from (and ignore |repo|)
+ repo: Look up this repository by name to locate profile data
+
+ Returns:
+ A dict mapping the keyword to its preferred state:
+ {'x86': ('stable', 'arch'), 'mips': ('dev', '~arch'), ...}
+ """
+ if portdir is None:
+ portdir = (
+ portage.db[portage.root]["vartree"].settings.repositories[repo].location
+ )
+
+ arch_status = {}
+
+ try:
+ arch_list = os.path.join(portdir, "profiles", "arch.list")
+ with open(
+ _unicode_encode(arch_list, encoding=_encodings["fs"]),
+ encoding=_encodings["content"],
+ ) as f:
+ for line in f:
+ line = line.split("#", 1)[0].strip()
+ if line:
+ arch_status[line] = None
+ except IOError:
+ pass
+
+ try:
+ profile_status = {
+ "stable": 0,
+ "dev": 1,
+ "exp": 2,
+ None: 3,
+ }
+ profiles_list = os.path.join(portdir, "profiles", "profiles.desc")
+ with open(
+ _unicode_encode(profiles_list, encoding=_encodings["fs"]),
+ encoding=_encodings["content"],
+ ) as f:
+ for line in f:
+ line = line.split("#", 1)[0].split()
+ if line:
+ arch, _profile, status = line
+ arch_status.setdefault(arch, status)
+ curr_status = profile_status[arch_status[arch]]
+ new_status = profile_status[status]
+ if new_status < curr_status:
+ arch_status[arch] = status
+ except IOError:
+ pass
+
+ if arch_status:
+ arch_status["all"] = None
+ else:
+ warning("could not read profile files: %s" % arch_list)
+ warning("will not be able to verify args are correct")
+
+ arches_desc = {}
+ try:
+ arches_list = os.path.join(portdir, "profiles", "arches.desc")
+ with open(
+ _unicode_encode(arches_list, encoding=_encodings["fs"]),
+ encoding=_encodings["content"],
+ ) as f:
+ for line in f:
+ line = line.split("#", 1)[0].split()
+ if line:
+ arch, status = line
+ arches_desc[arch] = status
+ except IOError:
+ # backwards compatibility
+ arches_desc = {
+ "alpha": "testing",
+ "ia64": "testing",
+ "m68k": "testing",
+ "mips": "testing",
+ "riscv": "testing",
+ }
+ for k in arch_status:
+ if "-" in k:
+ arches_desc[k] = "testing"
+
+ for k, v in arch_status.items():
+ if arches_desc.get(k) == "testing":
+ arch_status[k] = (v, "~arch")
+ else:
+ # TODO: explicit distinction of transitional, bad values?
+ arch_status[k] = (v, "arch")
+
+ return arch_status
diff --git a/pym/gentoolkit/query.py b/pym/gentoolkit/query.py
index c2b8d56..4304670 100644
--- a/pym/gentoolkit/query.py
+++ b/pym/gentoolkit/query.py
@@ -6,9 +6,7 @@
"""Provides common methods on a package query."""
-__all__ = (
- 'Query',
-)
+__all__ = ("Query",)
# =======
# Imports
@@ -34,357 +32,367 @@ from gentoolkit.sets import get_set_atoms, SETPREFIX
# Classes
# =======
+
class Query(CPV):
- """Provides common methods on a package query."""
-
- def __init__(self, query, is_regex=False):
- """Create query object.
-
- @type is_regex: bool
- @param is_regex: query is a regular expression
- """
-
- # We need at least one of these chars for a valid query
- needed_chars = ascii_letters + digits + '*'
- if not set(query).intersection(needed_chars):
- raise errors.GentoolkitInvalidPackage(query)
-
- # Separate repository
- repository = None
- if query.count(':') == 2:
- query, repository = query.rsplit(':', 1)
- self.query = query.rstrip(':') # Don't leave dangling colon
- self.repo_filter = repository
- self.is_regex = is_regex
- self.query_type = self._get_query_type()
-
- # Name the rest of the chunks, if possible
- if self.query_type != "set":
- try:
- atom = Atom(self.query)
- self.__dict__.update(atom.__dict__)
- except errors.GentoolkitInvalidAtom:
- CPV.__init__(self, self.query)
- self.operator = ''
- self.atom = self.cpv
-
- def __repr__(self):
- rx = ''
- if self.is_regex:
- rx = ' regex'
- repo = ''
- if self.repo_filter:
- repo = ' in %s' % self.repo_filter
- return "<%s%s %r%s>" % (self.__class__.__name__, rx, self.query, repo)
-
- def __str__(self):
- return self.query
-
- def print_summary(self):
- """Print a summary of the query."""
-
- if self.query_type == "set":
- cat_str = ""
- pkg_str = pp.emph(self.query)
- else:
- try:
- cat, pkg = self.category, self.name + self.fullversion
- except errors.GentoolkitInvalidCPV:
- cat = ''
- pkg = self.atom
- if cat and not self.is_regex:
- cat_str = "in %s " % pp.emph(cat.lstrip('><=~!'))
- else:
- cat_str = ""
-
- if self.is_regex:
- pkg_str = pp.emph(self.query)
- else:
- pkg_str = pp.emph(pkg)
-
- repo = ''
- if self.repo_filter is not None:
- repo = ' %s' % pp.section(self.repo_filter)
-
- pp.uprint(" * Searching%s for %s %s..." % (repo, pkg_str, cat_str))
-
- def smart_find(
- self,
- in_installed=True,
- in_porttree=True,
- in_overlay=True,
- include_masked=True,
- show_progress=True,
- no_matches_fatal=True,
- **kwargs
- ):
- """A high-level wrapper around gentoolkit package-finder functions.
-
- @type in_installed: bool
- @param in_installed: search for query in VARDB
- @type in_porttree: bool
- @param in_porttree: search for query in PORTDB
- @type in_overlay: bool
- @param in_overlay: search for query in overlays
- @type show_progress: bool
- @param show_progress: output search progress
- @type no_matches_fatal: bool
- @param no_matches_fatal: raise errors.GentoolkitNoMatches
- @rtype: list
- @return: Package objects matching query
- """
-
- if in_installed:
- if in_porttree or in_overlay:
- simple_package_finder = partial(
- self.find,
- include_masked=include_masked
- )
- complex_package_finder = helpers.get_cpvs
- else:
- simple_package_finder = self.find_installed
- complex_package_finder = helpers.get_installed_cpvs
- elif in_porttree or in_overlay:
- simple_package_finder = partial(
- self.find,
- include_masked=include_masked,
- in_installed=False
- )
- complex_package_finder = helpers.get_uninstalled_cpvs
- else:
- raise errors.GentoolkitFatalError(
- "Not searching in installed, Portage tree, or overlay. "
- "Nothing to do."
- )
-
- if self.query_type == "set":
- self.package_finder = simple_package_finder
- matches = self._do_set_lookup(show_progress=show_progress)
- elif self.query_type == "simple":
- self.package_finder = simple_package_finder
- matches = self._do_simple_lookup(
- in_installed=in_installed,
- show_progress=show_progress
- )
- else:
- self.package_finder = complex_package_finder
- matches = self._do_complex_lookup(show_progress=show_progress)
-
- if self.repo_filter is not None:
- matches = self._filter_by_repository(matches)
-
- if no_matches_fatal and not matches:
- ii = in_installed and not (in_porttree or in_overlay)
- raise errors.GentoolkitNoMatches(self.query, in_installed=ii)
- return matches
-
- def find(self, in_installed=True, include_masked=True):
- """Returns a list of Package objects that matched the query.
-
- @rtype: list
- @return: matching Package objects
- """
-
- if not self.query:
- return []
-
- try:
- if include_masked:
- matches = portage.db[portage.root]["porttree"].dbapi.xmatch("match-all", self.query)
- else:
- matches = portage.db[portage.root]["porttree"].dbapi.match(self.query)
- if in_installed:
- matches.extend(portage.db[portage.root]["vartree"].dbapi.match(self.query))
- except portage.exception.InvalidAtom as err:
- message = "query.py: find(), query=%s, InvalidAtom=%s" %(
- self.query, str(err))
- raise errors.GentoolkitInvalidAtom(message)
-
- return [Package(x) for x in set(matches)]
-
- def find_installed(self):
- """Return a list of Package objects that matched the search key."""
-
- try:
- matches = portage.db[portage.root]["vartree"].dbapi.match(self.query)
- # catch the ambiguous package Exception
- except portage.exception.AmbiguousPackageName as err:
- matches = []
- for pkgkey in err.args[0]:
- matches.extend(portage.db[portage.root]["vartree"].dbapi.match(pkgkey))
- except portage.exception.InvalidAtom as err:
- raise errors.GentoolkitInvalidAtom(err)
-
- return [Package(x) for x in set(matches)]
-
- def find_best(self, include_keyworded=True, include_masked=True):
- """Returns the "best" version available.
-
- Order of preference:
- highest available stable =>
- highest available keyworded =>
- highest available masked
-
- @rtype: Package object or None
- @return: best of up to three options
- @raise errors.GentoolkitInvalidAtom: if query is not valid input
- """
-
- best = keyworded = masked = None
- try:
- best = portage.db[portage.root]["porttree"].dbapi.xmatch("bestmatch-visible", self.query)
- except portage.exception.InvalidAtom as err:
- message = "query.py: find_best(), bestmatch-visible, " + \
- "query=%s, InvalidAtom=%s" %(self.query, str(err))
- raise errors.GentoolkitInvalidAtom(message)
- # xmatch can return an empty string, so checking for None is not enough
- if not best:
- if not (include_keyworded or include_masked):
- return None
- try:
- matches = portage.db[portage.root]["porttree"].dbapi.xmatch("match-all", self.query)
- except portage.exception.InvalidAtom as err:
- message = "query.py: find_best(), match-all, query=%s, InvalidAtom=%s" %(
- self.query, str(err))
- raise errors.GentoolkitInvalidAtom(message)
- masked = portage.best(matches)
- keywordable = []
- for m in matches:
- status = portage.getmaskingstatus(m)
- if 'package.mask' not in status or 'profile' not in status:
- keywordable.append(m)
- if matches:
- keyworded = portage.best(keywordable)
- else:
- return Package(best)
- if include_keyworded and keyworded:
- return Package(keyworded)
- if include_masked and masked:
- return Package(masked)
- return None
-
- def uses_globbing(self):
- """Check the query to see if it is using globbing.
-
- @rtype: bool
- @return: True if query uses globbing, else False
- """
-
- if set('!*?[]').intersection(self.query):
- # Is query an atom such as '=sys-apps/portage-2.2*'?
- if self.query[0] != '=':
- return True
-
- return False
-
- def is_ranged(self):
- """Return True if the query appears to be ranged, else False."""
-
- q = self.query
- return q.startswith(('~', '<', '>')) or q.endswith('*')
-
- def _do_simple_lookup(self, in_installed=True, show_progress=True):
- """Find matches for a query which is an atom or cpv."""
-
- result = []
-
- if show_progress and CONFIG['verbose']:
- self.print_summary()
-
- result = self.package_finder()
- if not in_installed:
- result = [x for x in result if not x.is_installed()]
-
- return result
-
- def _do_complex_lookup(self, show_progress=True):
- """Find matches for a query which is a regex or includes globbing."""
-
- result = []
-
- if show_progress and not CONFIG["piping"]:
- self.print_summary()
-
- try:
- cat = CPV(self.query).category
- except errors.GentoolkitInvalidCPV:
- cat = ''
-
- pre_filter = []
- # The "get_" functions can pre-filter against the whole package key,
- # but since we allow globbing now, we run into issues like:
- # >>> portage.dep.dep_getkey("sys-apps/portage-*")
- # 'sys-apps/portage-'
- # So the only way to guarantee we don't overrun the key is to
- # prefilter by cat only.
- if cat:
- if self.is_regex:
- cat_re = cat
- else:
- cat_re = fnmatch.translate(cat)
- predicate = lambda x: re.match(cat_re, x.split("/", 1)[0])
- pre_filter = self.package_finder(predicate=predicate)
-
- # Post-filter
- if self.is_regex:
- try:
- re.compile(self.query)
- except re.error:
- raise errors.GentoolkitInvalidRegex(self.query)
- predicate = lambda x: re.search(self.query, x)
- else:
- if cat:
- query_re = fnmatch.translate(self.query)
- else:
- query_re = fnmatch.translate("*/%s" % self.query)
- predicate = lambda x: re.search(query_re, x)
- if pre_filter:
- result = [x for x in pre_filter if predicate(x)]
- else:
- result = self.package_finder(predicate=predicate)
-
- return [Package(x) for x in result]
-
- def _do_set_lookup(self, show_progress=True):
- """Find matches for a query that is a package set."""
-
- if show_progress and not CONFIG["piping"]:
- self.print_summary()
-
- setname = self.query[len(SETPREFIX):]
- result = []
- try:
- atoms = get_set_atoms(setname)
- except errors.GentoolkitSetNotFound:
- return result
-
- q = self.query
- for atom in atoms:
- self.query = str(atom)
- result.extend(self._do_simple_lookup(show_progress=False))
- self.query = q
-
- return result
-
- def _filter_by_repository(self, matches):
- """Filter out packages which do not belong to self.repo_filter."""
-
- result = []
- for match in matches:
- repo_name = match.repo_name()
- if repo_name == self.repo_filter:
- result.append(match)
- elif (not repo_name and
- self.repo_filter in ('unknown', 'null')):
- result.append(match)
-
- return result
-
- def _get_query_type(self):
- """Determine of what type the query is."""
-
- if self.query.startswith(SETPREFIX):
- return "set"
- elif self.is_regex or self.uses_globbing():
- return "complex"
- return "simple"
+ """Provides common methods on a package query."""
+
+ def __init__(self, query, is_regex=False):
+ """Create query object.
+
+ @type is_regex: bool
+ @param is_regex: query is a regular expression
+ """
+
+ # We need at least one of these chars for a valid query
+ needed_chars = ascii_letters + digits + "*"
+ if not set(query).intersection(needed_chars):
+ raise errors.GentoolkitInvalidPackage(query)
+
+ # Separate repository
+ repository = None
+ if query.count(":") == 2:
+ query, repository = query.rsplit(":", 1)
+ self.query = query.rstrip(":") # Don't leave dangling colon
+ self.repo_filter = repository
+ self.is_regex = is_regex
+ self.query_type = self._get_query_type()
+
+ # Name the rest of the chunks, if possible
+ if self.query_type != "set":
+ try:
+ atom = Atom(self.query)
+ self.__dict__.update(atom.__dict__)
+ except errors.GentoolkitInvalidAtom:
+ CPV.__init__(self, self.query)
+ self.operator = ""
+ self.atom = self.cpv
+
+ def __repr__(self):
+ rx = ""
+ if self.is_regex:
+ rx = " regex"
+ repo = ""
+ if self.repo_filter:
+ repo = " in %s" % self.repo_filter
+ return "<%s%s %r%s>" % (self.__class__.__name__, rx, self.query, repo)
+
+ def __str__(self):
+ return self.query
+
+ def print_summary(self):
+ """Print a summary of the query."""
+
+ if self.query_type == "set":
+ cat_str = ""
+ pkg_str = pp.emph(self.query)
+ else:
+ try:
+ cat, pkg = self.category, self.name + self.fullversion
+ except errors.GentoolkitInvalidCPV:
+ cat = ""
+ pkg = self.atom
+ if cat and not self.is_regex:
+ cat_str = "in %s " % pp.emph(cat.lstrip("><=~!"))
+ else:
+ cat_str = ""
+
+ if self.is_regex:
+ pkg_str = pp.emph(self.query)
+ else:
+ pkg_str = pp.emph(pkg)
+
+ repo = ""
+ if self.repo_filter is not None:
+ repo = " %s" % pp.section(self.repo_filter)
+
+ pp.uprint(" * Searching%s for %s %s..." % (repo, pkg_str, cat_str))
+
+ def smart_find(
+ self,
+ in_installed=True,
+ in_porttree=True,
+ in_overlay=True,
+ include_masked=True,
+ show_progress=True,
+ no_matches_fatal=True,
+ **kwargs
+ ):
+ """A high-level wrapper around gentoolkit package-finder functions.
+
+ @type in_installed: bool
+ @param in_installed: search for query in VARDB
+ @type in_porttree: bool
+ @param in_porttree: search for query in PORTDB
+ @type in_overlay: bool
+ @param in_overlay: search for query in overlays
+ @type show_progress: bool
+ @param show_progress: output search progress
+ @type no_matches_fatal: bool
+ @param no_matches_fatal: raise errors.GentoolkitNoMatches
+ @rtype: list
+ @return: Package objects matching query
+ """
+
+ if in_installed:
+ if in_porttree or in_overlay:
+ simple_package_finder = partial(
+ self.find, include_masked=include_masked
+ )
+ complex_package_finder = helpers.get_cpvs
+ else:
+ simple_package_finder = self.find_installed
+ complex_package_finder = helpers.get_installed_cpvs
+ elif in_porttree or in_overlay:
+ simple_package_finder = partial(
+ self.find, include_masked=include_masked, in_installed=False
+ )
+ complex_package_finder = helpers.get_uninstalled_cpvs
+ else:
+ raise errors.GentoolkitFatalError(
+ "Not searching in installed, Portage tree, or overlay. "
+ "Nothing to do."
+ )
+
+ if self.query_type == "set":
+ self.package_finder = simple_package_finder
+ matches = self._do_set_lookup(show_progress=show_progress)
+ elif self.query_type == "simple":
+ self.package_finder = simple_package_finder
+ matches = self._do_simple_lookup(
+ in_installed=in_installed, show_progress=show_progress
+ )
+ else:
+ self.package_finder = complex_package_finder
+ matches = self._do_complex_lookup(show_progress=show_progress)
+
+ if self.repo_filter is not None:
+ matches = self._filter_by_repository(matches)
+
+ if no_matches_fatal and not matches:
+ ii = in_installed and not (in_porttree or in_overlay)
+ raise errors.GentoolkitNoMatches(self.query, in_installed=ii)
+ return matches
+
+ def find(self, in_installed=True, include_masked=True):
+ """Returns a list of Package objects that matched the query.
+
+ @rtype: list
+ @return: matching Package objects
+ """
+
+ if not self.query:
+ return []
+
+ try:
+ if include_masked:
+ matches = portage.db[portage.root]["porttree"].dbapi.xmatch(
+ "match-all", self.query
+ )
+ else:
+ matches = portage.db[portage.root]["porttree"].dbapi.match(self.query)
+ if in_installed:
+ matches.extend(
+ portage.db[portage.root]["vartree"].dbapi.match(self.query)
+ )
+ except portage.exception.InvalidAtom as err:
+ message = "query.py: find(), query=%s, InvalidAtom=%s" % (
+ self.query,
+ str(err),
+ )
+ raise errors.GentoolkitInvalidAtom(message)
+
+ return [Package(x) for x in set(matches)]
+
+ def find_installed(self):
+ """Return a list of Package objects that matched the search key."""
+
+ try:
+ matches = portage.db[portage.root]["vartree"].dbapi.match(self.query)
+ # catch the ambiguous package Exception
+ except portage.exception.AmbiguousPackageName as err:
+ matches = []
+ for pkgkey in err.args[0]:
+ matches.extend(portage.db[portage.root]["vartree"].dbapi.match(pkgkey))
+ except portage.exception.InvalidAtom as err:
+ raise errors.GentoolkitInvalidAtom(err)
+
+ return [Package(x) for x in set(matches)]
+
+ def find_best(self, include_keyworded=True, include_masked=True):
+ """Returns the "best" version available.
+
+ Order of preference:
+ highest available stable =>
+ highest available keyworded =>
+ highest available masked
+
+ @rtype: Package object or None
+ @return: best of up to three options
+ @raise errors.GentoolkitInvalidAtom: if query is not valid input
+ """
+
+ best = keyworded = masked = None
+ try:
+ best = portage.db[portage.root]["porttree"].dbapi.xmatch(
+ "bestmatch-visible", self.query
+ )
+ except portage.exception.InvalidAtom as err:
+ message = (
+ "query.py: find_best(), bestmatch-visible, "
+ + "query=%s, InvalidAtom=%s" % (self.query, str(err))
+ )
+ raise errors.GentoolkitInvalidAtom(message)
+ # xmatch can return an empty string, so checking for None is not enough
+ if not best:
+ if not (include_keyworded or include_masked):
+ return None
+ try:
+ matches = portage.db[portage.root]["porttree"].dbapi.xmatch(
+ "match-all", self.query
+ )
+ except portage.exception.InvalidAtom as err:
+ message = (
+ "query.py: find_best(), match-all, query=%s, InvalidAtom=%s"
+ % (self.query, str(err))
+ )
+ raise errors.GentoolkitInvalidAtom(message)
+ masked = portage.best(matches)
+ keywordable = []
+ for m in matches:
+ status = portage.getmaskingstatus(m)
+ if "package.mask" not in status or "profile" not in status:
+ keywordable.append(m)
+ if matches:
+ keyworded = portage.best(keywordable)
+ else:
+ return Package(best)
+ if include_keyworded and keyworded:
+ return Package(keyworded)
+ if include_masked and masked:
+ return Package(masked)
+ return None
+
+ def uses_globbing(self):
+ """Check the query to see if it is using globbing.
+
+ @rtype: bool
+ @return: True if query uses globbing, else False
+ """
+
+ if set("!*?[]").intersection(self.query):
+ # Is query an atom such as '=sys-apps/portage-2.2*'?
+ if self.query[0] != "=":
+ return True
+
+ return False
+
+ def is_ranged(self):
+ """Return True if the query appears to be ranged, else False."""
+
+ q = self.query
+ return q.startswith(("~", "<", ">")) or q.endswith("*")
+
+ def _do_simple_lookup(self, in_installed=True, show_progress=True):
+ """Find matches for a query which is an atom or cpv."""
+
+ result = []
+
+ if show_progress and CONFIG["verbose"]:
+ self.print_summary()
+
+ result = self.package_finder()
+ if not in_installed:
+ result = [x for x in result if not x.is_installed()]
+
+ return result
+
+ def _do_complex_lookup(self, show_progress=True):
+ """Find matches for a query which is a regex or includes globbing."""
+
+ result = []
+
+ if show_progress and not CONFIG["piping"]:
+ self.print_summary()
+
+ try:
+ cat = CPV(self.query).category
+ except errors.GentoolkitInvalidCPV:
+ cat = ""
+
+ pre_filter = []
+ # The "get_" functions can pre-filter against the whole package key,
+ # but since we allow globbing now, we run into issues like:
+ # >>> portage.dep.dep_getkey("sys-apps/portage-*")
+ # 'sys-apps/portage-'
+ # So the only way to guarantee we don't overrun the key is to
+ # prefilter by cat only.
+ if cat:
+ if self.is_regex:
+ cat_re = cat
+ else:
+ cat_re = fnmatch.translate(cat)
+ predicate = lambda x: re.match(cat_re, x.split("/", 1)[0])
+ pre_filter = self.package_finder(predicate=predicate)
+
+ # Post-filter
+ if self.is_regex:
+ try:
+ re.compile(self.query)
+ except re.error:
+ raise errors.GentoolkitInvalidRegex(self.query)
+ predicate = lambda x: re.search(self.query, x)
+ else:
+ if cat:
+ query_re = fnmatch.translate(self.query)
+ else:
+ query_re = fnmatch.translate("*/%s" % self.query)
+ predicate = lambda x: re.search(query_re, x)
+ if pre_filter:
+ result = [x for x in pre_filter if predicate(x)]
+ else:
+ result = self.package_finder(predicate=predicate)
+
+ return [Package(x) for x in result]
+
+ def _do_set_lookup(self, show_progress=True):
+ """Find matches for a query that is a package set."""
+
+ if show_progress and not CONFIG["piping"]:
+ self.print_summary()
+
+ setname = self.query[len(SETPREFIX) :]
+ result = []
+ try:
+ atoms = get_set_atoms(setname)
+ except errors.GentoolkitSetNotFound:
+ return result
+
+ q = self.query
+ for atom in atoms:
+ self.query = str(atom)
+ result.extend(self._do_simple_lookup(show_progress=False))
+ self.query = q
+
+ return result
+
+ def _filter_by_repository(self, matches):
+ """Filter out packages which do not belong to self.repo_filter."""
+
+ result = []
+ for match in matches:
+ repo_name = match.repo_name()
+ if repo_name == self.repo_filter:
+ result.append(match)
+ elif not repo_name and self.repo_filter in ("unknown", "null"):
+ result.append(match)
+
+ return result
+
+ def _get_query_type(self):
+ """Determine of what type the query is."""
+
+ if self.query.startswith(SETPREFIX):
+ return "set"
+ elif self.is_regex or self.uses_globbing():
+ return "complex"
+ return "simple"
diff --git a/pym/gentoolkit/revdep_rebuild/analyse.py b/pym/gentoolkit/revdep_rebuild/analyse.py
index bdd8306..c9c4a77 100644
--- a/pym/gentoolkit/revdep_rebuild/analyse.py
+++ b/pym/gentoolkit/revdep_rebuild/analyse.py
@@ -10,8 +10,12 @@ from portage import _encodings, _unicode_encode
from portage.output import bold, blue, yellow, green
from .stuff import scan
-from .collect import (prepare_search_dirs, parse_revdep_config,
- collect_libraries_from_dir, collect_binaries_from_dir)
+from .collect import (
+ prepare_search_dirs,
+ parse_revdep_config,
+ collect_libraries_from_dir,
+ collect_binaries_from_dir,
+)
from .assign import assign_packages
from .cache import save_cache
@@ -19,381 +23,422 @@ current_milli_time = lambda: int(round(time.time() * 1000))
def scan_files(libs_and_bins, cmd_max_args, logger, searchbits):
- '''Calls stuff.scan() and processes the data into a dictionary
- of scanned files information.
-
- @param libs_and_bins: set of libraries and binaries to scan for lib links.
- @param cmd_max_args: maximum number of files to pass into scanelf calls.
- @param logger: python style Logging function to use for output.
- @returns dict: {bit_length: {soname: {filename: set(needed)}}}
- '''
- stime = current_milli_time()
- scanned_files = {} # {bits: {soname: (filename, needed), ...}, ...}
- lines = scan(['-BF', '%F;%f;%S;%n;%M'],
- libs_and_bins, cmd_max_args, logger)
- ftime = current_milli_time()
- logger.debug("\tscan_files(); total time to get scanelf data is "
- "%d milliseconds" % (ftime-stime))
- stime = current_milli_time()
- count = 0
- for line in lines:
- parts = line.split(';')
- if len(parts) != 5:
- logger.error("\tscan_files(); error processing lib: %s" % line)
- logger.error("\tscan_files(); parts = %s" % str(parts))
- continue
- filename, sfilename, soname, needed, bits = parts
- filename = os.path.realpath(filename)
- needed = needed.split(',')
- bits = bits[8:] # 8: -> strlen('ELFCLASS')
- if bits not in searchbits:
- continue
- if not soname:
- soname = sfilename
-
- if bits not in scanned_files:
- scanned_files[bits] = {}
- if soname not in scanned_files[bits]:
- scanned_files[bits][soname] = {}
- if filename not in scanned_files[bits][soname]:
- scanned_files[bits][soname][filename] = set(needed)
- count += 1
- else:
- scanned_files[bits][soname][filename].update(needed)
- ftime = current_milli_time()
- logger.debug("\tscan_files(); total filenames found: %d in %d milliseconds"
- % (count, ftime-stime))
- return scanned_files
+ """Calls stuff.scan() and processes the data into a dictionary
+ of scanned files information.
+
+ @param libs_and_bins: set of libraries and binaries to scan for lib links.
+ @param cmd_max_args: maximum number of files to pass into scanelf calls.
+ @param logger: python style Logging function to use for output.
+ @returns dict: {bit_length: {soname: {filename: set(needed)}}}
+ """
+ stime = current_milli_time()
+ scanned_files = {} # {bits: {soname: (filename, needed), ...}, ...}
+ lines = scan(["-BF", "%F;%f;%S;%n;%M"], libs_and_bins, cmd_max_args, logger)
+ ftime = current_milli_time()
+ logger.debug(
+ "\tscan_files(); total time to get scanelf data is "
+ "%d milliseconds" % (ftime - stime)
+ )
+ stime = current_milli_time()
+ count = 0
+ for line in lines:
+ parts = line.split(";")
+ if len(parts) != 5:
+ logger.error("\tscan_files(); error processing lib: %s" % line)
+ logger.error("\tscan_files(); parts = %s" % str(parts))
+ continue
+ filename, sfilename, soname, needed, bits = parts
+ filename = os.path.realpath(filename)
+ needed = needed.split(",")
+ bits = bits[8:] # 8: -> strlen('ELFCLASS')
+ if bits not in searchbits:
+ continue
+ if not soname:
+ soname = sfilename
+
+ if bits not in scanned_files:
+ scanned_files[bits] = {}
+ if soname not in scanned_files[bits]:
+ scanned_files[bits][soname] = {}
+ if filename not in scanned_files[bits][soname]:
+ scanned_files[bits][soname][filename] = set(needed)
+ count += 1
+ else:
+ scanned_files[bits][soname][filename].update(needed)
+ ftime = current_milli_time()
+ logger.debug(
+ "\tscan_files(); total filenames found: %d in %d milliseconds"
+ % (count, ftime - stime)
+ )
+ return scanned_files
def extract_dependencies_from_la(la, libraries, to_check, logger):
- broken = []
-
- libnames = []
- for lib in libraries:
- match = re.match(r'.+\/(.+)\.(so|la|a)(\..+)?', lib)
- if match is not None:
- libname = match.group(1)
- if libname not in libnames:
- libnames += [libname, ]
-
- for _file in la:
- if not os.path.exists(_file):
- continue
-
- for line in open(_unicode_encode(_file, encoding=_encodings['fs']), mode='r',
- encoding=_encodings['content']).readlines():
- line = line.strip()
- if line.startswith('dependency_libs='):
- match = re.match(r"dependency_libs='([^']+)'", line)
- if match is not None:
- for el in match.group(1).split(' '):
- el = el.strip()
- if (len(el) < 1 or el.startswith('-L')
- or el.startswith('-R')
- ):
- continue
-
- if el.startswith('-l') and 'lib'+el[2:] in libnames:
- pass
- elif el in la or el in libraries:
- pass
- else:
- if to_check:
- _break = False
- for tc in to_check:
- if tc in el:
- _break = True
- break
- if not _break:
- continue
-
- logger.info('\t' + yellow(' * ') + _file +
- ' is broken (requires: ' + bold(el)+')')
- broken.append(_file)
- return broken
+ broken = []
+
+ libnames = []
+ for lib in libraries:
+ match = re.match(r".+\/(.+)\.(so|la|a)(\..+)?", lib)
+ if match is not None:
+ libname = match.group(1)
+ if libname not in libnames:
+ libnames += [
+ libname,
+ ]
+
+ for _file in la:
+ if not os.path.exists(_file):
+ continue
+
+ for line in open(
+ _unicode_encode(_file, encoding=_encodings["fs"]),
+ mode="r",
+ encoding=_encodings["content"],
+ ).readlines():
+ line = line.strip()
+ if line.startswith("dependency_libs="):
+ match = re.match(r"dependency_libs='([^']+)'", line)
+ if match is not None:
+ for el in match.group(1).split(" "):
+ el = el.strip()
+ if len(el) < 1 or el.startswith("-L") or el.startswith("-R"):
+ continue
+
+ if el.startswith("-l") and "lib" + el[2:] in libnames:
+ pass
+ elif el in la or el in libraries:
+ pass
+ else:
+ if to_check:
+ _break = False
+ for tc in to_check:
+ if tc in el:
+ _break = True
+ break
+ if not _break:
+ continue
+
+ logger.info(
+ "\t"
+ + yellow(" * ")
+ + _file
+ + " is broken (requires: "
+ + bold(el)
+ + ")"
+ )
+ broken.append(_file)
+ return broken
class LibCheck:
- def __init__(self, scanned_files, logger, searchlibs=None, searchbits=None,
- all_masks=None, masked_dirs=None):
- '''LibCheck init function.
-
- @param scanned_files: optional dictionary if the type created by
- scan_files(). Defaults to the class instance of scanned_files
- @param logger: python style Logging function to use for output.
- @param searchlibs: optional set() of libraries to search for. If defined
- it toggles several settings to configure this class for
- a target search rather than a broken libs search.
- '''
- self.scanned_files = scanned_files
- self.logger = logger
- self.searchlibs = searchlibs
- self.searchbits = sorted(searchbits) or ['32', '64']
- self.all_masks = all_masks
- self.masked_dirs = masked_dirs
- self.logger.debug("\tLibCheck.__init__(), new searchlibs: %s" %(self.searchbits))
- if searchlibs:
- self.smsg = '\tLibCheck.search(), Checking for %s bit dependants'
- self.pmsg = yellow(" * ") + 'Files that depend on: %s (%s bits)'
- self.setlibs = self._setslibs
- self.check = self._checkforlib
- else:
- self.smsg = '\tLibCheck.search(), Checking for broken %s bit libs'
- self.pmsg = green(' * ') + bold('Broken files that require:') + ' %s (%s bits)'
- self.setlibs = self._setlibs
- self.check = self._checkbroken
- self.sfmsg = "\tLibCheck.search(); Total found: %(count)d libs, %(deps)d files in %(time)d milliseconds"
- self.alllibs = None
-
-
- def _setslibs(self, l, b):
- '''Internal function. Use the class's setlibs variable'''
- sonames = []
- for s in self.searchlibs:
- if s in self.scanned_files[b].keys():
- sonames.append(s)
- continue
-
- found_partial = [a for a in self.scanned_files[b].keys() if s in a]
- if found_partial:
- sonames += found_partial
- continue
-
- for k, v in self.scanned_files[b].items():
- for vv in v.keys():
- if s in vv:
- sonames.append(k)
- break
-
- self.alllibs = '|'.join(sonames) + '|'
- self.logger.debug("\tLibCheck._setslibs(), new alllibs: %s" %(self.alllibs))
-
-
- def _setlibs(self, l, b):
- '''Internal function. Use the class's setlibs variable'''
- self.alllibs = '|'.join(l) + '|'
-
-
- def _checkforlib(self, l):
- '''Internal function. Use the class's check variable'''
- if l:
- return l+'|' in self.alllibs
- return False
-
-
- def _checkbroken(self, l):
- '''Internal function. Use the class's check variable'''
- if l:
- return l+'|' not in self.alllibs
- return False
-
-
- def search(self, scanned_files=None):
- '''Searches the scanned files for broken lib links
- or for libs to search for
-
- @param scanned_files: optional dictionary of the type created by
- scan_files(). Defaults to the class instance of scanned_files
- @ returns: dict: {bit_length: {found_lib: set(file_paths)}}.
- '''
- stime = current_milli_time()
- count = 0
- fcount = 0
- if not scanned_files:
- scanned_files = self.scanned_files
- found_libs = {}
- for bits in self.searchbits:
- try:
- scanned = scanned_files[bits]
- except KeyError:
- self.logger.debug('There are no %s-bit libraries'%bits)
- continue
- self.logger.debug(self.smsg % bits)
- self.setlibs(sorted(scanned), bits)
- for soname, filepaths in scanned.items():
- for filename, needed in filepaths.items():
- for l in needed:
- if self.check(l):
- if l in self.all_masks:
- self.logger.debug('\tLibrary %s ignored as it is masked' % l)
- continue
- if (filename in self.all_masks or
- os.path.realpath(filename) in self.all_masks or
- self.is_masked(os.path.realpath(filename))
- ):
- self.logger.debug('\tFile %s ignored as it is masked' % filename)
- continue
- if not bits in found_libs:
- found_libs[bits] = {}
- try:
- found_libs[bits][l].add(filename)
- except KeyError:
- found_libs[bits][l] = set([filename])
- count += 1
- fcount += 1
- self.logger.debug("\tLibCheck.search(); FOUND:"
- " %sbit, %s, %s" % (bits, l, filename))
- ftime = current_milli_time()
- self.logger.debug(self.sfmsg % {'count': count, 'deps': fcount,
- 'time': ftime-stime})
- return found_libs
-
-
- def is_masked(self, filename):
- for m in self.masked_dirs:
- t = os.path.realpath(m).split(os.sep)
- f = filename.split(os.sep)
- # self.logger.debug("\tis_masked(); %s, %s" % (t, f))
- if t == f[:min(len(t), len(f))]:
- return True
- return False
-
-
- def process_results(self, found_libs, scanned_files=None):
- '''Processes the search results, logs the files found
-
- @param found_libs: dictionary of the type returned by search()
- @param scanned_files: optional dictionary if the type created by
- scan_files(). Defaults to the class instance of scanned_files
- @ returns: list: of filepaths from teh search results.
- '''
- stime = current_milli_time()
- if not scanned_files:
- scanned_files = self.scanned_files
- found_pathes = []
- for bits, found in found_libs.items():
- for lib, files in found.items():
- self.logger.info(self.pmsg % (bold(lib), bits))
- for fp in sorted(files):
- self.logger.info('\t' +yellow('* ') + fp)
- found_pathes.append(fp)
- ftime = current_milli_time()
- self.logger.debug("\tLibCheck.process_results(); total filepaths found: "
- "%d in %d milliseconds" % (len(found_pathes), ftime-stime))
- return found_pathes
-
-
-def analyse(settings, logger, libraries=None, la_libraries=None,
- libraries_links=None, binaries=None, _libs_to_check=None):
- """Main program body. It will collect all info and determine the
- pkgs needing rebuilding.
-
- @param logger: logger used for logging messages, instance of logging.Logger
- class. Can be logging (RootLogger).
- @param _libs_to_check Libraries that need to be checked only
- @rtype list: list of pkgs that need rebuilding
- """
-
- searchbits = set()
- '''if _libs_to_check:
+ def __init__(
+ self,
+ scanned_files,
+ logger,
+ searchlibs=None,
+ searchbits=None,
+ all_masks=None,
+ masked_dirs=None,
+ ):
+ """LibCheck init function.
+
+ @param scanned_files: optional dictionary if the type created by
+ scan_files(). Defaults to the class instance of scanned_files
+ @param logger: python style Logging function to use for output.
+ @param searchlibs: optional set() of libraries to search for. If defined
+ it toggles several settings to configure this class for
+ a target search rather than a broken libs search.
+ """
+ self.scanned_files = scanned_files
+ self.logger = logger
+ self.searchlibs = searchlibs
+ self.searchbits = sorted(searchbits) or ["32", "64"]
+ self.all_masks = all_masks
+ self.masked_dirs = masked_dirs
+ self.logger.debug(
+ "\tLibCheck.__init__(), new searchlibs: %s" % (self.searchbits)
+ )
+ if searchlibs:
+ self.smsg = "\tLibCheck.search(), Checking for %s bit dependants"
+ self.pmsg = yellow(" * ") + "Files that depend on: %s (%s bits)"
+ self.setlibs = self._setslibs
+ self.check = self._checkforlib
+ else:
+ self.smsg = "\tLibCheck.search(), Checking for broken %s bit libs"
+ self.pmsg = (
+ green(" * ") + bold("Broken files that require:") + " %s (%s bits)"
+ )
+ self.setlibs = self._setlibs
+ self.check = self._checkbroken
+ self.sfmsg = "\tLibCheck.search(); Total found: %(count)d libs, %(deps)d files in %(time)d milliseconds"
+ self.alllibs = None
+
+ def _setslibs(self, l, b):
+ """Internal function. Use the class's setlibs variable"""
+ sonames = []
+ for s in self.searchlibs:
+ if s in self.scanned_files[b].keys():
+ sonames.append(s)
+ continue
+
+ found_partial = [a for a in self.scanned_files[b].keys() if s in a]
+ if found_partial:
+ sonames += found_partial
+ continue
+
+ for k, v in self.scanned_files[b].items():
+ for vv in v.keys():
+ if s in vv:
+ sonames.append(k)
+ break
+
+ self.alllibs = "|".join(sonames) + "|"
+ self.logger.debug("\tLibCheck._setslibs(), new alllibs: %s" % (self.alllibs))
+
+ def _setlibs(self, l, b):
+ """Internal function. Use the class's setlibs variable"""
+ self.alllibs = "|".join(l) + "|"
+
+ def _checkforlib(self, l):
+ """Internal function. Use the class's check variable"""
+ if l:
+ return l + "|" in self.alllibs
+ return False
+
+ def _checkbroken(self, l):
+ """Internal function. Use the class's check variable"""
+ if l:
+ return l + "|" not in self.alllibs
+ return False
+
+ def search(self, scanned_files=None):
+ """Searches the scanned files for broken lib links
+ or for libs to search for
+
+ @param scanned_files: optional dictionary of the type created by
+ scan_files(). Defaults to the class instance of scanned_files
+ @ returns: dict: {bit_length: {found_lib: set(file_paths)}}.
+ """
+ stime = current_milli_time()
+ count = 0
+ fcount = 0
+ if not scanned_files:
+ scanned_files = self.scanned_files
+ found_libs = {}
+ for bits in self.searchbits:
+ try:
+ scanned = scanned_files[bits]
+ except KeyError:
+ self.logger.debug("There are no %s-bit libraries" % bits)
+ continue
+ self.logger.debug(self.smsg % bits)
+ self.setlibs(sorted(scanned), bits)
+ for soname, filepaths in scanned.items():
+ for filename, needed in filepaths.items():
+ for l in needed:
+ if self.check(l):
+ if l in self.all_masks:
+ self.logger.debug(
+ "\tLibrary %s ignored as it is masked" % l
+ )
+ continue
+ if (
+ filename in self.all_masks
+ or os.path.realpath(filename) in self.all_masks
+ or self.is_masked(os.path.realpath(filename))
+ ):
+ self.logger.debug(
+ "\tFile %s ignored as it is masked" % filename
+ )
+ continue
+ if not bits in found_libs:
+ found_libs[bits] = {}
+ try:
+ found_libs[bits][l].add(filename)
+ except KeyError:
+ found_libs[bits][l] = set([filename])
+ count += 1
+ fcount += 1
+ self.logger.debug(
+ "\tLibCheck.search(); FOUND:"
+ " %sbit, %s, %s" % (bits, l, filename)
+ )
+ ftime = current_milli_time()
+ self.logger.debug(
+ self.sfmsg % {"count": count, "deps": fcount, "time": ftime - stime}
+ )
+ return found_libs
+
+ def is_masked(self, filename):
+ for m in self.masked_dirs:
+ t = os.path.realpath(m).split(os.sep)
+ f = filename.split(os.sep)
+ # self.logger.debug("\tis_masked(); %s, %s" % (t, f))
+ if t == f[: min(len(t), len(f))]:
+ return True
+ return False
+
+ def process_results(self, found_libs, scanned_files=None):
+ """Processes the search results, logs the files found
+
+ @param found_libs: dictionary of the type returned by search()
+ @param scanned_files: optional dictionary if the type created by
+ scan_files(). Defaults to the class instance of scanned_files
+ @ returns: list: of filepaths from teh search results.
+ """
+ stime = current_milli_time()
+ if not scanned_files:
+ scanned_files = self.scanned_files
+ found_pathes = []
+ for bits, found in found_libs.items():
+ for lib, files in found.items():
+ self.logger.info(self.pmsg % (bold(lib), bits))
+ for fp in sorted(files):
+ self.logger.info("\t" + yellow("* ") + fp)
+ found_pathes.append(fp)
+ ftime = current_milli_time()
+ self.logger.debug(
+ "\tLibCheck.process_results(); total filepaths found: "
+ "%d in %d milliseconds" % (len(found_pathes), ftime - stime)
+ )
+ return found_pathes
+
+
+def analyse(
+ settings,
+ logger,
+ libraries=None,
+ la_libraries=None,
+ libraries_links=None,
+ binaries=None,
+ _libs_to_check=None,
+):
+ """Main program body. It will collect all info and determine the
+ pkgs needing rebuilding.
+
+ @param logger: logger used for logging messages, instance of logging.Logger
+ class. Can be logging (RootLogger).
+ @param _libs_to_check Libraries that need to be checked only
+ @rtype list: list of pkgs that need rebuilding
+ """
+
+ searchbits = set()
+ """if _libs_to_check:
for lib in _libs_to_check:
if "lib64" in lib:
searchbits.add('64')
elif "lib32" in lib:
searchbits.add('32')
else:
- _libs_to_check = set()'''
- searchbits.update(['64', '32'])
-
- masked_dirs, masked_files, ld = parse_revdep_config(settings['REVDEP_CONFDIR'])
- masked_dirs.update([
- '/lib/modules',
- '/lib32/modules',
- '/lib64/modules',
- ]
- )
-
- if '64' not in searchbits:
- masked_dirs.update(['/lib64', '/usr/lib64'])
- elif '32' not in searchbits:
- masked_dirs.update(['/lib32', '/usr/lib32'])
-
- all_masks = masked_dirs.copy()
- all_masks.update(masked_files)
- logger.debug("\tall_masks:")
- for x in sorted(all_masks):
- logger.debug('\t\t%s' % (x))
-
- if libraries and la_libraries and libraries_links and binaries:
- logger.info(blue(' * ') +
- bold('Found a valid cache, skipping collecting phase'))
- else:
- #TODO: add partial cache (for ex. only libraries)
- # when found for some reason
-
- stime = current_milli_time()
- logger.warning(green(' * ') +
- bold('Collecting system binaries and libraries'))
- bin_dirs, lib_dirs = prepare_search_dirs(logger, settings)
-
- lib_dirs.update(ld)
- bin_dirs.update(ld)
-
- logger.debug('\tanalyse(), bin directories:')
- for x in sorted(bin_dirs):
- logger.debug('\t\t%s' % (x))
- logger.debug('\tanalyse(), lib directories:')
- for x in sorted(lib_dirs):
- logger.debug('\t\t%s' % (x))
- logger.debug('\tanalyse(), masked directories:')
- for x in sorted(masked_dirs):
- logger.debug('\t\t%s' % (x))
- logger.debug('\tanalyse(), masked files:')
- for x in sorted(masked_files):
- logger.debug('\t\t%s' % (x))
-
- ftime = current_milli_time()
- logger.debug('\ttime to complete task: %d milliseconds' % (ftime-stime))
- stime = current_milli_time()
- logger.info(green(' * ') +
- bold('Collecting dynamic linking informations'))
-
- libraries, la_libraries, libraries_links = \
- collect_libraries_from_dir(lib_dirs, all_masks, logger)
- binaries = collect_binaries_from_dir(bin_dirs, all_masks, logger)
- ftime = current_milli_time()
- logger.debug('\ttime to complete task: %d milliseconds' % (ftime-stime))
-
- if settings['USE_TMP_FILES']:
- save_cache(logger=logger,
- to_save={'libraries':libraries, 'la_libraries':la_libraries,
- 'libraries_links':libraries_links, 'binaries':binaries
- },
- temp_path=settings['DEFAULT_TMP_DIR']
- )
-
-
- logger.debug('\tanalyse(), Found %i libraries (+%i symlinks) and %i binaries' %
- (len(libraries), len(libraries_links), len(binaries))
- )
- logger.info(green(' * ') + bold('Scanning files'))
-
- libs_and_bins = libraries.union(binaries)
-
- scanned_files = scan_files(libs_and_bins, settings['CMD_MAX_ARGS'],
- logger, searchbits)
-
- logger.warning(green(' * ') + bold('Checking dynamic linking consistency'))
- logger.debug(
- '\tanalyse(), Searching for %i libs, bins within %i libraries and links'
- % (len(libs_and_bins), len(libraries)+len(libraries_links))
- )
-
- libcheck = LibCheck(scanned_files, logger, _libs_to_check, searchbits,
- all_masks, masked_dirs)
-
- broken_pathes = libcheck.process_results(libcheck.search())
-
- broken_la = extract_dependencies_from_la(la_libraries,
- libraries.union(libraries_links), _libs_to_check, logger)
- broken_pathes += broken_la
-
- if broken_pathes:
- logger.warning(green(' * ') + bold('Assign files to packages'))
- return assign_packages(broken_pathes, logger, settings)
- return None, None # no need to assign anything
-
-
-if __name__ == '__main__':
- print("This script shouldn't be called directly")
+ _libs_to_check = set()"""
+ searchbits.update(["64", "32"])
+
+ masked_dirs, masked_files, ld = parse_revdep_config(settings["REVDEP_CONFDIR"])
+ masked_dirs.update(
+ [
+ "/lib/modules",
+ "/lib32/modules",
+ "/lib64/modules",
+ ]
+ )
+
+ if "64" not in searchbits:
+ masked_dirs.update(["/lib64", "/usr/lib64"])
+ elif "32" not in searchbits:
+ masked_dirs.update(["/lib32", "/usr/lib32"])
+
+ all_masks = masked_dirs.copy()
+ all_masks.update(masked_files)
+ logger.debug("\tall_masks:")
+ for x in sorted(all_masks):
+ logger.debug("\t\t%s" % (x))
+
+ if libraries and la_libraries and libraries_links and binaries:
+ logger.info(
+ blue(" * ") + bold("Found a valid cache, skipping collecting phase")
+ )
+ else:
+ # TODO: add partial cache (for ex. only libraries)
+ # when found for some reason
+
+ stime = current_milli_time()
+ logger.warning(green(" * ") + bold("Collecting system binaries and libraries"))
+ bin_dirs, lib_dirs = prepare_search_dirs(logger, settings)
+
+ lib_dirs.update(ld)
+ bin_dirs.update(ld)
+
+ logger.debug("\tanalyse(), bin directories:")
+ for x in sorted(bin_dirs):
+ logger.debug("\t\t%s" % (x))
+ logger.debug("\tanalyse(), lib directories:")
+ for x in sorted(lib_dirs):
+ logger.debug("\t\t%s" % (x))
+ logger.debug("\tanalyse(), masked directories:")
+ for x in sorted(masked_dirs):
+ logger.debug("\t\t%s" % (x))
+ logger.debug("\tanalyse(), masked files:")
+ for x in sorted(masked_files):
+ logger.debug("\t\t%s" % (x))
+
+ ftime = current_milli_time()
+ logger.debug("\ttime to complete task: %d milliseconds" % (ftime - stime))
+ stime = current_milli_time()
+ logger.info(green(" * ") + bold("Collecting dynamic linking informations"))
+
+ libraries, la_libraries, libraries_links = collect_libraries_from_dir(
+ lib_dirs, all_masks, logger
+ )
+ binaries = collect_binaries_from_dir(bin_dirs, all_masks, logger)
+ ftime = current_milli_time()
+ logger.debug("\ttime to complete task: %d milliseconds" % (ftime - stime))
+
+ if settings["USE_TMP_FILES"]:
+ save_cache(
+ logger=logger,
+ to_save={
+ "libraries": libraries,
+ "la_libraries": la_libraries,
+ "libraries_links": libraries_links,
+ "binaries": binaries,
+ },
+ temp_path=settings["DEFAULT_TMP_DIR"],
+ )
+
+ logger.debug(
+ "\tanalyse(), Found %i libraries (+%i symlinks) and %i binaries"
+ % (len(libraries), len(libraries_links), len(binaries))
+ )
+ logger.info(green(" * ") + bold("Scanning files"))
+
+ libs_and_bins = libraries.union(binaries)
+
+ scanned_files = scan_files(
+ libs_and_bins, settings["CMD_MAX_ARGS"], logger, searchbits
+ )
+
+ logger.warning(green(" * ") + bold("Checking dynamic linking consistency"))
+ logger.debug(
+ "\tanalyse(), Searching for %i libs, bins within %i libraries and links"
+ % (len(libs_and_bins), len(libraries) + len(libraries_links))
+ )
+
+ libcheck = LibCheck(
+ scanned_files, logger, _libs_to_check, searchbits, all_masks, masked_dirs
+ )
+
+ broken_pathes = libcheck.process_results(libcheck.search())
+
+ broken_la = extract_dependencies_from_la(
+ la_libraries, libraries.union(libraries_links), _libs_to_check, logger
+ )
+ broken_pathes += broken_la
+
+ if broken_pathes:
+ logger.warning(green(" * ") + bold("Assign files to packages"))
+ return assign_packages(broken_pathes, logger, settings)
+ return None, None # no need to assign anything
+
+
+if __name__ == "__main__":
+ print("This script shouldn't be called directly")
diff --git a/pym/gentoolkit/revdep_rebuild/assign.py b/pym/gentoolkit/revdep_rebuild/assign.py
index 570c114..bfc56eb 100644
--- a/pym/gentoolkit/revdep_rebuild/assign.py
+++ b/pym/gentoolkit/revdep_rebuild/assign.py
@@ -9,6 +9,7 @@ import os
import io
import re
import time
+
current_milli_time = lambda: int(round(time.time() * 1000))
import portage
@@ -17,160 +18,175 @@ from portage.output import bold, red, yellow, green
class _file_matcher:
- """
- Compares files by basename and parent directory (device, inode),
- so comparisons work regardless of directory symlinks. If a
- parent directory does not exist, the realpath of the parent
- directory is used instead of the (device, inode). When multiple
- files share the same parent directory, stat is only called
- once per directory, and the result is cached internally.
- """
- def __init__(self):
- self._file_ids = {}
- self._added = {}
-
- def _file_id(self, filename):
- try:
- return self._file_ids[filename]
- except KeyError:
- try:
- st = os.stat(filename)
- except OSError as e:
- if e.errno != errno.ENOENT:
- raise
- file_id = (os.path.realpath(filename),)
- else:
- file_id = (st.st_dev, st.st_ino)
-
- self._file_ids[filename] = file_id
- return file_id
-
- def _file_key(self, filename):
- head, tail = os.path.split(filename)
- key = self._file_id(head) + (tail,)
- return key
-
- def add(self, filename):
- self._added[self._file_key(filename)] = filename
-
- def intersection(self, other):
- for file_key in self._added:
- match = other._added.get(file_key)
- if match is not None:
- yield match
+ """
+ Compares files by basename and parent directory (device, inode),
+ so comparisons work regardless of directory symlinks. If a
+ parent directory does not exist, the realpath of the parent
+ directory is used instead of the (device, inode). When multiple
+ files share the same parent directory, stat is only called
+ once per directory, and the result is cached internally.
+ """
+
+ def __init__(self):
+ self._file_ids = {}
+ self._added = {}
+
+ def _file_id(self, filename):
+ try:
+ return self._file_ids[filename]
+ except KeyError:
+ try:
+ st = os.stat(filename)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ file_id = (os.path.realpath(filename),)
+ else:
+ file_id = (st.st_dev, st.st_ino)
+
+ self._file_ids[filename] = file_id
+ return file_id
+
+ def _file_key(self, filename):
+ head, tail = os.path.split(filename)
+ key = self._file_id(head) + (tail,)
+ return key
+
+ def add(self, filename):
+ self._added[self._file_key(filename)] = filename
+
+ def intersection(self, other):
+ for file_key in self._added:
+ match = other._added.get(file_key)
+ if match is not None:
+ yield match
def assign_packages(broken, logger, settings):
- ''' Finds and returns packages that owns files placed in broken.
- Broken is list of files
- '''
- stime = current_milli_time()
-
- broken_matcher = _file_matcher()
- for filename in broken:
- broken_matcher.add(filename)
-
- assigned_pkgs = set()
- assigned_filenames = set()
- for group in os.listdir(settings['PKG_DIR']):
- grppath = settings['PKG_DIR'] + group
- if not os.path.isdir(grppath):
- continue
- for pkg in os.listdir(grppath):
- pkgpath = settings['PKG_DIR'] + group + '/' + pkg
- if not os.path.isdir(pkgpath):
- continue
- f = pkgpath + '/CONTENTS'
- if os.path.exists(f):
- contents_matcher = _file_matcher()
- try:
- with io.open(f, 'r', encoding='utf_8') as cnt:
- for line in cnt.readlines():
- m = re.match(r'^obj (/[^ ]+)', line)
- if m is not None:
- contents_matcher.add(m.group(1))
- except Exception as e:
- logger.warning(red(' !! Failed to read ' + f))
- logger.warning(red(' !! Error was:' + str(e)))
- else:
- for m in contents_matcher.intersection(broken_matcher):
- found = group+'/'+pkg
- assigned_pkgs.add(found)
- assigned_filenames.add(m)
- logger.info('\t' + green('* ') + m +
- ' -> ' + bold(found))
-
- broken_filenames = set(broken)
- orphaned = broken_filenames.difference(assigned_filenames)
- ftime = current_milli_time()
- logger.debug("\tassign_packages(); assigned "
- "%d packages, %d orphans in %d milliseconds"
- % (len(assigned_pkgs), len(orphaned), ftime-stime))
-
- return (assigned_pkgs, orphaned)
+ """Finds and returns packages that owns files placed in broken.
+ Broken is list of files
+ """
+ stime = current_milli_time()
+
+ broken_matcher = _file_matcher()
+ for filename in broken:
+ broken_matcher.add(filename)
+
+ assigned_pkgs = set()
+ assigned_filenames = set()
+ for group in os.listdir(settings["PKG_DIR"]):
+ grppath = settings["PKG_DIR"] + group
+ if not os.path.isdir(grppath):
+ continue
+ for pkg in os.listdir(grppath):
+ pkgpath = settings["PKG_DIR"] + group + "/" + pkg
+ if not os.path.isdir(pkgpath):
+ continue
+ f = pkgpath + "/CONTENTS"
+ if os.path.exists(f):
+ contents_matcher = _file_matcher()
+ try:
+ with io.open(f, "r", encoding="utf_8") as cnt:
+ for line in cnt.readlines():
+ m = re.match(r"^obj (/[^ ]+)", line)
+ if m is not None:
+ contents_matcher.add(m.group(1))
+ except Exception as e:
+ logger.warning(red(" !! Failed to read " + f))
+ logger.warning(red(" !! Error was:" + str(e)))
+ else:
+ for m in contents_matcher.intersection(broken_matcher):
+ found = group + "/" + pkg
+ assigned_pkgs.add(found)
+ assigned_filenames.add(m)
+ logger.info("\t" + green("* ") + m + " -> " + bold(found))
+
+ broken_filenames = set(broken)
+ orphaned = broken_filenames.difference(assigned_filenames)
+ ftime = current_milli_time()
+ logger.debug(
+ "\tassign_packages(); assigned "
+ "%d packages, %d orphans in %d milliseconds"
+ % (len(assigned_pkgs), len(orphaned), ftime - stime)
+ )
+
+ return (assigned_pkgs, orphaned)
def get_best_match(cpv, cp, logger):
- """Tries to find another version of the pkg with the same slot
- as the deprecated installed version. Failing that attempt to get any version
- of the same app
-
- @param cpv: string
- @param cp: string
- @rtype tuple: ([cpv,...], SLOT)
- """
-
- slot = portage.db[portage.root]["vartree"].dbapi.aux_get(cpv, ["SLOT"])[0]
- logger.warning('\t%s "%s" %s.' % (yellow('* Warning:'), cpv,bold('ebuild not found.')))
- logger.debug('\tget_best_match(); Looking for %s:%s' %(cp, slot))
- try:
- match = portdb.match('%s:%s' %(cp, slot))
- except portage.exception.InvalidAtom:
- match = None
-
- if not match:
- logger.warning('\t' + red('!!') + ' ' + yellow(
- 'Could not find ebuild for %s:%s' %(cp, slot)))
- slot = ['']
- match = portdb.match(cp)
- if not match:
- logger.warning('\t' + red('!!') + ' ' +
- yellow('Could not find ebuild for ' + cp))
- return match, slot
+ """Tries to find another version of the pkg with the same slot
+ as the deprecated installed version. Failing that attempt to get any version
+ of the same app
+
+ @param cpv: string
+ @param cp: string
+ @rtype tuple: ([cpv,...], SLOT)
+ """
+
+ slot = portage.db[portage.root]["vartree"].dbapi.aux_get(cpv, ["SLOT"])[0]
+ logger.warning(
+ '\t%s "%s" %s.' % (yellow("* Warning:"), cpv, bold("ebuild not found."))
+ )
+ logger.debug("\tget_best_match(); Looking for %s:%s" % (cp, slot))
+ try:
+ match = portdb.match("%s:%s" % (cp, slot))
+ except portage.exception.InvalidAtom:
+ match = None
+
+ if not match:
+ logger.warning(
+ "\t"
+ + red("!!")
+ + " "
+ + yellow("Could not find ebuild for %s:%s" % (cp, slot))
+ )
+ slot = [""]
+ match = portdb.match(cp)
+ if not match:
+ logger.warning(
+ "\t" + red("!!") + " " + yellow("Could not find ebuild for " + cp)
+ )
+ return match, slot
def get_slotted_cps(cpvs, logger):
- """Uses portage to reduce the cpv list into a cp:slot list and returns it
- """
- from portage.versions import catpkgsplit
- from portage import portdb
-
- cps = []
- for cpv in cpvs:
- parts = catpkgsplit(cpv)
- if not parts:
- logger.warning(('\t' + red("Failed to split the following pkg: "
- "%s, not a valid cat/pkg-ver" %cpv)))
- continue
-
- cp = parts[0] + '/' + parts[1]
- try:
- slot = portdb.aux_get(cpv, ["SLOT"])
- except KeyError:
- match, slot = get_best_match(cpv, cp, logger)
- if not match:
- logger.warning('\t' + red("Installed package: "
- "%s is no longer available" %cp))
- continue
-
- if slot[0]:
- cps.append(cp + ":" + slot[0])
- else:
- cps.append(cp)
-
- return cps
-
-
-
-if __name__ == '__main__':
- print('Nothing to call here')
+ """Uses portage to reduce the cpv list into a cp:slot list and returns it"""
+ from portage.versions import catpkgsplit
+ from portage import portdb
+
+ cps = []
+ for cpv in cpvs:
+ parts = catpkgsplit(cpv)
+ if not parts:
+ logger.warning(
+ (
+ "\t"
+ + red(
+ "Failed to split the following pkg: "
+ "%s, not a valid cat/pkg-ver" % cpv
+ )
+ )
+ )
+ continue
+
+ cp = parts[0] + "/" + parts[1]
+ try:
+ slot = portdb.aux_get(cpv, ["SLOT"])
+ except KeyError:
+ match, slot = get_best_match(cpv, cp, logger)
+ if not match:
+ logger.warning(
+ "\t" + red("Installed package: " "%s is no longer available" % cp)
+ )
+ continue
+
+ if slot[0]:
+ cps.append(cp + ":" + slot[0])
+ else:
+ cps.append(cp)
+
+ return cps
+
+
+if __name__ == "__main__":
+ print("Nothing to call here")
diff --git a/pym/gentoolkit/revdep_rebuild/cache.py b/pym/gentoolkit/revdep_rebuild/cache.py
index ab0b7d7..3815d72 100644
--- a/pym/gentoolkit/revdep_rebuild/cache.py
+++ b/pym/gentoolkit/revdep_rebuild/cache.py
@@ -1,4 +1,3 @@
-
"""Caching module
Functions for reading, saving and verifying the data caches
"""
@@ -10,125 +9,161 @@ from portage import _encodings, _unicode_encode
from portage.output import red
from .settings import DEFAULTS
-def read_cache(temp_path=DEFAULTS['DEFAULT_TMP_DIR']):
- ''' Reads cache information needed by analyse function.
- This function does not checks if files exists nor timestamps,
- check_temp_files should be called first
- @param temp_path: directory where all temp files should reside
- @return tuple with values of:
- libraries, la_libraries, libraries_links, symlink_pairs, binaries
- '''
-
- ret = {
- 'libraries': set(),
- 'la_libraries': set(),
- 'libraries_links': set(),
- 'binaries': set()
- }
- try:
- for key,val in ret.items():
- _file = open(_unicode_encode(os.path.join(temp_path, key),
- encoding=_encodings['fs']), encoding=_encodings['content'])
- for line in _file.readlines():
- val.add(line.strip())
- #libraries.remove('\n')
- _file .close()
- except EnvironmentError:
- pass
-
- return (ret['libraries'], ret['la_libraries'],
- ret['libraries_links'], ret['binaries'])
-
-
-def save_cache(logger, to_save={}, temp_path=DEFAULTS['DEFAULT_TMP_DIR']):
- ''' Tries to store caching information.
- @param logger
- @param to_save have to be dict with keys:
- libraries, la_libraries, libraries_links and binaries
- '''
-
- if not os.path.exists(temp_path):
- os.makedirs(temp_path)
-
- try:
- _file = open(_unicode_encode(os.path.join(temp_path, 'timestamp'),
- encoding=_encodings['fs']), mode='w', encoding=_encodings['content'])
- _file.write(str(int(time.time())))
- _file.close()
-
- for key,val in to_save.items():
- _file = open(_unicode_encode(os.path.join(temp_path, key),
- encoding=_encodings['fs']), mode='w',
- encoding=_encodings['content'])
- for line in val:
- _file.write(line + '\n')
- _file.close()
- except Exception as ex:
- logger.warning('\t' + red('Could not save cache: %s' %str(ex)))
-
-
-
-def check_temp_files(temp_path=DEFAULTS['DEFAULT_TMP_DIR'], max_delay=3600,
- logger=None):
- ''' Checks if temporary files from previous run are still available
- and if they aren't too old
- @param temp_path is directory, where temporary files should be found
- @param max_delay is maximum time difference (in seconds)
- when those files are still considered fresh and useful
- returns True, when files can be used, or False, when they don't
- exists or they are too old
- '''
-
- if not os.path.exists(temp_path) or not os.path.isdir(temp_path):
- return False
-
- timestamp_path = os.path.join(temp_path, 'timestamp')
- if not os.path.exists(timestamp_path) or not os.path.isfile(timestamp_path):
- return False
-
- try:
- _file = open(_unicode_encode(timestamp_path, encoding=_encodings['fs']),
- encoding=_encodings['content'])
- timestamp = int(_file.readline())
- _file .close()
- except Exception as ex:
- if logger:
- logger.debug("\tcheck_temp_files(); error retrieving"
- " timestamp_path:\n" + str(ex))
- timestamp = 0
- return False
-
- diff = int(time.time()) - timestamp
- return max_delay > diff
-
-
-
-if __name__ == '__main__':
- print('Preparing cache ... ')
-
- from .collect import (prepare_search_dirs, parse_revdep_config,
- collect_libraries_from_dir, collect_binaries_from_dir)
- import logging
-
- bin_dirs, lib_dirs = prepare_search_dirs()
-
- masked_dirs, masked_files, ld = parse_revdep_config()
- lib_dirs.update(ld)
- bin_dirs.update(ld)
- masked_dirs.update(
- set([
- '/lib/modules',
- '/lib32/modules',
- '/lib64/modules',
- ])
- )
-
- libraries, la_libraries, libraries_links, symlink_pairs = collect_libraries_from_dir(lib_dirs, masked_dirs, logging)
- binaries = collect_binaries_from_dir(bin_dirs, masked_dirs, logging)
-
- save_cache(logger=logging,
- to_save={'libraries':libraries, 'la_libraries':la_libraries,
- 'libraries_links':libraries_links, 'binaries':binaries}
- )
-
- print('Done.')
+
+def read_cache(temp_path=DEFAULTS["DEFAULT_TMP_DIR"]):
+ """Reads cache information needed by analyse function.
+ This function does not checks if files exists nor timestamps,
+ check_temp_files should be called first
+ @param temp_path: directory where all temp files should reside
+ @return tuple with values of:
+ libraries, la_libraries, libraries_links, symlink_pairs, binaries
+ """
+
+ ret = {
+ "libraries": set(),
+ "la_libraries": set(),
+ "libraries_links": set(),
+ "binaries": set(),
+ }
+ try:
+ for key, val in ret.items():
+ _file = open(
+ _unicode_encode(
+ os.path.join(temp_path, key), encoding=_encodings["fs"]
+ ),
+ encoding=_encodings["content"],
+ )
+ for line in _file.readlines():
+ val.add(line.strip())
+ # libraries.remove('\n')
+ _file.close()
+ except EnvironmentError:
+ pass
+
+ return (
+ ret["libraries"],
+ ret["la_libraries"],
+ ret["libraries_links"],
+ ret["binaries"],
+ )
+
+
+def save_cache(logger, to_save={}, temp_path=DEFAULTS["DEFAULT_TMP_DIR"]):
+ """Tries to store caching information.
+ @param logger
+ @param to_save have to be dict with keys:
+ libraries, la_libraries, libraries_links and binaries
+ """
+
+ if not os.path.exists(temp_path):
+ os.makedirs(temp_path)
+
+ try:
+ _file = open(
+ _unicode_encode(
+ os.path.join(temp_path, "timestamp"), encoding=_encodings["fs"]
+ ),
+ mode="w",
+ encoding=_encodings["content"],
+ )
+ _file.write(str(int(time.time())))
+ _file.close()
+
+ for key, val in to_save.items():
+ _file = open(
+ _unicode_encode(
+ os.path.join(temp_path, key), encoding=_encodings["fs"]
+ ),
+ mode="w",
+ encoding=_encodings["content"],
+ )
+ for line in val:
+ _file.write(line + "\n")
+ _file.close()
+ except Exception as ex:
+ logger.warning("\t" + red("Could not save cache: %s" % str(ex)))
+
+
+def check_temp_files(
+ temp_path=DEFAULTS["DEFAULT_TMP_DIR"], max_delay=3600, logger=None
+):
+ """Checks if temporary files from previous run are still available
+ and if they aren't too old
+ @param temp_path is directory, where temporary files should be found
+ @param max_delay is maximum time difference (in seconds)
+ when those files are still considered fresh and useful
+ returns True, when files can be used, or False, when they don't
+ exists or they are too old
+ """
+
+ if not os.path.exists(temp_path) or not os.path.isdir(temp_path):
+ return False
+
+ timestamp_path = os.path.join(temp_path, "timestamp")
+ if not os.path.exists(timestamp_path) or not os.path.isfile(timestamp_path):
+ return False
+
+ try:
+ _file = open(
+ _unicode_encode(timestamp_path, encoding=_encodings["fs"]),
+ encoding=_encodings["content"],
+ )
+ timestamp = int(_file.readline())
+ _file.close()
+ except Exception as ex:
+ if logger:
+ logger.debug(
+ "\tcheck_temp_files(); error retrieving" " timestamp_path:\n" + str(ex)
+ )
+ timestamp = 0
+ return False
+
+ diff = int(time.time()) - timestamp
+ return max_delay > diff
+
+
+if __name__ == "__main__":
+ print("Preparing cache ... ")
+
+ from .collect import (
+ prepare_search_dirs,
+ parse_revdep_config,
+ collect_libraries_from_dir,
+ collect_binaries_from_dir,
+ )
+ import logging
+
+ bin_dirs, lib_dirs = prepare_search_dirs()
+
+ masked_dirs, masked_files, ld = parse_revdep_config()
+ lib_dirs.update(ld)
+ bin_dirs.update(ld)
+ masked_dirs.update(
+ set(
+ [
+ "/lib/modules",
+ "/lib32/modules",
+ "/lib64/modules",
+ ]
+ )
+ )
+
+ (
+ libraries,
+ la_libraries,
+ libraries_links,
+ symlink_pairs,
+ ) = collect_libraries_from_dir(lib_dirs, masked_dirs, logging)
+ binaries = collect_binaries_from_dir(bin_dirs, masked_dirs, logging)
+
+ save_cache(
+ logger=logging,
+ to_save={
+ "libraries": libraries,
+ "la_libraries": la_libraries,
+ "libraries_links": libraries_links,
+ "binaries": binaries,
+ },
+ )
+
+ print("Done.")
diff --git a/pym/gentoolkit/revdep_rebuild/collect.py b/pym/gentoolkit/revdep_rebuild/collect.py
index 38ff48e..0e5d274 100644
--- a/pym/gentoolkit/revdep_rebuild/collect.py
+++ b/pym/gentoolkit/revdep_rebuild/collect.py
@@ -14,219 +14,242 @@ from .settings import parse_revdep_config
def parse_conf(conf_file, visited=None, logger=None):
- ''' Parses supplied conf_file for libraries pathes.
- conf_file is file or files to parse
- visited is set of files already parsed
- '''
- lib_dirs = set()
- to_parse = set()
-
- if isinstance(conf_file, str):
- conf_file = [conf_file]
-
- for conf in conf_file:
- try:
- with open(_unicode_encode(conf, encoding=_encodings['fs']),
- encoding=_encodings['content']) as _file:
- for line in _file.readlines():
- line = line.strip()
- if line.startswith('#'):
- continue
- elif line.startswith('include'):
- include_line = line.split()[1:]
- for included in include_line:
- if not included.startswith('/'):
- path = os.path.join(os.path.dirname(conf), \
- included)
- else:
- path = included
-
- to_parse.update(glob.glob(path))
- else:
- lib_dirs.add(line)
- except EnvironmentError:
- logger.warn('\t' + yellow('Error when parsing file %s' %conf))
-
- if visited is None:
- visited = set()
-
- visited.update(conf_file)
- to_parse = to_parse.difference(visited)
- if to_parse:
- lib_dirs.update(parse_conf(to_parse, visited, logger=logger))
-
- return lib_dirs
+ """Parses supplied conf_file for libraries pathes.
+ conf_file is file or files to parse
+ visited is set of files already parsed
+ """
+ lib_dirs = set()
+ to_parse = set()
+
+ if isinstance(conf_file, str):
+ conf_file = [conf_file]
+
+ for conf in conf_file:
+ try:
+ with open(
+ _unicode_encode(conf, encoding=_encodings["fs"]),
+ encoding=_encodings["content"],
+ ) as _file:
+ for line in _file.readlines():
+ line = line.strip()
+ if line.startswith("#"):
+ continue
+ elif line.startswith("include"):
+ include_line = line.split()[1:]
+ for included in include_line:
+ if not included.startswith("/"):
+ path = os.path.join(os.path.dirname(conf), included)
+ else:
+ path = included
+
+ to_parse.update(glob.glob(path))
+ else:
+ lib_dirs.add(line)
+ except EnvironmentError:
+ logger.warn("\t" + yellow("Error when parsing file %s" % conf))
+
+ if visited is None:
+ visited = set()
+
+ visited.update(conf_file)
+ to_parse = to_parse.difference(visited)
+ if to_parse:
+ lib_dirs.update(parse_conf(to_parse, visited, logger=logger))
+
+ return lib_dirs
def prepare_search_dirs(logger, settings):
- ''' Lookup for search dirs. Returns tuple with two lists,
- (list_of_bin_dirs, list_of_lib_dirs)
- '''
-
- bin_dirs = set(['/bin', '/usr/bin', ])
- lib_dirs = set(['/lib', '/usr/lib', ])
-
- #try:
- with open(_unicode_encode(os.path.join(
- portage.root, settings['DEFAULT_ENV_FILE']),
- encoding=_encodings['fs']), mode='r',
- encoding=_encodings['content']) as _file:
- for line in _file.readlines():
- line = line.strip()
- match = re.match(r"^export (ROOT)?PATH='([^']+)'", line)
- if match is not None:
- bin_dirs.update(set(match.group(2).split(':')))
- #except EnvironmentError:
- #logger.debug('\t' + yellow('Could not open file %s' % f))
-
- lib_dirs = parse_conf(settings['DEFAULT_LD_FILE'], logger=logger)
- return (bin_dirs, lib_dirs)
-
+ """Lookup for search dirs. Returns tuple with two lists,
+ (list_of_bin_dirs, list_of_lib_dirs)
+ """
+
+ bin_dirs = set(
+ [
+ "/bin",
+ "/usr/bin",
+ ]
+ )
+ lib_dirs = set(
+ [
+ "/lib",
+ "/usr/lib",
+ ]
+ )
+
+ # try:
+ with open(
+ _unicode_encode(
+ os.path.join(portage.root, settings["DEFAULT_ENV_FILE"]),
+ encoding=_encodings["fs"],
+ ),
+ mode="r",
+ encoding=_encodings["content"],
+ ) as _file:
+ for line in _file.readlines():
+ line = line.strip()
+ match = re.match(r"^export (ROOT)?PATH='([^']+)'", line)
+ if match is not None:
+ bin_dirs.update(set(match.group(2).split(":")))
+ # except EnvironmentError:
+ # logger.debug('\t' + yellow('Could not open file %s' % f))
+
+ lib_dirs = parse_conf(settings["DEFAULT_LD_FILE"], logger=logger)
+ return (bin_dirs, lib_dirs)
def collect_libraries_from_dir(dirs, mask, logger):
- ''' Collects all libraries from specified list of directories.
- mask is list of pathes, that are ommited in scanning, can be eighter single file or entire directory
- Returns tuple composed of: list of libraries, list of symlinks, and toupe with pair
- (symlink_id, library_id) for resolving dependencies
- '''
-
- # contains list of directories found
- # allows us to reduce number of fnc calls
- found_directories = set()
- found_files = set()
- found_symlinks = set()
- found_la_files = set() # la libraries
-
- for _dir in dirs:
- if _dir in mask:
- continue
-
- try:
- for _listing in os.listdir(_dir):
- listing = os.path.join(_dir, _listing)
- if listing in mask or _listing in mask:
- continue
-
- if os.path.isdir(listing):
- if os.path.islink(listing):
- #we do not want scan symlink-directories
- pass
- else:
- found_directories.add(listing)
- elif os.path.isfile(listing):
- if (listing.endswith('.so') or
- listing.endswith('.a') or
- '.so.' in listing
- ):
-
- if os.path.islink(listing):
- found_symlinks.add(listing)
- else:
- found_files.add(listing)
- continue
- elif listing.endswith('.la'):
- if listing in found_la_files:
- continue
-
- found_la_files.add(listing)
- else:
- # sometimes there are binaries in libs' subdir,
- # for example in nagios
- if not os.path.islink(listing):
- #if listing in found_files or listing in found_symlinks:
- #continue
- prv = os.stat(listing)[stat.ST_MODE]
- if prv & stat.S_IXUSR == stat.S_IXUSR or \
- prv & stat.S_IXGRP == stat.S_IXGRP or \
- prv & stat.S_IXOTH == stat.S_IXOTH:
- found_files.add(listing)
- except Exception as ex:
- logger.debug('\t' +
- yellow('Exception collecting libraries: ' +
- blue('%s') %str(ex)))
-
- if found_directories:
- _file, la_file, link = \
- collect_libraries_from_dir(found_directories, mask, logger)
- found_files.update(_file)
- found_la_files.update(la_file)
- found_symlinks.update(link)
- return (found_files, found_la_files, found_symlinks)
+ """Collects all libraries from specified list of directories.
+ mask is list of pathes, that are ommited in scanning, can be eighter single file or entire directory
+ Returns tuple composed of: list of libraries, list of symlinks, and toupe with pair
+ (symlink_id, library_id) for resolving dependencies
+ """
+
+ # contains list of directories found
+ # allows us to reduce number of fnc calls
+ found_directories = set()
+ found_files = set()
+ found_symlinks = set()
+ found_la_files = set() # la libraries
+
+ for _dir in dirs:
+ if _dir in mask:
+ continue
+
+ try:
+ for _listing in os.listdir(_dir):
+ listing = os.path.join(_dir, _listing)
+ if listing in mask or _listing in mask:
+ continue
+
+ if os.path.isdir(listing):
+ if os.path.islink(listing):
+ # we do not want scan symlink-directories
+ pass
+ else:
+ found_directories.add(listing)
+ elif os.path.isfile(listing):
+ if (
+ listing.endswith(".so")
+ or listing.endswith(".a")
+ or ".so." in listing
+ ):
+
+ if os.path.islink(listing):
+ found_symlinks.add(listing)
+ else:
+ found_files.add(listing)
+ continue
+ elif listing.endswith(".la"):
+ if listing in found_la_files:
+ continue
+
+ found_la_files.add(listing)
+ else:
+ # sometimes there are binaries in libs' subdir,
+ # for example in nagios
+ if not os.path.islink(listing):
+ # if listing in found_files or listing in found_symlinks:
+ # continue
+ prv = os.stat(listing)[stat.ST_MODE]
+ if (
+ prv & stat.S_IXUSR == stat.S_IXUSR
+ or prv & stat.S_IXGRP == stat.S_IXGRP
+ or prv & stat.S_IXOTH == stat.S_IXOTH
+ ):
+ found_files.add(listing)
+ except Exception as ex:
+ logger.debug(
+ "\t" + yellow("Exception collecting libraries: " + blue("%s") % str(ex))
+ )
+
+ if found_directories:
+ _file, la_file, link = collect_libraries_from_dir(
+ found_directories, mask, logger
+ )
+ found_files.update(_file)
+ found_la_files.update(la_file)
+ found_symlinks.update(link)
+ return (found_files, found_la_files, found_symlinks)
def collect_binaries_from_dir(dirs, mask, logger):
- ''' Collects all binaries from specified list of directories.
- mask is list of pathes, that are ommited in scanning,
- can be eighter single file or entire directory
- Returns list of binaries
- '''
-
- # contains list of directories found
- # allows us to reduce number of fnc calls
- found_directories = set()
- found_files = set()
-
- for _dir in dirs:
- if _dir in mask:
- continue
-
- try:
- for _listing in os.listdir(_dir):
- listing = os.path.join(_dir, _listing)
- if listing in mask or _listing in mask:
- continue
-
- if os.path.isdir(listing):
- if os.path.islink(listing):
- #we do not want scan symlink-directories
- pass
- else:
- found_directories.add(listing)
- elif os.path.isfile(listing):
- # we're looking for binaries
- # and with binaries we do not need links
- # thus we can optimize a bit
- if not os.path.islink(listing):
- prv = os.stat(listing)[stat.ST_MODE]
- if prv & stat.S_IXUSR == stat.S_IXUSR or \
- prv & stat.S_IXGRP == stat.S_IXGRP or \
- prv & stat.S_IXOTH == stat.S_IXOTH:
- found_files.add(listing)
- except Exception as ex:
- logger.debug('\t' +
- yellow('Exception during binaries collecting: '+
- blue('%s') %str(ex)))
-
- if found_directories:
- found_files.update(collect_binaries_from_dir(found_directories, mask, logger))
-
- return found_files
-
-
-
-if __name__ == '__main__':
- import logging
- bin_dirs, lib_dirs = prepare_search_dirs(logging)
-
- masked_dirs, masked_files, ld = parse_revdep_config()
- lib_dirs.update(ld)
- bin_dirs.update(ld)
- masked_dirs.update(
- set([
- '/lib/modules',
- '/lib32/modules',
- '/lib64/modules',
- ])
- )
-
- libraries, la_libraries, libraries_links = \
- collect_libraries_from_dir(lib_dirs, masked_dirs, logging)
- binaries = collect_binaries_from_dir(bin_dirs, masked_dirs, logging)
-
- logging.debug(
- 'Found: %i binaries and %i libraries.' %(
- len(binaries), len(libraries)))
-
-
-
+ """Collects all binaries from specified list of directories.
+ mask is list of pathes, that are ommited in scanning,
+ can be eighter single file or entire directory
+ Returns list of binaries
+ """
+
+ # contains list of directories found
+ # allows us to reduce number of fnc calls
+ found_directories = set()
+ found_files = set()
+
+ for _dir in dirs:
+ if _dir in mask:
+ continue
+
+ try:
+ for _listing in os.listdir(_dir):
+ listing = os.path.join(_dir, _listing)
+ if listing in mask or _listing in mask:
+ continue
+
+ if os.path.isdir(listing):
+ if os.path.islink(listing):
+ # we do not want scan symlink-directories
+ pass
+ else:
+ found_directories.add(listing)
+ elif os.path.isfile(listing):
+ # we're looking for binaries
+ # and with binaries we do not need links
+ # thus we can optimize a bit
+ if not os.path.islink(listing):
+ prv = os.stat(listing)[stat.ST_MODE]
+ if (
+ prv & stat.S_IXUSR == stat.S_IXUSR
+ or prv & stat.S_IXGRP == stat.S_IXGRP
+ or prv & stat.S_IXOTH == stat.S_IXOTH
+ ):
+ found_files.add(listing)
+ except Exception as ex:
+ logger.debug(
+ "\t"
+ + yellow(
+ "Exception during binaries collecting: " + blue("%s") % str(ex)
+ )
+ )
+
+ if found_directories:
+ found_files.update(collect_binaries_from_dir(found_directories, mask, logger))
+
+ return found_files
+
+
+if __name__ == "__main__":
+ import logging
+
+ bin_dirs, lib_dirs = prepare_search_dirs(logging)
+
+ masked_dirs, masked_files, ld = parse_revdep_config()
+ lib_dirs.update(ld)
+ bin_dirs.update(ld)
+ masked_dirs.update(
+ set(
+ [
+ "/lib/modules",
+ "/lib32/modules",
+ "/lib64/modules",
+ ]
+ )
+ )
+
+ libraries, la_libraries, libraries_links = collect_libraries_from_dir(
+ lib_dirs, masked_dirs, logging
+ )
+ binaries = collect_binaries_from_dir(bin_dirs, masked_dirs, logging)
+
+ logging.debug(
+ "Found: %i binaries and %i libraries." % (len(binaries), len(libraries))
+ )
diff --git a/pym/gentoolkit/revdep_rebuild/rebuild.py b/pym/gentoolkit/revdep_rebuild/rebuild.py
index 4109c4f..75e209d 100644
--- a/pym/gentoolkit/revdep_rebuild/rebuild.py
+++ b/pym/gentoolkit/revdep_rebuild/rebuild.py
@@ -19,6 +19,7 @@ import sys
import logging
import subprocess
import time
+
current_milli_time = lambda: int(round(time.time() * 1000))
@@ -40,136 +41,149 @@ __productname__ = "revdep-ng"
# functions
-def init_logger(settings):
- """Creates and iitializes our logger according to the settings"""
- logger = logging.getLogger()
- log_handler = logging.StreamHandler(sys.stdout)
- log_fmt = logging.Formatter('%(msg)s')
- log_handler.setFormatter(log_fmt)
- logger.addHandler(log_handler)
- if settings['quiet']:
- logger.setLevel(logging.ERROR)
- elif settings['VERBOSITY'] == 2:
- logger.setLevel(logging.INFO)
- elif settings['VERBOSITY'] == 3 or settings['debug']:
- logger.setLevel(logging.DEBUG)
- else:
- logger.setLevel(logging.WARNING)
- return logger
-
+def init_logger(settings):
+ """Creates and iitializes our logger according to the settings"""
+ logger = logging.getLogger()
+ log_handler = logging.StreamHandler(sys.stdout)
+ log_fmt = logging.Formatter("%(msg)s")
+ log_handler.setFormatter(log_fmt)
+ logger.addHandler(log_handler)
+ if settings["quiet"]:
+ logger.setLevel(logging.ERROR)
+ elif settings["VERBOSITY"] == 2:
+ logger.setLevel(logging.INFO)
+ elif settings["VERBOSITY"] == 3 or settings["debug"]:
+ logger.setLevel(logging.DEBUG)
+ else:
+ logger.setLevel(logging.WARNING)
+ return logger
def rebuild(logger, assigned, settings):
- """rebuilds the assigned pkgs"""
-
- args = list(settings['pass_through_options'])
- if settings['EXACT']:
- _assigned = filter_masked(assigned, logger)
- emerge_command = ['='+a for a in _assigned]
- else:
- _assigned = get_slotted_cps(assigned, logger)
- emerge_command = [a for a in _assigned]
- if settings['PRETEND']:
- args.append('--pretend')
- if settings['VERBOSITY'] >= 2:
- args.append('--verbose')
- elif settings['VERBOSITY'] < 1:
- args.append('--quiet')
- if settings['nocolor']:
- args.extend(['--color', 'n'])
-
- if len(emerge_command) == 0:
- logger.warning(bold('\nThere is nothing to emerge. Exiting.'))
- return 0
-
- logger.warning(yellow(
- '\nemerge') + ' ' + ' '.join(args) +
- ' --oneshot --complete-graph=y ' +
- bold(' '.join(emerge_command)))
-
- stime = current_milli_time()
- _args = ['emerge'] + args + ['--oneshot', '--complete-graph=y'] + emerge_command
- success = subprocess.call(_args)
- ftime = current_milli_time()
- logger.debug("\trebuild(); emerge call for %d ebuilds took: %s seconds"
- % (len(_assigned), str((ftime-stime)/1000.0)))
- return success
+ """rebuilds the assigned pkgs"""
+
+ args = list(settings["pass_through_options"])
+ if settings["EXACT"]:
+ _assigned = filter_masked(assigned, logger)
+ emerge_command = ["=" + a for a in _assigned]
+ else:
+ _assigned = get_slotted_cps(assigned, logger)
+ emerge_command = [a for a in _assigned]
+ if settings["PRETEND"]:
+ args.append("--pretend")
+ if settings["VERBOSITY"] >= 2:
+ args.append("--verbose")
+ elif settings["VERBOSITY"] < 1:
+ args.append("--quiet")
+ if settings["nocolor"]:
+ args.extend(["--color", "n"])
+
+ if len(emerge_command) == 0:
+ logger.warning(bold("\nThere is nothing to emerge. Exiting."))
+ return 0
+
+ logger.warning(
+ yellow("\nemerge")
+ + " "
+ + " ".join(args)
+ + " --oneshot --complete-graph=y "
+ + bold(" ".join(emerge_command))
+ )
+
+ stime = current_milli_time()
+ _args = ["emerge"] + args + ["--oneshot", "--complete-graph=y"] + emerge_command
+ success = subprocess.call(_args)
+ ftime = current_milli_time()
+ logger.debug(
+ "\trebuild(); emerge call for %d ebuilds took: %s seconds"
+ % (len(_assigned), str((ftime - stime) / 1000.0))
+ )
+ return success
def main(settings=None, logger=None):
- """Main program operation method....
-
- @param settings: dict. defaults to settings.DEFAULTS
- @param logger: python logging module defaults to init_logger(settings)
- @return boolean success/failure
- """
- if settings is None:
- print("NO Input settings, using defaults...")
- settings = DEFAULTS.copy()
-
- if logger is None:
- logger = init_logger(settings)
-
- _libs_to_check = settings['library']
-
- if not settings['stdout'].isatty() or settings['nocolor']:
- nocolor()
-
- logger.warning(blue(' * ') +
- yellow('This is the new python coded version'))
- logger.warning(blue(' * ') +
- yellow('Please report any bugs found using it.'))
- logger.warning(blue(' * ') +
- yellow('The original revdep-rebuild script is '
- 'installed as revdep-rebuild.sh'))
- logger.warning(blue(' * ') +
- yellow('Please file bugs at: '
- 'https://bugs.gentoo.org/'))
-
- if os.getuid() != 0 and not settings['PRETEND']:
- logger.warning(blue(' * ') +
- yellow('You are not root, adding --pretend to portage options'))
- settings['PRETEND'] = True
-
- logger.debug("\tmain(), _libs_to_check = %s" % str(_libs_to_check))
-
- if settings['USE_TMP_FILES'] \
- and check_temp_files(settings['DEFAULT_TMP_DIR'], logger=logger):
- libraries, la_libraries, libraries_links, binaries = read_cache(
- settings['DEFAULT_TMP_DIR'])
- assigned, orphaned = analyse(
- settings=settings,
- logger=logger,
- libraries=libraries,
- la_libraries=la_libraries,
- libraries_links=libraries_links,
- binaries=binaries,
- _libs_to_check=_libs_to_check)
- else:
- assigned, orphaned = analyse(settings, logger, _libs_to_check=_libs_to_check)
-
- if not assigned and not orphaned:
- logger.warning('\n' + bold('Your system is consistent'))
- # return the correct exit code
- return 0
- elif orphaned:
- # blank line for beter visibility of the following lines
- logger.warning('')
- if settings['library']:
- logger.warning(red(' !!! Dependant orphaned files: ') +
- bold('No installed package was found for the following:'))
- else:
- logger.warning(red(' !!! Broken orphaned files: ') +
- bold('No installed package was found for the following:'))
- for filename in orphaned:
- logger.warning(red('\t* ') + filename)
-
- success = rebuild(logger, assigned, settings)
- logger.debug("rebuild return code = %i" %success)
- return success
-
-
-if __name__ == '__main__':
- main(parse_options())
-
+ """Main program operation method....
+
+ @param settings: dict. defaults to settings.DEFAULTS
+ @param logger: python logging module defaults to init_logger(settings)
+ @return boolean success/failure
+ """
+ if settings is None:
+ print("NO Input settings, using defaults...")
+ settings = DEFAULTS.copy()
+
+ if logger is None:
+ logger = init_logger(settings)
+
+ _libs_to_check = settings["library"]
+
+ if not settings["stdout"].isatty() or settings["nocolor"]:
+ nocolor()
+
+ logger.warning(blue(" * ") + yellow("This is the new python coded version"))
+ logger.warning(blue(" * ") + yellow("Please report any bugs found using it."))
+ logger.warning(
+ blue(" * ")
+ + yellow(
+ "The original revdep-rebuild script is " "installed as revdep-rebuild.sh"
+ )
+ )
+ logger.warning(
+ blue(" * ") + yellow("Please file bugs at: " "https://bugs.gentoo.org/")
+ )
+
+ if os.getuid() != 0 and not settings["PRETEND"]:
+ logger.warning(
+ blue(" * ")
+ + yellow("You are not root, adding --pretend to portage options")
+ )
+ settings["PRETEND"] = True
+
+ logger.debug("\tmain(), _libs_to_check = %s" % str(_libs_to_check))
+
+ if settings["USE_TMP_FILES"] and check_temp_files(
+ settings["DEFAULT_TMP_DIR"], logger=logger
+ ):
+ libraries, la_libraries, libraries_links, binaries = read_cache(
+ settings["DEFAULT_TMP_DIR"]
+ )
+ assigned, orphaned = analyse(
+ settings=settings,
+ logger=logger,
+ libraries=libraries,
+ la_libraries=la_libraries,
+ libraries_links=libraries_links,
+ binaries=binaries,
+ _libs_to_check=_libs_to_check,
+ )
+ else:
+ assigned, orphaned = analyse(settings, logger, _libs_to_check=_libs_to_check)
+
+ if not assigned and not orphaned:
+ logger.warning("\n" + bold("Your system is consistent"))
+ # return the correct exit code
+ return 0
+ elif orphaned:
+ # blank line for beter visibility of the following lines
+ logger.warning("")
+ if settings["library"]:
+ logger.warning(
+ red(" !!! Dependant orphaned files: ")
+ + bold("No installed package was found for the following:")
+ )
+ else:
+ logger.warning(
+ red(" !!! Broken orphaned files: ")
+ + bold("No installed package was found for the following:")
+ )
+ for filename in orphaned:
+ logger.warning(red("\t* ") + filename)
+
+ success = rebuild(logger, assigned, settings)
+ logger.debug("rebuild return code = %i" % success)
+ return success
+
+
+if __name__ == "__main__":
+ main(parse_options())
diff --git a/pym/gentoolkit/revdep_rebuild/runner.py b/pym/gentoolkit/revdep_rebuild/runner.py
index 24411a5..5dd5c33 100644
--- a/pym/gentoolkit/revdep_rebuild/runner.py
+++ b/pym/gentoolkit/revdep_rebuild/runner.py
@@ -5,65 +5,60 @@ import subprocess
class ProcessRunner(threading.Thread):
- '''
+ """
ProcessRunner is class designed to run arbitrary command
- in background (separate thread). It's replacement for old
+ in background (separate thread). It's replacement for old
stuff.call_program function.
-
+
When called program is finished, its output can be accessed
through .stdout and .stderr fields
- '''
-
+ """
+
def __init__(self, args, autorun=True):
- '''
+ """
@param args - program name and its arguments
@param autorun - if True, then automatically starts new thread
- '''
+ """
threading.Thread.__init__(self)
self.args = args
self.lock = threading.Lock()
- self.stdout = ''
- self.stderr = ''
-
+ self.stdout = ""
+ self.stderr = ""
+
if autorun:
self.start()
-
-
-
+
def run(self):
self.lock.acquire()
-
- subp = subprocess.Popen(self.args, stdout=subprocess.PIPE, \
- stderr=subprocess.PIPE)
+
+ subp = subprocess.Popen(
+ self.args, stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ )
self.stdout, self.stderr = subp.communicate()
self.lock.release()
-
-
+
def is_ready(self):
- ''' Checks whether current command is finished '''
+ """Checks whether current command is finished"""
return not self.lock.locked()
-
-
+
def wait(self):
- ''' Waits until called program finishes '''
+ """Waits until called program finishes"""
self.lock.acquire()
self.lock.release()
-
-
class ScanRunner(threading.Thread):
- '''
- ScanRunner is a class for calling scanelf in separate
+ """
+ ScanRunner is a class for calling scanelf in separate
thread, so several instances could be called at a time,
and then all results could be consolidated.
-
+
Consolidated output is available through .out
- '''
-
+ """
+
def __init__(self, params, files, max_args, autorun=True):
- '''
+ """
@param params is list of parameters that should be passed into scanelf app.
@param files list of files to scan.
@param max_args number of files to process at once
@@ -71,44 +66,42 @@ class ScanRunner(threading.Thread):
When files count is greater CMD_MAX_ARGS, then scanelf will be called
several times.
- '''
-
+ """
+
threading.Thread.__init__(self)
self.params = params
self.files = files
self.max_args = max_args
-
+
self.out = []
self.lock = threading.Lock()
-
+
if autorun:
self.start()
-
-
+
def run(self):
self.lock.acquire()
-
+
process_pool = []
for i in range(0, len(self.files), self.max_args):
- process_pool.append(ProcessRunner(['scanelf'] + self.params + self.files[i:i+self.max_args]))
-
+ process_pool.append(
+ ProcessRunner(
+ ["scanelf"] + self.params + self.files[i : i + self.max_args]
+ )
+ )
+
while process_pool:
p = process_pool.pop()
p.wait()
- self.out += p.stdout.strip().split('\n')
-
+ self.out += p.stdout.strip().split("\n")
+
self.lock.release()
-
-
+
def is_ready(self):
- ''' Checks whether scanning is finished '''
+ """Checks whether scanning is finished"""
return not self.lock.locked()
-
-
+
def wait(self):
- ''' Waits until all scanning instances are finished '''
+ """Waits until all scanning instances are finished"""
self.lock.acquire()
self.lock.release()
-
-
- \ No newline at end of file
diff --git a/pym/gentoolkit/revdep_rebuild/settings.py b/pym/gentoolkit/revdep_rebuild/settings.py
index c8d77bc..5551855 100644
--- a/pym/gentoolkit/revdep_rebuild/settings.py
+++ b/pym/gentoolkit/revdep_rebuild/settings.py
@@ -14,150 +14,173 @@ from portage import _encodings, _unicode_encode
portage_root = str(portage.root)
DEFAULTS = {
- 'DEFAULT_LD_FILE': os.path.join(portage_root, 'etc/ld.so.conf'),
- 'DEFAULT_ENV_FILE': os.path.join(portage_root, 'etc/profile.env'),
- 'REVDEP_CONFDIR': os.path.join(portage_root, 'etc/revdep-rebuild/'),
- 'PKG_DIR': os.path.join(portage_root, 'var/db/pkg/'),
- 'DEFAULT_TMP_DIR': os.path.join(portage_root, '/tmp/revdep-rebuild' if os.getgid() else '/var/cache/revdep-rebuild'), #cache default location
-
- # number of maximum allowed files to be parsed at once
- 'CMD_MAX_ARGS': 1000,
-
- 'PRETEND': False, #pretend only
- 'EXACT': False, #exact package version
- #if program should use temporary files from previous run
- 'USE_TMP_FILES': True,
-
- 'VERBOSITY': 1,
-
- 'quiet': False,
- 'nocolor': False,
- 'library': set(),
- 'no-progress': False,
- 'debug': False,
- 'no-ld-path': False,
- 'no-order': False,
- 'pass_through_options': [],
- 'stdout': sys.stdout,
- 'stdin': sys.stdin,
- 'stderr': sys.stderr
- }
+ "DEFAULT_LD_FILE": os.path.join(portage_root, "etc/ld.so.conf"),
+ "DEFAULT_ENV_FILE": os.path.join(portage_root, "etc/profile.env"),
+ "REVDEP_CONFDIR": os.path.join(portage_root, "etc/revdep-rebuild/"),
+ "PKG_DIR": os.path.join(portage_root, "var/db/pkg/"),
+ "DEFAULT_TMP_DIR": os.path.join(
+ portage_root,
+ "/tmp/revdep-rebuild" if os.getgid() else "/var/cache/revdep-rebuild",
+ ), # cache default location
+ # number of maximum allowed files to be parsed at once
+ "CMD_MAX_ARGS": 1000,
+ "PRETEND": False, # pretend only
+ "EXACT": False, # exact package version
+ # if program should use temporary files from previous run
+ "USE_TMP_FILES": True,
+ "VERBOSITY": 1,
+ "quiet": False,
+ "nocolor": False,
+ "library": set(),
+ "no-progress": False,
+ "debug": False,
+ "no-ld-path": False,
+ "no-order": False,
+ "pass_through_options": [],
+ "stdout": sys.stdout,
+ "stdin": sys.stdin,
+ "stderr": sys.stderr,
+}
def parse_options():
- """Parses the command line options an sets settings accordingly"""
-
- # TODO: Verify: options: no-ld-path, no-order, no-progress
- #are not appliable
- from .rebuild import VERSION, APP_NAME
- settings = DEFAULTS.copy()
-
- parser = argparse.ArgumentParser(
- description='Broken reverse dependency rebuilder, python implementation.',
- epilog='Calls emerge, options after -- are ignored by %s '
- 'and passed directly to emerge.' % APP_NAME,
- add_help=False
- )
-
- parser.add_argument('-h', '--help',
- action='help',
- help='Print this usage and exit')
- parser.add_argument('-V', '--version',
- action='version',
- help='Show version informations',
- version='%(prog)s ' + VERSION)
-
- parser.add_argument('-i', '--ignore',
- action='store_true',
- help='Ignore temporary files from previous runs '
- '(also won\'t create any)')
-
- parser.add_argument('-L', '--library',
- action='append',
- help='Unconditionally emerge existing packages that use '
- 'the library with NAME. NAME can be a full path, full '
- 'or partial name')
- parser.add_argument('-l', '--no-ld-path',
- action='store_true',
- help='Do not set LD_LIBRARY_PATH')
- parser.add_argument('-o', '--no-order',
- action='store_true',
- help='Do not check the build order '
- '(Saves time, but may cause breakage.)')
- parser.add_argument('-p', '--pretend',
- action='store_true',
- help='Do a trial run without actually emerging anything '
- '(also passed to emerge command)')
-
- parser.add_argument('-C', '--nocolor',
- action='store_true',
- help='Turn off colored output')
- parser.add_argument('-q', '--quiet',
- action='store_true',
- help='Be less verbose (also passed to emerge command)')
- parser.add_argument('-v', '--verbose',
- action='store_true',
- help='Be more verbose (also passed to emerge command)')
- parser.add_argument('-d', '--debug',
- action='store_true',
- help='Print debug informations')
-
- parser.add_argument('portage_options', nargs='*')
-
- args = parser.parse_args()
- settings['VERBOSITY'] = 3 if args.debug else 2 if args.verbose else 0 if args.quiet else 1
- settings['quiet'] = args.quiet
- settings['PRETEND'] = args.pretend
- settings['nocolor'] = args.nocolor
- if args.library:
- settings['library'] = set(settings['library']) | set(args.library)
- settings['USE_TMP_FILES'] = not args.ignore
- settings['pass_through_options'] = list(settings['pass_through_options']) + args.portage_options
-
- return settings
+ """Parses the command line options an sets settings accordingly"""
+
+ # TODO: Verify: options: no-ld-path, no-order, no-progress
+ # are not appliable
+ from .rebuild import VERSION, APP_NAME
+
+ settings = DEFAULTS.copy()
+
+ parser = argparse.ArgumentParser(
+ description="Broken reverse dependency rebuilder, python implementation.",
+ epilog="Calls emerge, options after -- are ignored by %s "
+ "and passed directly to emerge." % APP_NAME,
+ add_help=False,
+ )
+
+ parser.add_argument("-h", "--help", action="help", help="Print this usage and exit")
+ parser.add_argument(
+ "-V",
+ "--version",
+ action="version",
+ help="Show version informations",
+ version="%(prog)s " + VERSION,
+ )
+
+ parser.add_argument(
+ "-i",
+ "--ignore",
+ action="store_true",
+ help="Ignore temporary files from previous runs " "(also won't create any)",
+ )
+
+ parser.add_argument(
+ "-L",
+ "--library",
+ action="append",
+ help="Unconditionally emerge existing packages that use "
+ "the library with NAME. NAME can be a full path, full "
+ "or partial name",
+ )
+ parser.add_argument(
+ "-l", "--no-ld-path", action="store_true", help="Do not set LD_LIBRARY_PATH"
+ )
+ parser.add_argument(
+ "-o",
+ "--no-order",
+ action="store_true",
+ help="Do not check the build order " "(Saves time, but may cause breakage.)",
+ )
+ parser.add_argument(
+ "-p",
+ "--pretend",
+ action="store_true",
+ help="Do a trial run without actually emerging anything "
+ "(also passed to emerge command)",
+ )
+
+ parser.add_argument(
+ "-C", "--nocolor", action="store_true", help="Turn off colored output"
+ )
+ parser.add_argument(
+ "-q",
+ "--quiet",
+ action="store_true",
+ help="Be less verbose (also passed to emerge command)",
+ )
+ parser.add_argument(
+ "-v",
+ "--verbose",
+ action="store_true",
+ help="Be more verbose (also passed to emerge command)",
+ )
+ parser.add_argument(
+ "-d", "--debug", action="store_true", help="Print debug informations"
+ )
+
+ parser.add_argument("portage_options", nargs="*")
+
+ args = parser.parse_args()
+ settings["VERBOSITY"] = (
+ 3 if args.debug else 2 if args.verbose else 0 if args.quiet else 1
+ )
+ settings["quiet"] = args.quiet
+ settings["PRETEND"] = args.pretend
+ settings["nocolor"] = args.nocolor
+ if args.library:
+ settings["library"] = set(settings["library"]) | set(args.library)
+ settings["USE_TMP_FILES"] = not args.ignore
+ settings["pass_through_options"] = (
+ list(settings["pass_through_options"]) + args.portage_options
+ )
+
+ return settings
def _parse_dirs_to_set(dir_str):
- '''Changes space-delimited directory list into set with them
- '''
- _ret = set()
- for search in dir_str.split():
- if search == '-*':
- break
- _ret.update(glob.glob(search))
- return _ret
+ """Changes space-delimited directory list into set with them"""
+ _ret = set()
+ for search in dir_str.split():
+ if search == "-*":
+ break
+ _ret.update(glob.glob(search))
+ return _ret
def parse_revdep_config(revdep_confdir):
- ''' Parses all files under and returns
- tuple of: (masked_dirs, masked_files, search_dirs)'''
-
- search_dirs = os.environ.get('SEARCH_DIRS', '')
- masked_dirs = os.environ.get('SEARCH_DIRS_MASK', '')
- masked_files = os.environ.get('LD_LIBRARY_MASK', '')
-
- for _file in os.listdir(revdep_confdir):
- for line in open(_unicode_encode(os.path.join(revdep_confdir, _file),
- encoding=_encodings['fs']), encoding=_encodings['content']):
- line = line.strip()
- #first check for comment, we do not want to regex all lines
- if not line.startswith('#'):
- match = re.match(r'LD_LIBRARY_MASK=\"([^"]+)"', line)
- if match is not None:
- masked_files += ' ' + match.group(1)
- continue
- match = re.match(r'SEARCH_DIRS_MASK=\"([^"]+)"', line)
- if match is not None:
- masked_dirs += ' ' + match.group(1)
- continue
- match = re.match(r'SEARCH_DIRS="([^"]+)"', line)
- if match is not None:
- search_dirs += ' ' + match.group(1)
- continue
-
- masked_files = set(masked_files.split(' '))
- masked_dirs = _parse_dirs_to_set(masked_dirs)
- search_dirs = _parse_dirs_to_set(search_dirs)
-
- return (masked_dirs, masked_files, search_dirs)
-
+ """Parses all files under and returns
+ tuple of: (masked_dirs, masked_files, search_dirs)"""
+
+ search_dirs = os.environ.get("SEARCH_DIRS", "")
+ masked_dirs = os.environ.get("SEARCH_DIRS_MASK", "")
+ masked_files = os.environ.get("LD_LIBRARY_MASK", "")
+
+ for _file in os.listdir(revdep_confdir):
+ for line in open(
+ _unicode_encode(
+ os.path.join(revdep_confdir, _file), encoding=_encodings["fs"]
+ ),
+ encoding=_encodings["content"],
+ ):
+ line = line.strip()
+ # first check for comment, we do not want to regex all lines
+ if not line.startswith("#"):
+ match = re.match(r'LD_LIBRARY_MASK=\"([^"]+)"', line)
+ if match is not None:
+ masked_files += " " + match.group(1)
+ continue
+ match = re.match(r'SEARCH_DIRS_MASK=\"([^"]+)"', line)
+ if match is not None:
+ masked_dirs += " " + match.group(1)
+ continue
+ match = re.match(r'SEARCH_DIRS="([^"]+)"', line)
+ if match is not None:
+ search_dirs += " " + match.group(1)
+ continue
+
+ masked_files = set(masked_files.split(" "))
+ masked_dirs = _parse_dirs_to_set(masked_dirs)
+ search_dirs = _parse_dirs_to_set(search_dirs)
+
+ return (masked_dirs, masked_files, search_dirs)
diff --git a/pym/gentoolkit/revdep_rebuild/stuff.py b/pym/gentoolkit/revdep_rebuild/stuff.py
index 432dc8f..eee90c8 100644
--- a/pym/gentoolkit/revdep_rebuild/stuff.py
+++ b/pym/gentoolkit/revdep_rebuild/stuff.py
@@ -11,95 +11,103 @@ from portage.output import green, red
# util. functions
def call_program(args):
- ''' Calls program with specified parameters
- and returns the stdout as a str object.
+ """Calls program with specified parameters
+ and returns the stdout as a str object.
- @param, args: arument list to pass to subprocess
- @return str
- '''
- args = [arg if isinstance(arg, bytes) else arg.encode('utf-8') for arg in args]
- subp = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- stdout, stderr = subp.communicate()
- stdout = stdout.decode('utf-8')
- return stdout
+ @param, args: arument list to pass to subprocess
+ @return str
+ """
+ args = [arg if isinstance(arg, bytes) else arg.encode("utf-8") for arg in args]
+ subp = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = subp.communicate()
+ stdout = stdout.decode("utf-8")
+ return stdout
def scan(params, files, max_args, logger):
- ''' Calls scanelf with given params and files to scan.
- @param params is list of parameters that should
- be passed into scanelf app.
- @param files list of files to scan.
- @param max_args number of files to process at once
-
- When files count is greater CMD_MAX_ARGS, it'll be divided
- into several parts
-
- @return scanelf output (joined if was called several times)
- '''
- logger.debug("\tscan(), scanelf params = %s, # files: %d" % (params, len(files)))
- # change it to a sorted list for group processing
- _files = sorted(files)
- out = []
- for i in range(0, len(_files), max_args):
- output = call_program(
- ['scanelf'] + params + _files[i:i+max_args]).strip().split('\n')
- output = [x for x in output if x != '']
- if output:
- out.extend(output)
- logger.debug("\tscan(), final output length: %d" % len(out))
- return out
+ """Calls scanelf with given params and files to scan.
+ @param params is list of parameters that should
+ be passed into scanelf app.
+ @param files list of files to scan.
+ @param max_args number of files to process at once
+
+ When files count is greater CMD_MAX_ARGS, it'll be divided
+ into several parts
+
+ @return scanelf output (joined if was called several times)
+ """
+ logger.debug("\tscan(), scanelf params = %s, # files: %d" % (params, len(files)))
+ # change it to a sorted list for group processing
+ _files = sorted(files)
+ out = []
+ for i in range(0, len(_files), max_args):
+ output = (
+ call_program(["scanelf"] + params + _files[i : i + max_args])
+ .strip()
+ .split("\n")
+ )
+ output = [x for x in output if x != ""]
+ if output:
+ out.extend(output)
+ logger.debug("\tscan(), final output length: %d" % len(out))
+ return out
def get_masking_status(ebuild):
- """returns the masking status of an ebuild
+ """returns the masking status of an ebuild
- @param ebuild: str
- @return list
- """
- try:
- status = portage.getmaskingstatus(ebuild)
- except KeyError:
- status = ['unavailable']
- return status
+ @param ebuild: str
+ @return list
+ """
+ try:
+ status = portage.getmaskingstatus(ebuild)
+ except KeyError:
+ status = ["unavailable"]
+ return status
def _match_str_in_list(lst, stri):
- """
- @param lst: list
- @param stri: string
- @return boolean or list menber that matches stri.endswith(member)
- """
- for item in lst:
- if stri.endswith(item):
- return item
- return False
+ """
+ @param lst: list
+ @param stri: string
+ @return boolean or list menber that matches stri.endswith(member)
+ """
+ for item in lst:
+ if stri.endswith(item):
+ return item
+ return False
def filter_masked(assigned, logger):
- '''Filter out masked pkgs/ebuilds'''
-
- def is_masked(ebuild):
- if get_masking_status(ebuild):
- logger.warning(' !!! ' + red('All ebuilds that could satisfy: ') +
- green(ebuild) + red(' have been masked'))
- return True
- return False
-
- has_masked = False
- tmp = []
- for ebuild in assigned:
- if not is_masked(ebuild):
- tmp.append(ebuild)
- else:
- has_masked = True
- if has_masked:
- logger.info('\t' + red('* ') +
- 'Unmask all ebuild(s) listed above and call revdep-rebuild '
- 'again or manually emerge given packages.')
- return tmp
-
-
-
-
-if __name__ == '__main__':
- print("There is nothing to run here.")
+ """Filter out masked pkgs/ebuilds"""
+
+ def is_masked(ebuild):
+ if get_masking_status(ebuild):
+ logger.warning(
+ " !!! "
+ + red("All ebuilds that could satisfy: ")
+ + green(ebuild)
+ + red(" have been masked")
+ )
+ return True
+ return False
+
+ has_masked = False
+ tmp = []
+ for ebuild in assigned:
+ if not is_masked(ebuild):
+ tmp.append(ebuild)
+ else:
+ has_masked = True
+ if has_masked:
+ logger.info(
+ "\t"
+ + red("* ")
+ + "Unmask all ebuild(s) listed above and call revdep-rebuild "
+ "again or manually emerge given packages."
+ )
+ return tmp
+
+
+if __name__ == "__main__":
+ print("There is nothing to run here.")
diff --git a/pym/gentoolkit/sets.py b/pym/gentoolkit/sets.py
index d130603..4fd5ff4 100644
--- a/pym/gentoolkit/sets.py
+++ b/pym/gentoolkit/sets.py
@@ -4,54 +4,61 @@
"""Provides access to Portage sets api"""
-__docformat__ = 'epytext'
+__docformat__ = "epytext"
import portage
+
try:
- # Per commit 25d8427b3b29cbcee97279186983dae818495f8f in portage,
- # portage.sets is renamed to portage._sets.
- import portage._sets
- _sets_available = True
- SETPREFIX = portage._sets.SETPREFIX
+ # Per commit 25d8427b3b29cbcee97279186983dae818495f8f in portage,
+ # portage.sets is renamed to portage._sets.
+ import portage._sets
+
+ _sets_available = True
+ SETPREFIX = portage._sets.SETPREFIX
except ImportError:
- _sets_available = False
- SETPREFIX = "@"
+ _sets_available = False
+ SETPREFIX = "@"
from gentoolkit import errors
from gentoolkit.atom import Atom
_set_config = None
+
+
def _init_set_config():
- global _set_config
- if _set_config is None:
- _set_config = portage._sets.load_default_config(
- portage.settings, portage.db[portage.root])
+ global _set_config
+ if _set_config is None:
+ _set_config = portage._sets.load_default_config(
+ portage.settings, portage.db[portage.root]
+ )
+
def get_available_sets():
- """Returns all available sets."""
+ """Returns all available sets."""
+
+ if _sets_available:
+ _init_set_config()
+ return _set_config.getSets()
+ return {}
- if _sets_available:
- _init_set_config()
- return _set_config.getSets()
- return {}
def get_set_atoms(setname):
- """Return atoms belonging to the given set
-
- @type setname: string
- @param setname: Name of the set
- @rtype list
- @return: List of atoms in the given set
- """
-
- if _sets_available:
- _init_set_config()
- try:
- return set([Atom(str(x))
- for x in _set_config.getSetAtoms(setname)])
- except portage._sets.PackageSetNotFound:
- raise errors.GentoolkitSetNotFound(setname)
- raise errors.GentoolkitSetNotFound(setname)
+ """Return atoms belonging to the given set
+
+ @type setname: string
+ @param setname: Name of the set
+ @rtype list
+ @return: List of atoms in the given set
+ """
+
+ if _sets_available:
+ _init_set_config()
+ try:
+ return set([Atom(str(x)) for x in _set_config.getSetAtoms(setname)])
+ except portage._sets.PackageSetNotFound:
+ raise errors.GentoolkitSetNotFound(setname)
+ raise errors.GentoolkitSetNotFound(setname)
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/test/eclean/creator.py b/pym/gentoolkit/test/eclean/creator.py
index da5123e..7c47cf2 100644
--- a/pym/gentoolkit/test/eclean/creator.py
+++ b/pym/gentoolkit/test/eclean/creator.py
@@ -12,211 +12,242 @@ import random
import gentoolkit.pprinter as pp
from portage import _encodings, _unicode_encode
-__version__= "0.0.1"
+__version__ = "0.0.1"
__author__ = "Brian Dolbec"
__email__ = "brian.dolbec@gmail.com"
-dir_mode = int('0774', 8)
-file_mode = int('0644', 8)
+dir_mode = int("0774", 8)
+file_mode = int("0644", 8)
def make_dir(path):
- """create the directory at path
+ """create the directory at path
- @param path: full pathname to create
- capable of multiple intermediate directory creations.
- Will Error and exit if the target dir already exits"""
- try:
- os.makedirs(path, dir_mode)
- except EnvironmentError as er:
- print( pp.error("Error creating path:%s" %path), file=sys.stderr)
- print( pp.error("Error: %s" %str(er), file=sys.stderr))
- sys.exit(1)
+ @param path: full pathname to create
+ capable of multiple intermediate directory creations.
+ Will Error and exit if the target dir already exits"""
+ try:
+ os.makedirs(path, dir_mode)
+ except EnvironmentError as er:
+ print(pp.error("Error creating path:%s" % path), file=sys.stderr)
+ print(pp.error("Error: %s" % str(er), file=sys.stderr))
+ sys.exit(1)
def make_dist(path, files, clean_dict=None):
- """Creates a small fake distfiles/binpkg directory @path populated
- with generated files of small random sizes using real names from
- the files list. udates the clean_dict with fullpathname.
-
- @param path: the path to create the distfiles directory
- @param files: list of file names to populate "path" with
- @param clean_dict: dict of {file-key:[path/file-key,],}
- that will be updated with full file-path-names
- """
- make_dir(path)
- for file_ in files:
- size = random.randint(1000,5000)
- data = "0" * size
- filepath = os.path.join(path, file_)
- with open(_unicode_encode(filepath, encoding=_encodings['fs']), 'w', file_mode,
- encoding=_encodings['content']) as new_file:
- new_file.write(data)
- if file_ not in clean_dict:
- # it is included in a multifile target
- continue
- elif clean_dict[file_] == []:
- clean_dict[file_] = filepath
- else:
- file_list = clean_dict[file_]
- for key in range(len(file_list)):
- file_list[key] = os.path.join(path, file_list[key])
+ """Creates a small fake distfiles/binpkg directory @path populated
+ with generated files of small random sizes using real names from
+ the files list. udates the clean_dict with fullpathname.
+
+ @param path: the path to create the distfiles directory
+ @param files: list of file names to populate "path" with
+ @param clean_dict: dict of {file-key:[path/file-key,],}
+ that will be updated with full file-path-names
+ """
+ make_dir(path)
+ for file_ in files:
+ size = random.randint(1000, 5000)
+ data = "0" * size
+ filepath = os.path.join(path, file_)
+ with open(
+ _unicode_encode(filepath, encoding=_encodings["fs"]),
+ "w",
+ file_mode,
+ encoding=_encodings["content"],
+ ) as new_file:
+ new_file.write(data)
+ if file_ not in clean_dict:
+ # it is included in a multifile target
+ continue
+ elif clean_dict[file_] == []:
+ clean_dict[file_] = filepath
+ else:
+ file_list = clean_dict[file_]
+ for key in range(len(file_list)):
+ file_list[key] = os.path.join(path, file_list[key])
def make_pkgs(path, files_dict, clean_dict):
- """Create a small fake packages directory and call make_dist() to
- create and populate the category dir & package files
-
- @param path: the path to create the packages directory
- @param files_dict: dictionary of {cat: [pkg1, pkg2,...]}
- """
- make_dir(path)
- for cat in files_dict.keys():
- make_dist(os.path.join(path,cat),
- files_dict[cat],
- clean_dict)
- # cp the Packages index file to path
- source = os.path.join(os.path.dirname(__file__), 'Packages')
- shutil.copy2(source, path)
+ """Create a small fake packages directory and call make_dist() to
+ create and populate the category dir & package files
+
+ @param path: the path to create the packages directory
+ @param files_dict: dictionary of {cat: [pkg1, pkg2,...]}
+ """
+ make_dir(path)
+ for cat in files_dict.keys():
+ make_dist(os.path.join(path, cat), files_dict[cat], clean_dict)
+ # cp the Packages index file to path
+ source = os.path.join(os.path.dirname(__file__), "Packages")
+ shutil.copy2(source, path)
def make_symlinks(path, links, targets):
- """Create some symlinks at path
+ """Create some symlinks at path
- @param path: the location to create the symlinks at
- @param links: list of links to create
- @param targets: list of targets to create links for,
- and need to be in the same index order as links
- """
- for i in range(len(links)):
- os.symlink(os.path.join(path,targets[i]),
- os.path.join(path, links[i]))
+ @param path: the location to create the symlinks at
+ @param links: list of links to create
+ @param targets: list of targets to create links for,
+ and need to be in the same index order as links
+ """
+ for i in range(len(links)):
+ os.symlink(os.path.join(path, targets[i]), os.path.join(path, links[i]))
class TestDirCreation:
""""""
- distfile_list = ['ExtUtils-ParseXS-2.22.tar.gz',
- 'xorg-server-1.5.3.tar.bz2',
- 'portage-utils-0.2.1.tar.bz2',
- 'sysvinit_2.87dsf.orig.tar.gz',
- 'sysvinit-2.86.tar.gz',
- 'ExtUtils-ParseXS-2.20.tar.gz',
- 'libisofs-0.6.22.tar.gz',
- 'pixman-0.16.0.tar.bz2',
- 'libburn-0.7.2.pl01.tar.gz',
- 'libisofs-0.6.24.tar.gz',
- 'xorg-server-1.5.3-gentoo-patches-08.tar.bz2',
- 'ExtUtils-ParseXS-2.200401.tar.gz',
- 'sysvinit-2.87-patches-2.tar.bz2',
- 'sysvinit-2.86-kexec.patch',
- 'Module-Build-0.3601.tar.gz',
- 'libisofs-0.6.20.tar.gz',
- 'xine-lib-1.1.17.tar.bz2',
- 'pixman-0.14.0.tar.bz2',
- 'Archive-Tar-1.52.tar.gz',
- 'libburn-0.6.8.pl00.tar.gz',
- 'libexif-0.6.17.tar.bz2',
- 'portage-utils-0.3.tar.bz2',
- 'xine-lib-1.1.15-textrel-fix.patch',
- 'Module-Build-0.34.tar.gz',
- 'Archive-Tar-1.54.tar.gz',
- 'pixman-0.16.2.tar.bz2',
- 'libburn-0.7.4.pl00.tar.gz ',
- 'Module-Build-0.340201.tar.gz',
- 'pixman-0.17.2.tar.bz2',
- 'util-macros-1.3.0.tar.bz2',
- 'Module-Build-0.35.tar.gz',
- 'libburn-0.7.2.pl00.tar.gz',
- 'util-macros-1.4.1.tar.bz2',
- 'xine-lib-1.1.16.3.tar.bz2',
- 'sysvinit-2.86-extra.patch',
- 'libburn-0.7.0.pl00.tar.gz',
- 'ExtUtils-ParseXS-2.21.tar.gz',
- 'libexif-0.6.19.tar.bz2',
- 'sysvinit-2.87-patches-1.tar.bz2',
+ distfile_list = [
+ "ExtUtils-ParseXS-2.22.tar.gz",
+ "xorg-server-1.5.3.tar.bz2",
+ "portage-utils-0.2.1.tar.bz2",
+ "sysvinit_2.87dsf.orig.tar.gz",
+ "sysvinit-2.86.tar.gz",
+ "ExtUtils-ParseXS-2.20.tar.gz",
+ "libisofs-0.6.22.tar.gz",
+ "pixman-0.16.0.tar.bz2",
+ "libburn-0.7.2.pl01.tar.gz",
+ "libisofs-0.6.24.tar.gz",
+ "xorg-server-1.5.3-gentoo-patches-08.tar.bz2",
+ "ExtUtils-ParseXS-2.200401.tar.gz",
+ "sysvinit-2.87-patches-2.tar.bz2",
+ "sysvinit-2.86-kexec.patch",
+ "Module-Build-0.3601.tar.gz",
+ "libisofs-0.6.20.tar.gz",
+ "xine-lib-1.1.17.tar.bz2",
+ "pixman-0.14.0.tar.bz2",
+ "Archive-Tar-1.52.tar.gz",
+ "libburn-0.6.8.pl00.tar.gz",
+ "libexif-0.6.17.tar.bz2",
+ "portage-utils-0.3.tar.bz2",
+ "xine-lib-1.1.15-textrel-fix.patch",
+ "Module-Build-0.34.tar.gz",
+ "Archive-Tar-1.54.tar.gz",
+ "pixman-0.16.2.tar.bz2",
+ "libburn-0.7.4.pl00.tar.gz ",
+ "Module-Build-0.340201.tar.gz",
+ "pixman-0.17.2.tar.bz2",
+ "util-macros-1.3.0.tar.bz2",
+ "Module-Build-0.35.tar.gz",
+ "libburn-0.7.2.pl00.tar.gz",
+ "util-macros-1.4.1.tar.bz2",
+ "xine-lib-1.1.16.3.tar.bz2",
+ "sysvinit-2.86-extra.patch",
+ "libburn-0.7.0.pl00.tar.gz",
+ "ExtUtils-ParseXS-2.21.tar.gz",
+ "libexif-0.6.19.tar.bz2",
+ "sysvinit-2.87-patches-1.tar.bz2",
# now a base pkg with 2 additional symlink targets
- 'symlink-test-1.2.3.tar.bz2',
- 'target-1',
- 'target-2'
- ]
+ "symlink-test-1.2.3.tar.bz2",
+ "target-1",
+ "target-2",
+ ]
- distfile_symlink = ['symlink-test-1.2.3-symlink1',
- 'symlink-test-1.2.3-symlink2']
+ distfile_symlink = ["symlink-test-1.2.3-symlink1", "symlink-test-1.2.3-symlink2"]
dist_clean = {
- 'Archive-Tar-1.52.tar.gz': [],
- 'ExtUtils-ParseXS-2.20.tar.gz': [],
- 'ExtUtils-ParseXS-2.200401.tar.gz': [],
- 'ExtUtils-ParseXS-2.21.tar.gz': [],
- 'Module-Build-0.34.tar.gz': [],
- 'Module-Build-0.340201.tar.gz': [],
- 'Module-Build-0.35.tar.gz': [],
- 'libburn-0.6.8.pl00.tar.gz': [],
- 'libburn-0.7.0.pl00.tar.gz': [],
- 'libburn-0.7.2.pl00.tar.gz': [],
- 'libburn-0.7.2.pl01.tar.gz': [],
- 'libexif-0.6.17.tar.bz2': [],
- 'libisofs-0.6.20.tar.gz': [],
- 'libisofs-0.6.22.tar.gz': [],
- 'pixman-0.14.0.tar.bz2': [],
- 'pixman-0.16.0.tar.bz2': [],
- 'pixman-0.16.2.tar.bz2': [],
- 'portage-utils-0.2.1.tar.bz2': [],
- 'sysvinit-2.86.tar.gz': ['sysvinit-2.86.tar.gz',
- 'sysvinit-2.86-kexec.patch', 'sysvinit-2.86-extra.patch'],
- 'util-macros-1.3.0.tar.bz2': [],
- 'xine-lib-1.1.15-textrel-fix.patch': [],
- 'xine-lib-1.1.16.3.tar.bz2': [],
- 'xorg-server-1.5.3.tar.bz2': ['xorg-server-1.5.3.tar.bz2',
- 'xorg-server-1.5.3-gentoo-patches-08.tar.bz2'],
- 'symlink-test-1.2.3.tar.bz2': distfile_symlink
+ "Archive-Tar-1.52.tar.gz": [],
+ "ExtUtils-ParseXS-2.20.tar.gz": [],
+ "ExtUtils-ParseXS-2.200401.tar.gz": [],
+ "ExtUtils-ParseXS-2.21.tar.gz": [],
+ "Module-Build-0.34.tar.gz": [],
+ "Module-Build-0.340201.tar.gz": [],
+ "Module-Build-0.35.tar.gz": [],
+ "libburn-0.6.8.pl00.tar.gz": [],
+ "libburn-0.7.0.pl00.tar.gz": [],
+ "libburn-0.7.2.pl00.tar.gz": [],
+ "libburn-0.7.2.pl01.tar.gz": [],
+ "libexif-0.6.17.tar.bz2": [],
+ "libisofs-0.6.20.tar.gz": [],
+ "libisofs-0.6.22.tar.gz": [],
+ "pixman-0.14.0.tar.bz2": [],
+ "pixman-0.16.0.tar.bz2": [],
+ "pixman-0.16.2.tar.bz2": [],
+ "portage-utils-0.2.1.tar.bz2": [],
+ "sysvinit-2.86.tar.gz": [
+ "sysvinit-2.86.tar.gz",
+ "sysvinit-2.86-kexec.patch",
+ "sysvinit-2.86-extra.patch",
+ ],
+ "util-macros-1.3.0.tar.bz2": [],
+ "xine-lib-1.1.15-textrel-fix.patch": [],
+ "xine-lib-1.1.16.3.tar.bz2": [],
+ "xorg-server-1.5.3.tar.bz2": [
+ "xorg-server-1.5.3.tar.bz2",
+ "xorg-server-1.5.3-gentoo-patches-08.tar.bz2",
+ ],
+ "symlink-test-1.2.3.tar.bz2": distfile_symlink,
}
package_dict = {
- 'app-arch': ['p7zip-4.65.tbz2', 'p7zip-4.57.tbz2',
- 'file-roller-2.26.3.tbz2', 'tar-1.20.tbz2',
- 'p7zip-4.58.tbz2', 'file-roller-2.28.2.tbz2',
- 'file-roller-2.24.3.tbz2', 'gzip-1.4.tbz2', 'rar-3.9.0.tbz2',
- 'bzip2-1.0.5-r1.tbz2', 'cpio-2.10.tbz2', 'tar-1.21-r1.tbz2',
- 'cpio-2.10-r1.tbz2', 'file-roller-2.28.1.tbz2', 'cpio-2.9-r2.tbz2',
- 'tar-1.22.tbz2', 'cpio-2.9-r3.tbz2'],
- 'app-editors': ['nano-2.2.0.tbz2', 'nano-2.1.10.tbz2',
- 'nano-2.0.9.tbz2', 'nano-2.2.2.tbz2'],
- 'app-portage': ['layman-1.3.0_rc1-r3.tbz2', 'layman-1.2.6.tbz2',
- 'portage-utils-0.3.1.tbz2', 'layman-1.3.0.tbz2',
- 'layman-1.2.4-r3.tbz2', 'layman-1.2.3.tbz2',
- 'layman-1.3.0_rc1.tbz2'],
- 'sys-apps': ['shadow-4.0.18.2.tbz2', 'shadow-4.1.2.2.tbz2',
- 'openrc-0.6.0-r1.tbz2', 'shadow-4.1.4.2-r1.tbz2',
- 'shadow-4.1.4.2-r2.tbz2']
- }
+ "app-arch": [
+ "p7zip-4.65.tbz2",
+ "p7zip-4.57.tbz2",
+ "file-roller-2.26.3.tbz2",
+ "tar-1.20.tbz2",
+ "p7zip-4.58.tbz2",
+ "file-roller-2.28.2.tbz2",
+ "file-roller-2.24.3.tbz2",
+ "gzip-1.4.tbz2",
+ "rar-3.9.0.tbz2",
+ "bzip2-1.0.5-r1.tbz2",
+ "cpio-2.10.tbz2",
+ "tar-1.21-r1.tbz2",
+ "cpio-2.10-r1.tbz2",
+ "file-roller-2.28.1.tbz2",
+ "cpio-2.9-r2.tbz2",
+ "tar-1.22.tbz2",
+ "cpio-2.9-r3.tbz2",
+ ],
+ "app-editors": [
+ "nano-2.2.0.tbz2",
+ "nano-2.1.10.tbz2",
+ "nano-2.0.9.tbz2",
+ "nano-2.2.2.tbz2",
+ ],
+ "app-portage": [
+ "layman-1.3.0_rc1-r3.tbz2",
+ "layman-1.2.6.tbz2",
+ "portage-utils-0.3.1.tbz2",
+ "layman-1.3.0.tbz2",
+ "layman-1.2.4-r3.tbz2",
+ "layman-1.2.3.tbz2",
+ "layman-1.3.0_rc1.tbz2",
+ ],
+ "sys-apps": [
+ "shadow-4.0.18.2.tbz2",
+ "shadow-4.1.2.2.tbz2",
+ "openrc-0.6.0-r1.tbz2",
+ "shadow-4.1.4.2-r1.tbz2",
+ "shadow-4.1.4.2-r2.tbz2",
+ ],
+ }
pkg_clean = {
- 'app-arch/p7zip-4.57.tbz2': [],
- 'app-arch/file-roller-2.26.3.tbz2': [],
- 'app-arch/tar-1.20.tbz2': [],
- 'app-arch/p7zip-4.58.tbz2': [],
- 'app-arch/file-roller-2.28.2.tbz2': [],
- 'app-arch/file-roller-2.24.3.tbz2': [],
- 'app-arch/bzip2-1.0.5-r1.tbz2': [],
- 'app-arch/cpio-2.10.tbz2': [],
- 'app-arch/tar-1.21-r1.tbz2': [],
- 'app-arch/cpio-2.9-r2.tbz2': [],
- 'app-arch/cpio-2.9-r3.tbz2': [],
- 'app-editors/nano-2.2.0.tbz2': [],
- 'app-editors/nano-2.1.10.tbz2': [],
- 'app-editors/nano-2.0.9.tbz2': [],
- 'app-portage/layman-1.3.0_rc1-r3.tbz2': [],
- 'app-portage/layman-1.2.6.tbz2': [],
- 'app-portage/layman-1.2.4-r3.tbz2': [],
- 'app-portage/layman-1.2.3.tbz2': [],
- 'app-portage/layman-1.3.0_rc1.tbz2': [],
- 'sys-apps/shadow-4.0.18.2.tbz2': [],
- 'sys-apps/shadow-4.1.2.2.tbz2': [],
- 'sys-apps/shadow-4.1.4.2-r1.tbz2': [],
- }
+ "app-arch/p7zip-4.57.tbz2": [],
+ "app-arch/file-roller-2.26.3.tbz2": [],
+ "app-arch/tar-1.20.tbz2": [],
+ "app-arch/p7zip-4.58.tbz2": [],
+ "app-arch/file-roller-2.28.2.tbz2": [],
+ "app-arch/file-roller-2.24.3.tbz2": [],
+ "app-arch/bzip2-1.0.5-r1.tbz2": [],
+ "app-arch/cpio-2.10.tbz2": [],
+ "app-arch/tar-1.21-r1.tbz2": [],
+ "app-arch/cpio-2.9-r2.tbz2": [],
+ "app-arch/cpio-2.9-r3.tbz2": [],
+ "app-editors/nano-2.2.0.tbz2": [],
+ "app-editors/nano-2.1.10.tbz2": [],
+ "app-editors/nano-2.0.9.tbz2": [],
+ "app-portage/layman-1.3.0_rc1-r3.tbz2": [],
+ "app-portage/layman-1.2.6.tbz2": [],
+ "app-portage/layman-1.2.4-r3.tbz2": [],
+ "app-portage/layman-1.2.3.tbz2": [],
+ "app-portage/layman-1.3.0_rc1.tbz2": [],
+ "sys-apps/shadow-4.0.18.2.tbz2": [],
+ "sys-apps/shadow-4.1.2.2.tbz2": [],
+ "sys-apps/shadow-4.1.4.2-r1.tbz2": [],
+ }
def __init__(self, options):
"""Initialization
@@ -226,12 +257,13 @@ class TestDirCreation:
self.options = options
self.targets_init = False
# create distfiles dir and populate it
- make_dist(self.options['target_path'], self.distfile_list, self.dist_clean)
+ make_dist(self.options["target_path"], self.distfile_list, self.dist_clean)
# add some symlinks to it
- path = os.path.join(self.options['target_path'], 'distfiles')
- make_symlinks(path, self.distfile_symlink,
- self.dist_clean['symlink-test-1.2.3.tar.bz2'])
+ path = os.path.join(self.options["target_path"], "distfiles")
+ make_symlinks(
+ path, self.distfile_symlink, self.dist_clean["symlink-test-1.2.3.tar.bz2"]
+ )
# create the packages dir and populate it
- path = os.path.join(self.options['target_path'], 'packages')
+ path = os.path.join(self.options["target_path"], "packages")
make_pkgs(path, self.package_dict, self.pkg_clean)
self.targets_init = True
diff --git a/pym/gentoolkit/test/eclean/distsupport.py b/pym/gentoolkit/test/eclean/distsupport.py
index da7cdbb..58f5624 100644
--- a/pym/gentoolkit/test/eclean/distsupport.py
+++ b/pym/gentoolkit/test/eclean/distsupport.py
@@ -14,452 +14,507 @@ import portage
dir_mode = 0o774
CPVS = [
- 'sys-auth/consolekit-0.4.1',
- 'sys-apps/devicekit-power-014',
- 'media-libs/sdl-pango-0.1.2',
- 'sys-apps/help2man-1.37.1',
- 'app-emulation/emul-linux-x86-baselibs-20100220'
- ]
+ "sys-auth/consolekit-0.4.1",
+ "sys-apps/devicekit-power-014",
+ "media-libs/sdl-pango-0.1.2",
+ "sys-apps/help2man-1.37.1",
+ "app-emulation/emul-linux-x86-baselibs-20100220",
+]
PROPS = {
- 'sys-apps/devicekit-power-014': {
- 'SRC_URI':'http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz',
- "RESTRICT": ''},
- 'sys-apps/help2man-1.37.1': {
- "SRC_URI": 'mirror://gnu/help2man/help2man-1.37.1.tar.gz',
- "RESTRICT": ''},
- 'sys-auth/consolekit-0.4.1': {
- "SRC_URI": 'http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2',
- "RESTRICT": ''},
- 'app-emulation/emul-linux-x86-baselibs-20100220': {
- "SRC_URI": 'mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz',
- "RESTRICT": 'strip'},
- 'media-libs/sdl-pango-0.1.2': {
- "SRC_URI": 'mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch',
- "RESTRICT": ''},
- 'x11-base/xorg-server-1.6.5-r1': {
- "SRC_URI": 'http://xorg.freedesktop.org/releases/individual/xserver/xorg-server-1.6.5.tar.bz2 mirror://gentoo/xorg-server-1.6.5-gentoo-patches-01.tar.bz2',
- "RESTRICT": ''},
- 'perl-core/ExtUtils-ParseXS-2.20.0401': {
- "SRC_URI": 'mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.200401.tar.gz',
- "RESTRICT": ''},
- 'x11-misc/util-macros-1.3.0': {
- "SRC_URI": 'http://xorg.freedesktop.org/releases/individual/util/util-macros-1.3.0.tar.bz2',
- "RESTRICT": ''},
- 'x11-base/xorg-server-1.7.5': {
- "SRC_URI": 'http://xorg.freedesktop.org/releases/individual/xserver/xorg-server-1.7.5.tar.bz2',
- "RESTRICT": ''},
- 'app-portage/portage-utils-0.3.1': {
- "SRC_URI": 'mirror://gentoo/portage-utils-0.3.1.tar.bz2',
- "RESTRICT": ''},
- 'x11-misc/util-macros-1.5.0': {
- "SRC_URI": 'http://xorg.freedesktop.org/releases/individual/util/util-macros-1.5.0.tar.bz2',
- "RESTRICT": ''},
- 'perl-core/Module-Build-0.35': {
- "SRC_URI": 'mirror://cpan/authors/id/D/DA/DAGOLDEN//Module-Build-0.35.tar.gz',
- "RESTRICT": ''},
- 'perl-core/ExtUtils-ParseXS-2.22.02': {
- "SRC_URI": 'mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.2202.tar.gz',
- "RESTRICT": ''},
- 'perl-core/ExtUtils-ParseXS-2.22.03': {
- "SRC_URI": 'mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.2203.tar.gz',
- "RESTRICT": ''},
- 'perl-core/ExtUtils-ParseXS-2.22.01': {
- "SRC_URI": 'mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.2201.tar.gz',
- "RESTRICT": ''},
- 'perl-core/Archive-Tar-1.38': {
- "SRC_URI": 'mirror://cpan/authors/id/K/KA/KANE/Archive-Tar-1.38.tar.gz',
- "RESTRICT": ''},
- 'perl-core/Archive-Tar-1.58': {
- "SRC_URI": 'mirror://cpan/authors/id/B/BI/BINGOS//Archive-Tar-1.58.tar.gz',
- "RESTRICT": ''},
- 'perl-core/Archive-Tar-1.54': {
- "SRC_URI": 'mirror://cpan/authors/id/B/BI/BINGOS//Archive-Tar-1.54.tar.gz',
- "RESTRICT": ''},
- 'perl-core/Archive-Tar-1.56': {
- "SRC_URI": 'mirror://cpan/authors/id/B/BI/BINGOS//Archive-Tar-1.56.tar.gz',
- "RESTRICT": ''},
- 'app-portage/portage-utils-0.2.1': {
- "SRC_URI": 'mirror://gentoo/portage-utils-0.2.1.tar.bz2',
- "RESTRICT": ''},
- 'dev-libs/libisofs-0.6.20-r1': {
- "SRC_URI": 'http://files.libburnia-project.org/releases/libisofs-0.6.20.tar.gz',
- "RESTRICT": ''},
- 'perl-core/ExtUtils-ParseXS-2.22.02-r1': {
- "SRC_URI": 'mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.2202.tar.gz',
- "RESTRICT": ''},
- 'x11-misc/util-macros-1.6.0': {
- "SRC_URI": 'http://xorg.freedesktop.org/releases/individual/util/util-macros-1.6.0.tar.bz2',
- "RESTRICT": ''},
- 'x11-libs/pixman-0.16.0': {
- "SRC_URI": 'http://xorg.freedesktop.org/releases/individual/lib/pixman-0.16.0.tar.bz2',
- "RESTRICT": ''},
- 'x11-libs/pixman-0.16.4': {
- "SRC_URI": 'http://xorg.freedesktop.org/releases/individual/lib/pixman-0.16.4.tar.bz2',
- "RESTRICT": ''},
- 'x11-libs/pixman-0.17.4': {
- "SRC_URI": 'http://xorg.freedesktop.org/releases/individual/lib/pixman-0.17.4.tar.bz2',
- "RESTRICT": ''},
- 'x11-libs/pixman-0.17.2': {
- "SRC_URI": 'http://xorg.freedesktop.org/releases/individual/lib/pixman-0.17.2.tar.bz2',
- "RESTRICT": ''},
- 'dev-libs/libburn-0.7.6-r1': {
- "SRC_URI": 'http://files.libburnia-project.org/releases/libburn-0.7.6.pl00.tar.gz',
- "RESTRICT": ''},
- 'dev-libs/libburn-0.7.0': {
- "SRC_URI": 'http://files.libburnia-project.org/releases/libburn-0.7.0.pl00.tar.gz',
- "RESTRICT": ''},
- 'perl-core/Module-Build-0.34.0201': {
- "SRC_URI": 'mirror://cpan/authors/id/D/DA/DAGOLDEN//Module-Build-0.340201.tar.gz',
- "RESTRICT": ''},
- 'dev-libs/libburn-0.6.8': {
- "SRC_URI": 'http://files.libburnia-project.org/releases/libburn-0.6.8.pl00.tar.gz',
- "RESTRICT": ''},
- 'dev-libs/libburn-0.7.4': {
- "SRC_URI": 'http://files.libburnia-project.org/releases/libburn-0.7.4.pl00.tar.gz',
- "RESTRICT": ''},
- 'perl-core/Module-Build-0.36.03': {
- "SRC_URI": 'mirror://cpan/authors/id/D/DA/DAGOLDEN//Module-Build-0.3603.tar.gz',
- "RESTRICT": ''},
- 'perl-core/Module-Build-0.36.01': {
- "SRC_URI": 'mirror://cpan/authors/id/D/DA/DAGOLDEN//Module-Build-0.3601.tar.gz',
- "RESTRICT": ''},
- 'x11-base/xorg-server-1.5.3-r6': {
- "SRC_URI": 'http://xorg.freedesktop.org/releases/individual/xserver/xorg-server-1.5.3.tar.bz2 mirror://gentoo/xorg-server-1.5.3-gentoo-patches-08.tar.bz2',
- "RESTRICT": ''},
- 'dev-libs/libisofs-0.6.28': {
- "SRC_URI": 'http://files.libburnia-project.org/releases/libisofs-0.6.28.tar.gz',
- "RESTRICT": ''},
- 'media-libs/xine-lib-1.1.17': {
- "SRC_URI": 'mirror://sourceforge/xine/xine-lib-1.1.17.tar.bz2 mirror://gentoo/xine-lib-1.1.15-textrel-fix.patch',
- "RESTRICT": ''},
- 'media-libs/xine-lib-1.1.18': {
- "SRC_URI": 'mirror://sourceforge/xine/xine-lib-1.1.18.tar.xz mirror://gentoo/xine-lib-1.1.15-textrel-fix.patch mirror://gentoo/xine-lib-1.1.18-compat.c.tbz2',
- "RESTRICT": ''},
- 'perl-core/ExtUtils-ParseXS-2.22': {
- "SRC_URI": 'mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.22.tar.gz',
- "RESTRICT": ''},
- 'perl-core/ExtUtils-ParseXS-2.21': {
- "SRC_URI": 'mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.21.tar.gz',
- "RESTRICT": ''},
- 'x11-base/xorg-server-1.7.5.901': {
- "SRC_URI": 'http://xorg.freedesktop.org/releases/individual/xserver/xorg-server-1.7.5.901.tar.bz2',
- "RESTRICT": ''},
- 'dev-libs/libisofs-0.6.24': {
- "SRC_URI": 'http://files.libburnia-project.org/releases/libisofs-0.6.24.tar.gz',
- "RESTRICT": ''},
- 'dev-libs/libisofs-0.6.26': {
- "SRC_URI": 'http://files.libburnia-project.org/releases/libisofs-0.6.26.tar.gz',
- "RESTRICT": ''},
- 'app-portage/gentoolkit-0.3.0_rc8-r1': {
- "SRC_URI": 'mirror://gentoo/gentoolkit-0.3.0_rc8.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc8.tar.gz',
- "RESTRICT": ''},
- 'app-portage/gentoolkit-0.2.4.6-r1': {
- "SRC_URI": 'mirror://gentoo/gentoolkit-0.2.4.6.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.6.tar.gz',
- "RESTRICT": ''},
- 'app-portage/eix-0.20.2': {
- "SRC_URI": 'mirror://berlios/eix/eix-0.20.2.tar.xz',
- "RESTRICT": ''},
- 'app-portage/gentoolkit-0.2.4.5': {
- "SRC_URI": 'mirror://gentoo/gentoolkit-0.2.4.5.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.5.tar.gz',
- "RESTRICT": ''},
- 'app-portage/gentoolkit-0.3.0_rc8': {
- "SRC_URI": 'mirror://gentoo/gentoolkit-0.3.0_rc8.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc8.tar.gz',
- "RESTRICT": ''},
- 'app-portage/gentoolkit-0.2.4.6': {
- "SRC_URI": 'mirror://gentoo/gentoolkit-0.2.4.6.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.6.tar.gz',
- "RESTRICT": ''},
- 'app-portage/layman-1.3.0-r1': {
- "SRC_URI": 'mirror://sourceforge/layman/layman-1.3.0.tar.gz',
- "RESTRICT": ''},
- 'app-portage/gentoolkit-0.3.0_rc7': {
- "SRC_URI": 'mirror://gentoo/gentoolkit-0.3.0_rc7.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc7.tar.gz',
- "RESTRICT": ''},
- 'app-portage/layman-1.3.0': {
- "SRC_URI": 'mirror://sourceforge/layman/layman-1.3.0.tar.gz',
- "RESTRICT": ''},
- 'app-portage/layman-1.3.1': {
- "SRC_URI": 'mirror://sourceforge/layman/layman-1.3.1.tar.gz',
- "RESTRICT": ''},
- 'app-portage/layman-1.2.6': {
- "SRC_URI": 'mirror://sourceforge/layman/layman-1.2.6.tar.gz',
- "RESTRICT": ''},
- 'app-portage/layman-9999': {
- "SRC_URI": '',
- "RESTRICT": ''},
- 'app-portage/layman-1.2.5': {
- "SRC_URI": 'mirror://sourceforge/layman/layman-1.2.5.tar.gz',
- "RESTRICT": ''},
- 'app-portage/layman-1.3.0_rc1-r3': {
- "SRC_URI": 'mirror://sourceforge/layman/layman-1.3.0_rc1.tar.gz',
- "RESTRICT": ''},
- 'app-portage/gentoolkit-0.3.0_rc9': {
- "SRC_URI": 'mirror://gentoo/gentoolkit-0.3.0_rc9.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc9.tar.gz',
- "RESTRICT": ''},
- 'app-portage/eix-0.20.1': {
- "SRC_URI": 'mirror://sourceforge/eix/eix-0.20.1.tar.xz',
- "RESTRICT": ''},
- 'app-portage/eix-0.19.2': {
- "SRC_URI": 'mirror://sourceforge/eix/eix-0.19.2.tar.xz',
- "RESTRICT": ''},
- 'app-portage/layman-1.3.2-r1': {
- "SRC_URI": 'mirror://sourceforge/layman/layman-1.3.2.tar.gz',
- "RESTRICT": ''},
+ "sys-apps/devicekit-power-014": {
+ "SRC_URI": "http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz",
+ "RESTRICT": "",
+ },
+ "sys-apps/help2man-1.37.1": {
+ "SRC_URI": "mirror://gnu/help2man/help2man-1.37.1.tar.gz",
+ "RESTRICT": "",
+ },
+ "sys-auth/consolekit-0.4.1": {
+ "SRC_URI": "http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2",
+ "RESTRICT": "",
+ },
+ "app-emulation/emul-linux-x86-baselibs-20100220": {
+ "SRC_URI": "mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz",
+ "RESTRICT": "strip",
+ },
+ "media-libs/sdl-pango-0.1.2": {
+ "SRC_URI": "mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch",
+ "RESTRICT": "",
+ },
+ "x11-base/xorg-server-1.6.5-r1": {
+ "SRC_URI": "http://xorg.freedesktop.org/releases/individual/xserver/xorg-server-1.6.5.tar.bz2 mirror://gentoo/xorg-server-1.6.5-gentoo-patches-01.tar.bz2",
+ "RESTRICT": "",
+ },
+ "perl-core/ExtUtils-ParseXS-2.20.0401": {
+ "SRC_URI": "mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.200401.tar.gz",
+ "RESTRICT": "",
+ },
+ "x11-misc/util-macros-1.3.0": {
+ "SRC_URI": "http://xorg.freedesktop.org/releases/individual/util/util-macros-1.3.0.tar.bz2",
+ "RESTRICT": "",
+ },
+ "x11-base/xorg-server-1.7.5": {
+ "SRC_URI": "http://xorg.freedesktop.org/releases/individual/xserver/xorg-server-1.7.5.tar.bz2",
+ "RESTRICT": "",
+ },
+ "app-portage/portage-utils-0.3.1": {
+ "SRC_URI": "mirror://gentoo/portage-utils-0.3.1.tar.bz2",
+ "RESTRICT": "",
+ },
+ "x11-misc/util-macros-1.5.0": {
+ "SRC_URI": "http://xorg.freedesktop.org/releases/individual/util/util-macros-1.5.0.tar.bz2",
+ "RESTRICT": "",
+ },
+ "perl-core/Module-Build-0.35": {
+ "SRC_URI": "mirror://cpan/authors/id/D/DA/DAGOLDEN//Module-Build-0.35.tar.gz",
+ "RESTRICT": "",
+ },
+ "perl-core/ExtUtils-ParseXS-2.22.02": {
+ "SRC_URI": "mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.2202.tar.gz",
+ "RESTRICT": "",
+ },
+ "perl-core/ExtUtils-ParseXS-2.22.03": {
+ "SRC_URI": "mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.2203.tar.gz",
+ "RESTRICT": "",
+ },
+ "perl-core/ExtUtils-ParseXS-2.22.01": {
+ "SRC_URI": "mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.2201.tar.gz",
+ "RESTRICT": "",
+ },
+ "perl-core/Archive-Tar-1.38": {
+ "SRC_URI": "mirror://cpan/authors/id/K/KA/KANE/Archive-Tar-1.38.tar.gz",
+ "RESTRICT": "",
+ },
+ "perl-core/Archive-Tar-1.58": {
+ "SRC_URI": "mirror://cpan/authors/id/B/BI/BINGOS//Archive-Tar-1.58.tar.gz",
+ "RESTRICT": "",
+ },
+ "perl-core/Archive-Tar-1.54": {
+ "SRC_URI": "mirror://cpan/authors/id/B/BI/BINGOS//Archive-Tar-1.54.tar.gz",
+ "RESTRICT": "",
+ },
+ "perl-core/Archive-Tar-1.56": {
+ "SRC_URI": "mirror://cpan/authors/id/B/BI/BINGOS//Archive-Tar-1.56.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/portage-utils-0.2.1": {
+ "SRC_URI": "mirror://gentoo/portage-utils-0.2.1.tar.bz2",
+ "RESTRICT": "",
+ },
+ "dev-libs/libisofs-0.6.20-r1": {
+ "SRC_URI": "http://files.libburnia-project.org/releases/libisofs-0.6.20.tar.gz",
+ "RESTRICT": "",
+ },
+ "perl-core/ExtUtils-ParseXS-2.22.02-r1": {
+ "SRC_URI": "mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.2202.tar.gz",
+ "RESTRICT": "",
+ },
+ "x11-misc/util-macros-1.6.0": {
+ "SRC_URI": "http://xorg.freedesktop.org/releases/individual/util/util-macros-1.6.0.tar.bz2",
+ "RESTRICT": "",
+ },
+ "x11-libs/pixman-0.16.0": {
+ "SRC_URI": "http://xorg.freedesktop.org/releases/individual/lib/pixman-0.16.0.tar.bz2",
+ "RESTRICT": "",
+ },
+ "x11-libs/pixman-0.16.4": {
+ "SRC_URI": "http://xorg.freedesktop.org/releases/individual/lib/pixman-0.16.4.tar.bz2",
+ "RESTRICT": "",
+ },
+ "x11-libs/pixman-0.17.4": {
+ "SRC_URI": "http://xorg.freedesktop.org/releases/individual/lib/pixman-0.17.4.tar.bz2",
+ "RESTRICT": "",
+ },
+ "x11-libs/pixman-0.17.2": {
+ "SRC_URI": "http://xorg.freedesktop.org/releases/individual/lib/pixman-0.17.2.tar.bz2",
+ "RESTRICT": "",
+ },
+ "dev-libs/libburn-0.7.6-r1": {
+ "SRC_URI": "http://files.libburnia-project.org/releases/libburn-0.7.6.pl00.tar.gz",
+ "RESTRICT": "",
+ },
+ "dev-libs/libburn-0.7.0": {
+ "SRC_URI": "http://files.libburnia-project.org/releases/libburn-0.7.0.pl00.tar.gz",
+ "RESTRICT": "",
+ },
+ "perl-core/Module-Build-0.34.0201": {
+ "SRC_URI": "mirror://cpan/authors/id/D/DA/DAGOLDEN//Module-Build-0.340201.tar.gz",
+ "RESTRICT": "",
+ },
+ "dev-libs/libburn-0.6.8": {
+ "SRC_URI": "http://files.libburnia-project.org/releases/libburn-0.6.8.pl00.tar.gz",
+ "RESTRICT": "",
+ },
+ "dev-libs/libburn-0.7.4": {
+ "SRC_URI": "http://files.libburnia-project.org/releases/libburn-0.7.4.pl00.tar.gz",
+ "RESTRICT": "",
+ },
+ "perl-core/Module-Build-0.36.03": {
+ "SRC_URI": "mirror://cpan/authors/id/D/DA/DAGOLDEN//Module-Build-0.3603.tar.gz",
+ "RESTRICT": "",
+ },
+ "perl-core/Module-Build-0.36.01": {
+ "SRC_URI": "mirror://cpan/authors/id/D/DA/DAGOLDEN//Module-Build-0.3601.tar.gz",
+ "RESTRICT": "",
+ },
+ "x11-base/xorg-server-1.5.3-r6": {
+ "SRC_URI": "http://xorg.freedesktop.org/releases/individual/xserver/xorg-server-1.5.3.tar.bz2 mirror://gentoo/xorg-server-1.5.3-gentoo-patches-08.tar.bz2",
+ "RESTRICT": "",
+ },
+ "dev-libs/libisofs-0.6.28": {
+ "SRC_URI": "http://files.libburnia-project.org/releases/libisofs-0.6.28.tar.gz",
+ "RESTRICT": "",
+ },
+ "media-libs/xine-lib-1.1.17": {
+ "SRC_URI": "mirror://sourceforge/xine/xine-lib-1.1.17.tar.bz2 mirror://gentoo/xine-lib-1.1.15-textrel-fix.patch",
+ "RESTRICT": "",
+ },
+ "media-libs/xine-lib-1.1.18": {
+ "SRC_URI": "mirror://sourceforge/xine/xine-lib-1.1.18.tar.xz mirror://gentoo/xine-lib-1.1.15-textrel-fix.patch mirror://gentoo/xine-lib-1.1.18-compat.c.tbz2",
+ "RESTRICT": "",
+ },
+ "perl-core/ExtUtils-ParseXS-2.22": {
+ "SRC_URI": "mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.22.tar.gz",
+ "RESTRICT": "",
+ },
+ "perl-core/ExtUtils-ParseXS-2.21": {
+ "SRC_URI": "mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.21.tar.gz",
+ "RESTRICT": "",
+ },
+ "x11-base/xorg-server-1.7.5.901": {
+ "SRC_URI": "http://xorg.freedesktop.org/releases/individual/xserver/xorg-server-1.7.5.901.tar.bz2",
+ "RESTRICT": "",
+ },
+ "dev-libs/libisofs-0.6.24": {
+ "SRC_URI": "http://files.libburnia-project.org/releases/libisofs-0.6.24.tar.gz",
+ "RESTRICT": "",
+ },
+ "dev-libs/libisofs-0.6.26": {
+ "SRC_URI": "http://files.libburnia-project.org/releases/libisofs-0.6.26.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/gentoolkit-0.3.0_rc8-r1": {
+ "SRC_URI": "mirror://gentoo/gentoolkit-0.3.0_rc8.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc8.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/gentoolkit-0.2.4.6-r1": {
+ "SRC_URI": "mirror://gentoo/gentoolkit-0.2.4.6.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.6.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/eix-0.20.2": {
+ "SRC_URI": "mirror://berlios/eix/eix-0.20.2.tar.xz",
+ "RESTRICT": "",
+ },
+ "app-portage/gentoolkit-0.2.4.5": {
+ "SRC_URI": "mirror://gentoo/gentoolkit-0.2.4.5.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.5.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/gentoolkit-0.3.0_rc8": {
+ "SRC_URI": "mirror://gentoo/gentoolkit-0.3.0_rc8.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc8.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/gentoolkit-0.2.4.6": {
+ "SRC_URI": "mirror://gentoo/gentoolkit-0.2.4.6.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.6.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/layman-1.3.0-r1": {
+ "SRC_URI": "mirror://sourceforge/layman/layman-1.3.0.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/gentoolkit-0.3.0_rc7": {
+ "SRC_URI": "mirror://gentoo/gentoolkit-0.3.0_rc7.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc7.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/layman-1.3.0": {
+ "SRC_URI": "mirror://sourceforge/layman/layman-1.3.0.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/layman-1.3.1": {
+ "SRC_URI": "mirror://sourceforge/layman/layman-1.3.1.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/layman-1.2.6": {
+ "SRC_URI": "mirror://sourceforge/layman/layman-1.2.6.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/layman-9999": {"SRC_URI": "", "RESTRICT": ""},
+ "app-portage/layman-1.2.5": {
+ "SRC_URI": "mirror://sourceforge/layman/layman-1.2.5.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/layman-1.3.0_rc1-r3": {
+ "SRC_URI": "mirror://sourceforge/layman/layman-1.3.0_rc1.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/gentoolkit-0.3.0_rc9": {
+ "SRC_URI": "mirror://gentoo/gentoolkit-0.3.0_rc9.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc9.tar.gz",
+ "RESTRICT": "",
+ },
+ "app-portage/eix-0.20.1": {
+ "SRC_URI": "mirror://sourceforge/eix/eix-0.20.1.tar.xz",
+ "RESTRICT": "",
+ },
+ "app-portage/eix-0.19.2": {
+ "SRC_URI": "mirror://sourceforge/eix/eix-0.19.2.tar.xz",
+ "RESTRICT": "",
+ },
+ "app-portage/layman-1.3.2-r1": {
+ "SRC_URI": "mirror://sourceforge/layman/layman-1.3.2.tar.gz",
+ "RESTRICT": "",
+ },
}
PKGS = {
- 'app-portage/layman-1.3.2-r1': 'mirror://sourceforge/layman/layman-1.3.2.tar.gz',
- 'app-portage/eix-0.20.1': 'mirror://sourceforge/eix/eix-0.20.1.tar.xz',
- 'app-portage/eix-0.19.2': 'mirror://sourceforge/eix/eix-0.19.2.tar.xz',
- 'app-portage/gentoolkit-0.3.0_rc9': 'mirror://gentoo/gentoolkit-0.3.0_rc9.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc9.tar.gz',
- 'app-portage/gentoolkit-0.2.4.6': 'mirror://gentoo/gentoolkit-0.2.4.6.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.6.tar.gz',
- 'media-libs/xine-lib-1.1.18': 'mirror://sourceforge/xine/xine-lib-1.1.18.tar.xz mirror://gentoo/xine-lib-1.1.15-textrel-fix.patch mirror://gentoo/xine-lib-1.1.18-compat.c.tbz2',
- 'perl-core/ExtUtils-ParseXS-2.21': 'mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.21.tar.gz',
- 'dev-libs/libisofs-0.6.24': 'http://files.libburnia-project.org/releases/libisofs-0.6.24.tar.gz',
- }
+ "app-portage/layman-1.3.2-r1": "mirror://sourceforge/layman/layman-1.3.2.tar.gz",
+ "app-portage/eix-0.20.1": "mirror://sourceforge/eix/eix-0.20.1.tar.xz",
+ "app-portage/eix-0.19.2": "mirror://sourceforge/eix/eix-0.19.2.tar.xz",
+ "app-portage/gentoolkit-0.3.0_rc9": "mirror://gentoo/gentoolkit-0.3.0_rc9.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc9.tar.gz",
+ "app-portage/gentoolkit-0.2.4.6": "mirror://gentoo/gentoolkit-0.2.4.6.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.6.tar.gz",
+ "media-libs/xine-lib-1.1.18": "mirror://sourceforge/xine/xine-lib-1.1.18.tar.xz mirror://gentoo/xine-lib-1.1.15-textrel-fix.patch mirror://gentoo/xine-lib-1.1.18-compat.c.tbz2",
+ "perl-core/ExtUtils-ParseXS-2.21": "mirror://cpan/authors/id/D/DA/DAGOLDEN//ExtUtils-ParseXS-2.21.tar.gz",
+ "dev-libs/libisofs-0.6.24": "http://files.libburnia-project.org/releases/libisofs-0.6.24.tar.gz",
+}
CLEAN_ME = {
- 'layman-1.3.2.tar.gz': '/path/to/some/where/layman-1.3.2.tar.gz',
- 'layman-1.2.5.tar.gz': '/path/to/some/where/layman-1.2.5.tar.gz',
- 'eix-0.20.1.tar.xz': '/path/to/some/where/eix-0.20.1.tar.xz',
- 'gentoolkit-0.3.0_rc9.tar.gz': '/path/to/some/where/gentoolkit-0.3.0_rc9.tar.gz',
- 'xine-lib-1.1.18.tar.xz': '/path/to/some/where/xine-lib-1.1.18.tar.xz',
- 'xine-lib-1.1.15-textrel-fix.patch': '/path/to/some/where/xine-lib-1.1.15-textrel-fix.patch',
- 'xine-lib-1.1.18-compat.c.tbz2': '/path/to/some/where/xine-lib-1.1.18-compat.c.tbz2',
- 'ExtUtils-ParseXS-2.21.tar.gz': '/path/to/some/where/ExtUtils-ParseXS-2.21.tar.gz',
- 'libisofs-0.6.24.tar.gz': '/path/to/some/where/libisofs-0.6.24.tar.gz'
- }
+ "layman-1.3.2.tar.gz": "/path/to/some/where/layman-1.3.2.tar.gz",
+ "layman-1.2.5.tar.gz": "/path/to/some/where/layman-1.2.5.tar.gz",
+ "eix-0.20.1.tar.xz": "/path/to/some/where/eix-0.20.1.tar.xz",
+ "gentoolkit-0.3.0_rc9.tar.gz": "/path/to/some/where/gentoolkit-0.3.0_rc9.tar.gz",
+ "xine-lib-1.1.18.tar.xz": "/path/to/some/where/xine-lib-1.1.18.tar.xz",
+ "xine-lib-1.1.15-textrel-fix.patch": "/path/to/some/where/xine-lib-1.1.15-textrel-fix.patch",
+ "xine-lib-1.1.18-compat.c.tbz2": "/path/to/some/where/xine-lib-1.1.18-compat.c.tbz2",
+ "ExtUtils-ParseXS-2.21.tar.gz": "/path/to/some/where/ExtUtils-ParseXS-2.21.tar.gz",
+ "libisofs-0.6.24.tar.gz": "/path/to/some/where/libisofs-0.6.24.tar.gz",
+}
CPVS2 = [
- 'app-emulation/emul-linux-x86-baselibs-20100220',
- 'app-portage/eix-0.19.2', 'app-portage/eix-0.20.1',
- 'app-portage/eix-0.20.2',
- 'app-portage/gentoolkit-0.2.4.5',
- 'app-portage/gentoolkit-0.2.4.6',
- 'app-portage/gentoolkit-0.2.4.6-r1',
- 'app-portage/gentoolkit-0.3.0_rc7',
- 'app-portage/gentoolkit-0.3.0_rc8',
- 'app-portage/gentoolkit-0.3.0_rc8-r1',
- 'app-portage/gentoolkit-0.3.0_rc9',
- 'app-portage/layman-1.2.5',
- 'app-portage/layman-1.2.6',
- 'app-portage/layman-1.3.0',
- 'app-portage/layman-1.3.0-r1',
- 'app-portage/layman-1.3.0_rc1-r3',
- 'app-portage/layman-1.3.1',
- 'app-portage/layman-1.3.2-r1',
- 'app-portage/layman-9999',
- 'app-portage/portage-utils-0.2.1',
- 'app-portage/portage-utils-0.3.1',
- 'dev-libs/libburn-0.6.8',
- 'dev-libs/libburn-0.7.0',
- 'dev-libs/libburn-0.7.4',
- 'dev-libs/libburn-0.7.6-r1',
- 'dev-libs/libisofs-0.6.20-r1',
- 'dev-libs/libisofs-0.6.24',
- 'dev-libs/libisofs-0.6.26',
- 'dev-libs/libisofs-0.6.28',
- 'media-libs/sdl-pango-0.1.2',
- 'media-libs/xine-lib-1.1.17',
- 'media-libs/xine-lib-1.1.18',
- 'perl-core/Archive-Tar-1.38',
- 'perl-core/Archive-Tar-1.54',
- 'perl-core/Archive-Tar-1.56',
- 'perl-core/Archive-Tar-1.58',
- 'perl-core/ExtUtils-ParseXS-2.20.0401',
- 'perl-core/ExtUtils-ParseXS-2.21',
- 'perl-core/ExtUtils-ParseXS-2.22',
- 'perl-core/ExtUtils-ParseXS-2.22.01',
- 'perl-core/ExtUtils-ParseXS-2.22.02',
- 'perl-core/ExtUtils-ParseXS-2.22.02-r1',
- 'perl-core/ExtUtils-ParseXS-2.22.03',
- 'perl-core/Module-Build-0.34.0201',
- 'perl-core/Module-Build-0.35',
- 'perl-core/Module-Build-0.36.01',
- 'perl-core/Module-Build-0.36.03',
- 'sys-apps/devicekit-power-014',
- 'sys-apps/help2man-1.37.1',
- 'sys-auth/consolekit-0.4.1',
- 'x11-base/xorg-server-1.5.3-r6',
- 'x11-base/xorg-server-1.6.5-r1',
- 'x11-base/xorg-server-1.7.5',
- 'x11-base/xorg-server-1.7.5.901',
- 'x11-libs/pixman-0.16.0',
- 'x11-libs/pixman-0.16.4',
- 'x11-libs/pixman-0.17.2',
- 'x11-libs/pixman-0.17.4',
- 'x11-misc/util-macros-1.3.0',
- 'x11-misc/util-macros-1.5.0',
- 'x11-misc/util-macros-1.6.0'
- ]
+ "app-emulation/emul-linux-x86-baselibs-20100220",
+ "app-portage/eix-0.19.2",
+ "app-portage/eix-0.20.1",
+ "app-portage/eix-0.20.2",
+ "app-portage/gentoolkit-0.2.4.5",
+ "app-portage/gentoolkit-0.2.4.6",
+ "app-portage/gentoolkit-0.2.4.6-r1",
+ "app-portage/gentoolkit-0.3.0_rc7",
+ "app-portage/gentoolkit-0.3.0_rc8",
+ "app-portage/gentoolkit-0.3.0_rc8-r1",
+ "app-portage/gentoolkit-0.3.0_rc9",
+ "app-portage/layman-1.2.5",
+ "app-portage/layman-1.2.6",
+ "app-portage/layman-1.3.0",
+ "app-portage/layman-1.3.0-r1",
+ "app-portage/layman-1.3.0_rc1-r3",
+ "app-portage/layman-1.3.1",
+ "app-portage/layman-1.3.2-r1",
+ "app-portage/layman-9999",
+ "app-portage/portage-utils-0.2.1",
+ "app-portage/portage-utils-0.3.1",
+ "dev-libs/libburn-0.6.8",
+ "dev-libs/libburn-0.7.0",
+ "dev-libs/libburn-0.7.4",
+ "dev-libs/libburn-0.7.6-r1",
+ "dev-libs/libisofs-0.6.20-r1",
+ "dev-libs/libisofs-0.6.24",
+ "dev-libs/libisofs-0.6.26",
+ "dev-libs/libisofs-0.6.28",
+ "media-libs/sdl-pango-0.1.2",
+ "media-libs/xine-lib-1.1.17",
+ "media-libs/xine-lib-1.1.18",
+ "perl-core/Archive-Tar-1.38",
+ "perl-core/Archive-Tar-1.54",
+ "perl-core/Archive-Tar-1.56",
+ "perl-core/Archive-Tar-1.58",
+ "perl-core/ExtUtils-ParseXS-2.20.0401",
+ "perl-core/ExtUtils-ParseXS-2.21",
+ "perl-core/ExtUtils-ParseXS-2.22",
+ "perl-core/ExtUtils-ParseXS-2.22.01",
+ "perl-core/ExtUtils-ParseXS-2.22.02",
+ "perl-core/ExtUtils-ParseXS-2.22.02-r1",
+ "perl-core/ExtUtils-ParseXS-2.22.03",
+ "perl-core/Module-Build-0.34.0201",
+ "perl-core/Module-Build-0.35",
+ "perl-core/Module-Build-0.36.01",
+ "perl-core/Module-Build-0.36.03",
+ "sys-apps/devicekit-power-014",
+ "sys-apps/help2man-1.37.1",
+ "sys-auth/consolekit-0.4.1",
+ "x11-base/xorg-server-1.5.3-r6",
+ "x11-base/xorg-server-1.6.5-r1",
+ "x11-base/xorg-server-1.7.5",
+ "x11-base/xorg-server-1.7.5.901",
+ "x11-libs/pixman-0.16.0",
+ "x11-libs/pixman-0.16.4",
+ "x11-libs/pixman-0.17.2",
+ "x11-libs/pixman-0.17.4",
+ "x11-misc/util-macros-1.3.0",
+ "x11-misc/util-macros-1.5.0",
+ "x11-misc/util-macros-1.6.0",
+]
FILES = [
- 'DeviceKit-power-014.tar.gz',
- 'help2man-1.37.1.tar.gz',
- 'ConsoleKit-0.4.1.tar.bz2',
- 'emul-linux-x86-baselibs-20100220.tar.gz',
- 'SDL_Pango-0.1.2.tar.gz',
- 'SDL_Pango-0.1.2-API-adds.patch'
- ]
+ "DeviceKit-power-014.tar.gz",
+ "help2man-1.37.1.tar.gz",
+ "ConsoleKit-0.4.1.tar.bz2",
+ "emul-linux-x86-baselibs-20100220.tar.gz",
+ "SDL_Pango-0.1.2.tar.gz",
+ "SDL_Pango-0.1.2-API-adds.patch",
+]
CPVS3 = [
- 'x11-base/xorg-server-1.7.5',
- 'x11-misc/util-macros-1.6.0',
- 'x11-libs/pixman-0.16.4',
- #'dev-libs/libisofs-0.6.28',
- #'perl-core/Module-Build-0.36.03',
- #'perl-core/ExtUtils-ParseXS-2.22.02-r1',
- #'perl-core/Archive-Tar-1.56',
- #'app-portage/gentoolkit-0.3.0_rc8-r1',
- #'app-portage/layman-1.3.1',
- #'app-portage/eix-0.20.1',
- ]
-
-
-Exclude= {'packages': {
- 'media-libs/sdl-pango': None,
- },
- 'anti-packages': {'app-emulation/emul-linux-x86-baselibs': None},
- 'categories': {'app-portage': None,
- 'app-portage/gentoolkit': None
- },
- 'filenames': {'sys-auth/consolekit-0.4.1': re.compile(r'sys-auth/consolekit-0\.4\.1')
- }
- }
+ "x11-base/xorg-server-1.7.5",
+ "x11-misc/util-macros-1.6.0",
+ "x11-libs/pixman-0.16.4",
+ # 'dev-libs/libisofs-0.6.28',
+ # 'perl-core/Module-Build-0.36.03',
+ # 'perl-core/ExtUtils-ParseXS-2.22.02-r1',
+ # 'perl-core/Archive-Tar-1.56',
+ # 'app-portage/gentoolkit-0.3.0_rc8-r1',
+ # 'app-portage/layman-1.3.1',
+ # 'app-portage/eix-0.20.1',
+]
+
+
+Exclude = {
+ "packages": {
+ "media-libs/sdl-pango": None,
+ },
+ "anti-packages": {"app-emulation/emul-linux-x86-baselibs": None},
+ "categories": {"app-portage": None, "app-portage/gentoolkit": None},
+ "filenames": {
+ "sys-auth/consolekit-0.4.1": re.compile(r"sys-auth/consolekit-0\.4\.1")
+ },
+}
def get_props(cpvs):
- props = {}
- for cpv in cpvs:
- props[cpv] = PROPS[cpv].copy()
- return props
+ props = {}
+ for cpv in cpvs:
+ props[cpv] = PROPS[cpv].copy()
+ return props
+
class Dbapi:
- """Fake portage dbapi class used to return
- pre-determined test data in place of a live system
-
- @param cp_all: list of cat/pkg's to use for testing
- eg: ['app-portage/gentoolkit', 'app-portage/porthole',...]
- @param cpv_all: list of cat/pkg-ver's to use for testing.
- @param props: dictionary of ebuild properties to use for testing.
- eg: {'cpv': {"SRC_URI": 'http://...', "RESTRICT": restriction},}
- @param cp_list: ?????????
- """
-
- def __init__(self, cp_all=None, cpv_all=None, props=None,
- cp_list=None, name=None):
- self._cp_all = cp_all
- self._cpv_all = cpv_all
- self._props = props
- self._cp_list = cp_list
- self.name = name
- #print(self.name, "DBAPI: cpv_all=")
- #print(self._cpv_all)
- #print(self.name, "DBAPI: props=")
- #print(self._props)
-
- def cp_all(self):
- return self._cp_all[:]
-
- def cp_list(self, package):
- #print(self._cp_list)
- if self._cp_list is None or self._cp_list==[]:
- cplist = []
- for cpv in self._cpv_all:
- parts = portage.catpkgsplit(cpv)
- cp='/'.join(parts[:2])
- if cp == package:
- cplist.append(cpv)
- #print("package = %s, cplist = %s" %(package, cplist))
- return cplist
- else:
- return self._cp_list
-
- def cpv_all(self):
- #print(self.name, type(self._cpv_all), self._cpv_all)
- return self._cpv_all
-
- def cpv_exists(self, cpv):
- return cpv in self._cpv_all
-
- def aux_get(self, cpv, prop_list):
- """only need stubs for ["SRC_URI","RESTRICT"]
- """
- #print("FAKE DBAPI", cpv, prop_list)
- props = []
- for prop in prop_list:
- if cpv in self._props:
- props.append(self._props[cpv][prop])
- else:
- raise KeyError(self.name)
- #print(self.name, "DBAPI", cpv, props)
- return props
+ """Fake portage dbapi class used to return
+ pre-determined test data in place of a live system
+
+ @param cp_all: list of cat/pkg's to use for testing
+ eg: ['app-portage/gentoolkit', 'app-portage/porthole',...]
+ @param cpv_all: list of cat/pkg-ver's to use for testing.
+ @param props: dictionary of ebuild properties to use for testing.
+ eg: {'cpv': {"SRC_URI": 'http://...', "RESTRICT": restriction},}
+ @param cp_list: ?????????
+ """
+
+ def __init__(self, cp_all=None, cpv_all=None, props=None, cp_list=None, name=None):
+ self._cp_all = cp_all
+ self._cpv_all = cpv_all
+ self._props = props
+ self._cp_list = cp_list
+ self.name = name
+ # print(self.name, "DBAPI: cpv_all=")
+ # print(self._cpv_all)
+ # print(self.name, "DBAPI: props=")
+ # print(self._props)
+
+ def cp_all(self):
+ return self._cp_all[:]
+
+ def cp_list(self, package):
+ # print(self._cp_list)
+ if self._cp_list is None or self._cp_list == []:
+ cplist = []
+ for cpv in self._cpv_all:
+ parts = portage.catpkgsplit(cpv)
+ cp = "/".join(parts[:2])
+ if cp == package:
+ cplist.append(cpv)
+ # print("package = %s, cplist = %s" %(package, cplist))
+ return cplist
+ else:
+ return self._cp_list
+
+ def cpv_all(self):
+ # print(self.name, type(self._cpv_all), self._cpv_all)
+ return self._cpv_all
+
+ def cpv_exists(self, cpv):
+ return cpv in self._cpv_all
+
+ def aux_get(self, cpv, prop_list):
+ """only need stubs for ["SRC_URI","RESTRICT"]"""
+ # print("FAKE DBAPI", cpv, prop_list)
+ props = []
+ for prop in prop_list:
+ if cpv in self._props:
+ props.append(self._props[cpv][prop])
+ else:
+ raise KeyError(self.name)
+ # print(self.name, "DBAPI", cpv, props)
+ return props
class OutputSimulator:
- """Simple output accumulator used for testing.
- Simulates eclean.output.OutputControl class """
+ """Simple output accumulator used for testing.
+ Simulates eclean.output.OutputControl class"""
- def __init__(self, callback):
- self.callback = callback
+ def __init__(self, callback):
+ self.callback = callback
- def set_data(self, data):
- """sets the data for the progress_controller to return
- for the test being performed"""
- self.data = data
+ def set_data(self, data):
+ """sets the data for the progress_controller to return
+ for the test being performed"""
+ self.data = data
- def einfo(self, message=""):
- self.callback('einfo', message)
+ def einfo(self, message=""):
+ self.callback("einfo", message)
- def eprompt(self, message):
- self.callback('eprompt', message)
+ def eprompt(self, message):
+ self.callback("eprompt", message)
- def prettySize(self, size, justify=False, color=None):
- self.callback('prettySize', size)
+ def prettySize(self, size, justify=False, color=None):
+ self.callback("prettySize", size)
- def yesNoAllPrompt(self, message="Dummy"):
- self.callback('yesNoAllPrompt', message)
+ def yesNoAllPrompt(self, message="Dummy"):
+ self.callback("yesNoAllPrompt", message)
- def progress_controller(self, size, key, clean_list, file_type):
- self.callback('progress_controller', self.data)
- return self.data
+ def progress_controller(self, size, key, clean_list, file_type):
+ self.callback("progress_controller", self.data)
+ return self.data
- def total(self, mode, size, num_files, verb, action):
- pass
+ def total(self, mode, size, num_files, verb, action):
+ pass
- def list_pkgs(self, pkgs):
- self.callback('list_pkgs', pkgs)
+ def list_pkgs(self, pkgs):
+ self.callback("list_pkgs", pkgs)
class TestDisfiles:
-
- def setUp(self):
- # create the dist dir
- self.tmpdir = mkdtemp()
- #print("New tmpdir =", self.tmpdir)
- os.chmod(self.tmpdir, dir_mode)
- self.workdir = os.path.join(self.tmpdir, 'distfiles')
- dir = os.path.dirname(os.path.abspath(__file__))
- file = os.path.join(dir,"testdistfiles.tar.gz")
- command = "tar -xpf %s -C %s" %(file, self.tmpdir)
- subprocess.call(command, shell=True)
- # create a symlink as part of the test files
- #print()
- self.target_symlink = "symlink-1.0.0.tar.gz"
- os.symlink(file, os.path.join(self.workdir, self.target_symlink))
- self.files = FILES[:]
- self.files.append(self.target_symlink)
- self.test_filepaths = []
- for file in self.files:
- self.test_filepaths.append(os.path.join(self.workdir, file))
-
- def tearDown(self):
- for file in self.test_filepaths:
- os.unlink(file)
- #print("deleting workdir =", self.workdir)
- os.rmdir(self.workdir)
- #print("deleting tmpdir =", self.tmpdir)
- os.rmdir(self.tmpdir)
-
-
+ def setUp(self):
+ # create the dist dir
+ self.tmpdir = mkdtemp()
+ # print("New tmpdir =", self.tmpdir)
+ os.chmod(self.tmpdir, dir_mode)
+ self.workdir = os.path.join(self.tmpdir, "distfiles")
+ dir = os.path.dirname(os.path.abspath(__file__))
+ file = os.path.join(dir, "testdistfiles.tar.gz")
+ command = "tar -xpf %s -C %s" % (file, self.tmpdir)
+ subprocess.call(command, shell=True)
+ # create a symlink as part of the test files
+ # print()
+ self.target_symlink = "symlink-1.0.0.tar.gz"
+ os.symlink(file, os.path.join(self.workdir, self.target_symlink))
+ self.files = FILES[:]
+ self.files.append(self.target_symlink)
+ self.test_filepaths = []
+ for file in self.files:
+ self.test_filepaths.append(os.path.join(self.workdir, file))
+
+ def tearDown(self):
+ for file in self.test_filepaths:
+ os.unlink(file)
+ # print("deleting workdir =", self.workdir)
+ os.rmdir(self.workdir)
+ # print("deleting tmpdir =", self.tmpdir)
+ os.rmdir(self.tmpdir)
diff --git a/pym/gentoolkit/test/eclean/test_clean.py b/pym/gentoolkit/test/eclean/test_clean.py
index 2f50e27..a2519d2 100755
--- a/pym/gentoolkit/test/eclean/test_clean.py
+++ b/pym/gentoolkit/test/eclean/test_clean.py
@@ -4,7 +4,7 @@
# Copyright 2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
-__version__= "0.0.1"
+__version__ = "0.0.1"
__author__ = "Brian Dolbec"
__email__ = "brian.dolbec@gmail.com"
@@ -87,7 +87,6 @@ __email__ = "brian.dolbec@gmail.com"
# data = controller.gathered_data
-
# def useage():
# """output run options"""
# print("Useage: test_clean [OPTONS] path=test-dir")
@@ -125,7 +124,6 @@ __email__ = "brian.dolbec@gmail.com"
# sys.exit(1)
-
# def main(cmdline=False):
# """parse options and run the tests"""
@@ -141,5 +139,3 @@ __email__ = "brian.dolbec@gmail.com"
# print("Aborted.")
# sys.exit(130)
# sys.exit(0)
-
-
diff --git a/pym/gentoolkit/test/eclean/test_search.py b/pym/gentoolkit/test/eclean/test_search.py
index 5a20e38..714fbb5 100755
--- a/pym/gentoolkit/test/eclean/test_search.py
+++ b/pym/gentoolkit/test/eclean/test_search.py
@@ -12,8 +12,18 @@ import re
import os
from gentoolkit.test.eclean.distsupport import (
- FILES, TestDisfiles, OutputSimulator, Dbapi, CPVS, CPVS2, CPVS3, PROPS,
- PKGS, CLEAN_ME, get_props)
+ FILES,
+ TestDisfiles,
+ OutputSimulator,
+ Dbapi,
+ CPVS,
+ CPVS2,
+ CPVS3,
+ PROPS,
+ PKGS,
+ CLEAN_ME,
+ get_props,
+)
import gentoolkit.eclean.search as search
from gentoolkit.eclean.search import DistfilesSearch
from gentoolkit.eclean.exclude import parseExcludeFile
@@ -22,602 +32,653 @@ from gentoolkit.eclean.exclude import parseExcludeFile
class DistLimits(DistfilesSearch):
- """subclass the DistfilesSearch class in order to override a number of
- functions to isolate & test"""
+ """subclass the DistfilesSearch class in order to override a number of
+ functions to isolate & test"""
- def __init__(self,
- output=lambda x: None,
- portdb=None,
- vardb=None,
- ):
- DistfilesSearch.__init__(self, output, portdb, vardb)
- self.data = None
+ def __init__(
+ self,
+ output=lambda x: None,
+ portdb=None,
+ vardb=None,
+ ):
+ DistfilesSearch.__init__(self, output, portdb, vardb)
+ self.data = None
- def set_data(self, data):
- """sets the data for the functions to return for
- the test being performed"""
- self.data = data
+ def set_data(self, data):
+ """sets the data for the functions to return for
+ the test being performed"""
+ self.data = data
class TestCheckLimits(unittest.TestCase):
- """Test the eclean.search.DistfilesSearch._check_limits() group.
-
- it will test [ _get_default_checks(), _check_limits(),
- _isreg_check_(), _size_check_(), _time_check_(), _filenames_check_()]
- """
-
- test_excludes = {
- 'blank': {},
- 'filenames': {
- 'filenames': {'help2man-1.37.1.tar.gz': re.compile(r'help2man-1\.37\.1\.tar\.gz')}
- }
- }
-
- def setUp(self):
- self.testdata = [
- # test is_reg_limit alone, will give a base clean_me
- { 'test': 'is_reg_limit',
- 'params': (0, 0, self.test_excludes['blank']),
- 'results': FILES[:],
- 'output': [" - skipping size limit check",
- " - skipping time limit check",
- " - skipping exclude filenames check"
- ]
- },
- # test size_limit trip
- { 'test': 'size_limit',
- 'params': (1024000, 0, self.test_excludes['blank']),
- 'results': FILES[:3] + FILES[4:],
- 'output': [
- " - skipping time limit check",
- " - skipping exclude filenames check"
- ]
- },
- # test time_limit trip
- { 'test': 'time_limit',
- 'params': (0,1112671872, self.test_excludes['blank']),
- 'results': [FILES[4]], # + FILES[5:],
- 'output': [" - skipping size limit check",
- " - skipping exclude filenames check"
- ]
- },
- # test filenames_limit trip
- { 'test': 'filenames_limit',
- 'params': (0, 0, self.test_excludes['filenames']),
- 'results': FILES[:1] + FILES[2:],
- 'output': [" - skipping size limit check",
- " - skipping time limit check",
- ]
- }
- ]
-
- self.testwork = TestDisfiles()
- self.testwork.setUp()
- self.workdir = self.testwork.workdir
- self.target_class = DistLimits() #DistCheckLimits()
- self.output = OutputSimulator(self.callback)
- self.target_class.output = self.output
- self.callback_data = []
- self.test_index = 0
-
- def tearDown(self):
- self.testwork.tearDown()
- #pass
-
- def get_test(self, num):
- return self.testdata[num]
-
- def callback(self, id, data):
- self.callback_data.append(data)
-
- def set_limits(self, test):
- limit = {}
- #set is_reg always to testdata[0]
- t1 = self.testdata[0]
- limit[t1['test']] = {}
- name = test['test']
- limit[name] = {}
- limits = test['limits']
- for i in range(6):
- file = self.testwork.files[i]
- limits = test['limits']
- limit[t1['test']][file] = t1['limits'][i]
- if name != t1['test']:
- limit[name][file] = limits[i]
- return limit
-
-
- def test_check_limits(self):
- """Testing DistfilesSearch._check_limits()"""
- # pass in output=self.output.einfo
- self.target_class.output = self.output.einfo
- run_callbacks = []
- run_results = []
- print()
- # run the tests
- for i in range(4):
- clean_me = {}
- test = self.get_test(i)
- #print("test =", test['test'])
- if not test:
- print("Error getting test data for index:", i)
- #self.target_class.set_data(self.set_limits(test))
- size_chk, time_chk, exclude = test["params"]
- checks = self.target_class._get_default_checks(size_chk, time_chk, exclude, False)
- clean_me = self.target_class._check_limits(self.workdir, checks, clean_me)
- results = sorted(clean_me)
- run_results.append(results)
- self.callback_data.sort()
- run_callbacks.append(self.callback_data)
- self.callback_data = []
- results = None
-
- # check results
- for i in range(4):
- test = self.get_test(i)
- print("test =", test['test'])
- if not test:
- print("Error getting test data for index:", i)
- test['results'].sort()
- #print("actual=", run_results[i])
- #print("should-be=", test['results'])
- self.assertEqual(run_results[i], test["results"],
- "/ntest_check_limits, test# %d, test=%s, diff=%s"
- %(i, test['test'], str(set(run_results[i]).difference(test['results'])))
- )
- test['output'].sort()
- self.assertEqual(run_callbacks[i], test['output'])
+ """Test the eclean.search.DistfilesSearch._check_limits() group.
+
+ it will test [ _get_default_checks(), _check_limits(),
+ _isreg_check_(), _size_check_(), _time_check_(), _filenames_check_()]
+ """
+
+ test_excludes = {
+ "blank": {},
+ "filenames": {
+ "filenames": {
+ "help2man-1.37.1.tar.gz": re.compile(r"help2man-1\.37\.1\.tar\.gz")
+ }
+ },
+ }
+
+ def setUp(self):
+ self.testdata = [
+ # test is_reg_limit alone, will give a base clean_me
+ {
+ "test": "is_reg_limit",
+ "params": (0, 0, self.test_excludes["blank"]),
+ "results": FILES[:],
+ "output": [
+ " - skipping size limit check",
+ " - skipping time limit check",
+ " - skipping exclude filenames check",
+ ],
+ },
+ # test size_limit trip
+ {
+ "test": "size_limit",
+ "params": (1024000, 0, self.test_excludes["blank"]),
+ "results": FILES[:3] + FILES[4:],
+ "output": [
+ " - skipping time limit check",
+ " - skipping exclude filenames check",
+ ],
+ },
+ # test time_limit trip
+ {
+ "test": "time_limit",
+ "params": (0, 1112671872, self.test_excludes["blank"]),
+ "results": [FILES[4]], # + FILES[5:],
+ "output": [
+ " - skipping size limit check",
+ " - skipping exclude filenames check",
+ ],
+ },
+ # test filenames_limit trip
+ {
+ "test": "filenames_limit",
+ "params": (0, 0, self.test_excludes["filenames"]),
+ "results": FILES[:1] + FILES[2:],
+ "output": [
+ " - skipping size limit check",
+ " - skipping time limit check",
+ ],
+ },
+ ]
+
+ self.testwork = TestDisfiles()
+ self.testwork.setUp()
+ self.workdir = self.testwork.workdir
+ self.target_class = DistLimits() # DistCheckLimits()
+ self.output = OutputSimulator(self.callback)
+ self.target_class.output = self.output
+ self.callback_data = []
+ self.test_index = 0
+
+ def tearDown(self):
+ self.testwork.tearDown()
+ # pass
+
+ def get_test(self, num):
+ return self.testdata[num]
+
+ def callback(self, id, data):
+ self.callback_data.append(data)
+
+ def set_limits(self, test):
+ limit = {}
+ # set is_reg always to testdata[0]
+ t1 = self.testdata[0]
+ limit[t1["test"]] = {}
+ name = test["test"]
+ limit[name] = {}
+ limits = test["limits"]
+ for i in range(6):
+ file = self.testwork.files[i]
+ limits = test["limits"]
+ limit[t1["test"]][file] = t1["limits"][i]
+ if name != t1["test"]:
+ limit[name][file] = limits[i]
+ return limit
+
+ def test_check_limits(self):
+ """Testing DistfilesSearch._check_limits()"""
+ # pass in output=self.output.einfo
+ self.target_class.output = self.output.einfo
+ run_callbacks = []
+ run_results = []
+ print()
+ # run the tests
+ for i in range(4):
+ clean_me = {}
+ test = self.get_test(i)
+ # print("test =", test['test'])
+ if not test:
+ print("Error getting test data for index:", i)
+ # self.target_class.set_data(self.set_limits(test))
+ size_chk, time_chk, exclude = test["params"]
+ checks = self.target_class._get_default_checks(
+ size_chk, time_chk, exclude, False
+ )
+ clean_me = self.target_class._check_limits(self.workdir, checks, clean_me)
+ results = sorted(clean_me)
+ run_results.append(results)
+ self.callback_data.sort()
+ run_callbacks.append(self.callback_data)
+ self.callback_data = []
+ results = None
+
+ # check results
+ for i in range(4):
+ test = self.get_test(i)
+ print("test =", test["test"])
+ if not test:
+ print("Error getting test data for index:", i)
+ test["results"].sort()
+ # print("actual=", run_results[i])
+ # print("should-be=", test['results'])
+ self.assertEqual(
+ run_results[i],
+ test["results"],
+ "/ntest_check_limits, test# %d, test=%s, diff=%s"
+ % (
+ i,
+ test["test"],
+ str(set(run_results[i]).difference(test["results"])),
+ ),
+ )
+ test["output"].sort()
+ self.assertEqual(run_callbacks[i], test["output"])
class TestFetchRestricted(unittest.TestCase):
- """Tests eclean.search.DistfilesSearch._fetch_restricted and _unrestricted
- functions
- """
-
- def setUp(self):
- self.vardb = Dbapi(cp_all=[], cpv_all=CPVS,
- props=PROPS, cp_list=[], name="FAKE VARDB")
- self.portdb = Dbapi(cp_all=[], cpv_all=CPVS[:4],
- props=get_props(CPVS[:4]), cp_list=[], name="FAKE PORTDB")
- # set a fetch restricted pkg
- self.portdb._props[CPVS[0]]["RESTRICT"] = 'fetch'
- self.callback_data = []
- self.output = self.output = OutputSimulator(self.callback)
- self.target_class = DistfilesSearch(self.output.einfo, self.portdb, self.vardb)
- self.target_class.portdb = self.portdb
- self.target_class.portdb = self.portdb
- self.results = {}
- self.testdata = {
- 'fetch_restricted1':{
- 'deprecated':
- {'app-emulation/emul-linux-x86-baselibs-20100220': 'mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz'
- },
- 'pkgs':
- {'sys-auth/consolekit-0.4.1': 'http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2'
- },
- 'output': [
- '!!! "Deprecation Warning: Installed package: app-emulation/emul-linux-x86-baselibs-20100220\n\tIs no longer in the tree or an installed overlay\n'
- ]
- },
- 'fetch_restricted2':{
- 'deprecated':
- {'app-emulation/emul-linux-x86-baselibs-20100220': 'mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz'
- },
- 'pkgs':
- {'sys-auth/consolekit-0.4.1': 'http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2'
- },
- 'output': [
- '!!! "Deprecation Warning: Installed package: app-emulation/emul-linux-x86-baselibs-20100220\n\tIs no longer in the tree or an installed overlay\n',
- ' - Key Error looking up: app-portage/deprecated-pkg-1.0.0'
- ]
- },
- 'unrestricted1':{
- 'deprecated':{
- 'app-emulation/emul-linux-x86-baselibs-20100220': 'mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz'
- },
- 'pkgs': {
- 'sys-apps/devicekit-power-014': 'http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz',
- 'sys-apps/help2man-1.37.1': 'mirror://gnu/help2man/help2man-1.37.1.tar.gz',
- 'sys-auth/consolekit-0.4.1': 'http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2',
- 'app-emulation/emul-linux-x86-baselibs-20100220': 'mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz',
- 'media-libs/sdl-pango-0.1.2': 'mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch'
- },
- 'output': [
- '!!! "Deprecation Warning: Installed package: app-emulation/emul-linux-x86-baselibs-20100220\n\tIs no longer in the tree or an installed overlay\n',
- ]
- },
- 'unrestricted2':{
- 'deprecated':{
- 'app-emulation/emul-linux-x86-baselibs-20100220': 'mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz'
- },
- 'pkgs': {
- 'sys-apps/devicekit-power-014': 'http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz',
- 'sys-apps/help2man-1.37.1': 'mirror://gnu/help2man/help2man-1.37.1.tar.gz',
- 'sys-auth/consolekit-0.4.1': 'http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2',
- 'app-emulation/emul-linux-x86-baselibs-20100220': 'mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz',
- 'media-libs/sdl-pango-0.1.2': 'mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch'
- },
- 'output': [
- '!!! "Deprecation Warning: Installed package: app-emulation/emul-linux-x86-baselibs-20100220\n\tIs no longer in the tree or an installed overlay\n',
- ' - Key Error looking up: app-portage/deprecated-pkg-1.0.0'
- ]
- }
- }
-
-
- def callback(self, id, data):
- self.callback_data.append(data)
-
-
- def test__fetch_restricted(self):
- self.results = {}
- pkgs, deprecated = self.target_class._fetch_restricted(None, CPVS)
- self.record_results('fetch_restricted1', pkgs, deprecated)
-
- self.callback_data = []
- cpvs = CPVS[:]
- cpvs.append('app-portage/deprecated-pkg-1.0.0')
- pkgs, deprecated = self.target_class._fetch_restricted(None, cpvs)
- self.record_results('fetch_restricted2', pkgs, deprecated)
- self.check_results("test_fetch_restricted")
-
-
- def test_unrestricted(self):
- self.results = {}
- pkgs, deprecated = self.target_class._unrestricted(None, CPVS)
- self.record_results('unrestricted1', pkgs, deprecated)
- self.callback_data = []
- cpvs = CPVS[:]
- cpvs.append('app-portage/deprecated-pkg-1.0.0')
- pkgs, deprecated = self.target_class._unrestricted(None, cpvs)
- self.record_results('unrestricted2', pkgs, deprecated)
- self.check_results("test_unrestricted")
-
-
- def check_results(self, test_name):
- print("\nChecking results for %s,............" %test_name)
- for key in sorted(self.results):
- testdata = self.testdata[key]
- results = self.results[key]
- for item in sorted(testdata):
- if sorted(results[item]) == sorted(testdata[item]):
- test = "OK"
- else:
- test = "FAILED"
- print("comparing %s, %s" %(key, item), test)
- self.assertEqual(sorted(testdata[item]), sorted(results[item]),
- "\n%s: %s %s data does not match\nresult=" %(test_name, key, item) +\
- str(results[item]) + "\ntestdata=" + str(testdata[item]))
-
-
- def record_results(self, test, pkgs, deprecated):
- self.results[test] = {'pkgs': pkgs,
- 'deprecated': deprecated,
- 'output': self.callback_data
- }
-
-
- def tearDown(self):
- del self.portdb, self.vardb
+ """Tests eclean.search.DistfilesSearch._fetch_restricted and _unrestricted
+ functions
+ """
+
+ def setUp(self):
+ self.vardb = Dbapi(
+ cp_all=[], cpv_all=CPVS, props=PROPS, cp_list=[], name="FAKE VARDB"
+ )
+ self.portdb = Dbapi(
+ cp_all=[],
+ cpv_all=CPVS[:4],
+ props=get_props(CPVS[:4]),
+ cp_list=[],
+ name="FAKE PORTDB",
+ )
+ # set a fetch restricted pkg
+ self.portdb._props[CPVS[0]]["RESTRICT"] = "fetch"
+ self.callback_data = []
+ self.output = self.output = OutputSimulator(self.callback)
+ self.target_class = DistfilesSearch(self.output.einfo, self.portdb, self.vardb)
+ self.target_class.portdb = self.portdb
+ self.target_class.portdb = self.portdb
+ self.results = {}
+ self.testdata = {
+ "fetch_restricted1": {
+ "deprecated": {
+ "app-emulation/emul-linux-x86-baselibs-20100220": "mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz"
+ },
+ "pkgs": {
+ "sys-auth/consolekit-0.4.1": "http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2"
+ },
+ "output": [
+ '!!! "Deprecation Warning: Installed package: app-emulation/emul-linux-x86-baselibs-20100220\n\tIs no longer in the tree or an installed overlay\n'
+ ],
+ },
+ "fetch_restricted2": {
+ "deprecated": {
+ "app-emulation/emul-linux-x86-baselibs-20100220": "mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz"
+ },
+ "pkgs": {
+ "sys-auth/consolekit-0.4.1": "http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2"
+ },
+ "output": [
+ '!!! "Deprecation Warning: Installed package: app-emulation/emul-linux-x86-baselibs-20100220\n\tIs no longer in the tree or an installed overlay\n',
+ " - Key Error looking up: app-portage/deprecated-pkg-1.0.0",
+ ],
+ },
+ "unrestricted1": {
+ "deprecated": {
+ "app-emulation/emul-linux-x86-baselibs-20100220": "mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz"
+ },
+ "pkgs": {
+ "sys-apps/devicekit-power-014": "http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz",
+ "sys-apps/help2man-1.37.1": "mirror://gnu/help2man/help2man-1.37.1.tar.gz",
+ "sys-auth/consolekit-0.4.1": "http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2",
+ "app-emulation/emul-linux-x86-baselibs-20100220": "mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz",
+ "media-libs/sdl-pango-0.1.2": "mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch",
+ },
+ "output": [
+ '!!! "Deprecation Warning: Installed package: app-emulation/emul-linux-x86-baselibs-20100220\n\tIs no longer in the tree or an installed overlay\n',
+ ],
+ },
+ "unrestricted2": {
+ "deprecated": {
+ "app-emulation/emul-linux-x86-baselibs-20100220": "mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz"
+ },
+ "pkgs": {
+ "sys-apps/devicekit-power-014": "http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz",
+ "sys-apps/help2man-1.37.1": "mirror://gnu/help2man/help2man-1.37.1.tar.gz",
+ "sys-auth/consolekit-0.4.1": "http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2",
+ "app-emulation/emul-linux-x86-baselibs-20100220": "mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz",
+ "media-libs/sdl-pango-0.1.2": "mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch",
+ },
+ "output": [
+ '!!! "Deprecation Warning: Installed package: app-emulation/emul-linux-x86-baselibs-20100220\n\tIs no longer in the tree or an installed overlay\n',
+ " - Key Error looking up: app-portage/deprecated-pkg-1.0.0",
+ ],
+ },
+ }
+
+ def callback(self, id, data):
+ self.callback_data.append(data)
+
+ def test__fetch_restricted(self):
+ self.results = {}
+ pkgs, deprecated = self.target_class._fetch_restricted(None, CPVS)
+ self.record_results("fetch_restricted1", pkgs, deprecated)
+
+ self.callback_data = []
+ cpvs = CPVS[:]
+ cpvs.append("app-portage/deprecated-pkg-1.0.0")
+ pkgs, deprecated = self.target_class._fetch_restricted(None, cpvs)
+ self.record_results("fetch_restricted2", pkgs, deprecated)
+ self.check_results("test_fetch_restricted")
+
+ def test_unrestricted(self):
+ self.results = {}
+ pkgs, deprecated = self.target_class._unrestricted(None, CPVS)
+ self.record_results("unrestricted1", pkgs, deprecated)
+ self.callback_data = []
+ cpvs = CPVS[:]
+ cpvs.append("app-portage/deprecated-pkg-1.0.0")
+ pkgs, deprecated = self.target_class._unrestricted(None, cpvs)
+ self.record_results("unrestricted2", pkgs, deprecated)
+ self.check_results("test_unrestricted")
+
+ def check_results(self, test_name):
+ print("\nChecking results for %s,............" % test_name)
+ for key in sorted(self.results):
+ testdata = self.testdata[key]
+ results = self.results[key]
+ for item in sorted(testdata):
+ if sorted(results[item]) == sorted(testdata[item]):
+ test = "OK"
+ else:
+ test = "FAILED"
+ print("comparing %s, %s" % (key, item), test)
+ self.assertEqual(
+ sorted(testdata[item]),
+ sorted(results[item]),
+ "\n%s: %s %s data does not match\nresult=" % (test_name, key, item)
+ + str(results[item])
+ + "\ntestdata="
+ + str(testdata[item]),
+ )
+
+ def record_results(self, test, pkgs, deprecated):
+ self.results[test] = {
+ "pkgs": pkgs,
+ "deprecated": deprecated,
+ "output": self.callback_data,
+ }
+
+ def tearDown(self):
+ del self.portdb, self.vardb
class TestNonDestructive(unittest.TestCase):
- """Tests eclean.search.DistfilesSearch._non_destructive and _destructive
- functions, with addition useage tests of fetch_restricted() and _unrestricted()
- """
-
- def setUp(self):
- self.vardb = Dbapi(cp_all=[], cpv_all=CPVS,
- props=PROPS, cp_list=[], name="FAKE VARDB")
- self.portdb = Dbapi(cp_all=[], cpv_all=CPVS[:4],
- props=get_props(CPVS[:4]), cp_list=[], name="FAKE PORTDB")
- print(self.portdb)
- # set a fetch restricted pkg
- self.portdb._props[CPVS[0]]["RESTRICT"] = 'fetch'
- self.callback_data = []
- self.output = OutputSimulator(self.callback)
- self.target_class = DistfilesSearch(self.output.einfo, self.portdb, self.vardb)
- search.exclDictExpand = self.exclDictExpand
- self.exclude = parseExcludeFile(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'distfiles.exclude'), self.output.einfo)
- #print(self.callback_data)
- #print(self.exclude)
- self.callback_data = []
- self.results = {}
- self.testdata = {
- 'non_destructive1':{
- 'deprecated':
- {'app-emulation/emul-linux-x86-baselibs-20100220': 'mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz'
- },
- 'pkgs': {
- 'sys-auth/consolekit-0.4.1': 'http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2',
- 'sys-apps/help2man-1.37.1': 'mirror://gnu/help2man/help2man-1.37.1.tar.gz',
- 'sys-apps/devicekit-power-014': 'http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz',
- 'app-emulation/emul-linux-x86-baselibs-20100220': 'mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz',
- 'media-libs/sdl-pango-0.1.2': 'mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch'
- },
- 'output': [
- ' - getting complete ebuild list',
- ' - getting source file names for 5 ebuilds',
- '!!! "Deprecation Warning: Installed package: app-emulation/emul-linux-x86-baselibs-20100220\n\tIs no longer in the tree or an installed overlay\n'
- ]
- },
- 'non_destructive2':{
- 'deprecated': {
- },
- 'pkgs': {
- 'sys-apps/devicekit-power-014': 'http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz',
- 'sys-auth/consolekit-0.4.1': 'http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2',
- 'media-libs/sdl-pango-0.1.2': 'mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch'
- },
- 'output': [
- ' - getting complete ebuild list',
- ' - getting source file names for 3 installed ebuilds',
- ' - getting fetch-restricted source file names for 2 remaining ebuilds'
- ]
- },
- 'non_destructive3':{
- 'deprecated':{
- },
- 'pkgs': {
- 'sys-apps/devicekit-power-014': 'http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz',
- 'sys-auth/consolekit-0.4.1': 'http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2',
- 'app-emulation/emul-linux-x86-baselibs-20100220': 'mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz',
- },
- 'output': [
- ' - getting complete ebuild list',
- ' - getting source file names for 2 installed ebuilds',
- ' - getting fetch-restricted source file names for 3 remaining ebuilds'
- ]
- },
- 'destructive1':{
- 'deprecated':{
- 'app-emulation/emul-linux-x86-baselibs-20100220': 'mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz'
- },
- 'pkgs': {
- 'sys-apps/devicekit-power-014': 'http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz',
- 'sys-apps/help2man-1.37.1': 'mirror://gnu/help2man/help2man-1.37.1.tar.gz',
- 'sys-auth/consolekit-0.4.1': 'http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2',
- 'app-emulation/emul-linux-x86-baselibs-20100220': 'mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz',
- 'media-libs/sdl-pango-0.1.2': 'mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch'
- },
- 'output': [
- ' - processing 5 installed ebuilds', ' - processing excluded',
- ' - (5 of 0 total) additional excluded packages to get source filenames for',
- '!!! "Deprecation Warning: Installed package: app-emulation/emul-linux-x86-baselibs-20100220\n\tIs no longer in the tree or an installed overlay\n'
- ]
- },
- 'destructive2':{
- 'deprecated':{
- },
- 'pkgs': {
- },
- 'output': [
- ' - processing 0 installed packages',
- ' - processing excluded', ' - (0 of 0 total) additional excluded packages to get source filenames for'
- ]
- },
- 'destructive3':{
- 'deprecated':{
- },
- 'pkgs': {
- 'app-portage/gentoolkit-0.3.0_rc8-r1': 'mirror://gentoo/gentoolkit-0.3.0_rc8.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc8.tar.gz',
- 'sys-apps/devicekit-power-014': 'http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz',
- 'app-portage/gentoolkit-0.3.0_rc8': 'mirror://gentoo/gentoolkit-0.3.0_rc8.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc8.tar.gz',
- 'app-portage/gentoolkit-0.2.4.6-r1': 'mirror://gentoo/gentoolkit-0.2.4.6.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.6.tar.gz',
- 'app-portage/gentoolkit-0.3.0_rc7': 'mirror://gentoo/gentoolkit-0.3.0_rc7.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc7.tar.gz',
- 'app-portage/gentoolkit-0.2.4.6': 'mirror://gentoo/gentoolkit-0.2.4.6.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.6.tar.gz',
- 'app-portage/eix-0.19.2': 'mirror://sourceforge/eix/eix-0.19.2.tar.xz',
- 'app-portage/gentoolkit-0.2.4.5': 'mirror://gentoo/gentoolkit-0.2.4.5.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.5.tar.gz',
- 'app-portage/gentoolkit-0.3.0_rc9': 'mirror://gentoo/gentoolkit-0.3.0_rc9.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc9.tar.gz',
- 'app-portage/eix-0.20.1': 'mirror://sourceforge/eix/eix-0.20.1.tar.xz',
- 'app-portage/eix-0.20.2': 'mirror://berlios/eix/eix-0.20.2.tar.xz'
- },
- 'output': [
- ' - processing excluded',
- ' - (10 of 10 total) additional excluded packages to get source filenames for'
- ]
- },
- 'destructive4':{
- 'deprecated':{
- },
- 'pkgs': {
- 'sys-auth/consolekit-0.4.1':
- 'http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2',
- 'sys-apps/devicekit-power-014':
- 'http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz',
- 'media-libs/sdl-pango-0.1.2':
- 'mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch'
- },
- 'output': [
- ' - processing 3 installed ebuilds',
- ' - processing excluded',
- ' - (3 of 0 total) additional excluded packages to get source filenames for'
- ]
- },
- 'destructive5':{
- 'deprecated':{
- },
- 'pkgs': {
- 'x11-base/xorg-server-1.7.5': 'http://xorg.freedesktop.org/releases/individual/xserver/xorg-server-1.7.5.tar.bz2',
- 'app-portage/gentoolkit-0.3.0_rc8-r1': 'mirror://gentoo/gentoolkit-0.3.0_rc8.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc8.tar.gz',
- 'sys-apps/devicekit-power-014': 'http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz',
- 'x11-misc/util-macros-1.6.0': 'http://xorg.freedesktop.org/releases/individual/util/util-macros-1.6.0.tar.bz2',
- 'app-portage/eix-0.19.2': 'mirror://sourceforge/eix/eix-0.19.2.tar.xz',
- 'app-portage/gentoolkit-0.3.0_rc8': 'mirror://gentoo/gentoolkit-0.3.0_rc8.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc8.tar.gz',
- 'app-portage/gentoolkit-0.2.4.6-r1': 'mirror://gentoo/gentoolkit-0.2.4.6.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.6.tar.gz',
- 'app-portage/gentoolkit-0.3.0_rc7': 'mirror://gentoo/gentoolkit-0.3.0_rc7.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc7.tar.gz',
- 'sys-auth/consolekit-0.4.1': 'http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2',
- 'app-portage/gentoolkit-0.2.4.6': 'mirror://gentoo/gentoolkit-0.2.4.6.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.6.tar.gz',
- 'media-libs/sdl-pango-0.1.2': 'mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch',
- 'x11-libs/pixman-0.16.4': 'http://xorg.freedesktop.org/releases/individual/lib/pixman-0.16.4.tar.bz2',
- 'app-portage/gentoolkit-0.2.4.5': 'mirror://gentoo/gentoolkit-0.2.4.5.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.5.tar.gz',
- 'app-portage/gentoolkit-0.3.0_rc9': 'mirror://gentoo/gentoolkit-0.3.0_rc9.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc9.tar.gz',
- 'app-portage/eix-0.20.1': 'mirror://sourceforge/eix/eix-0.20.1.tar.xz',
- 'app-portage/eix-0.20.2': 'mirror://berlios/eix/eix-0.20.2.tar.xz'
- },
- 'output': [
- ' - processing 6 installed ebuilds',
- ' - processing excluded',
- ' - (16 of 10 total) additional excluded packages to get source filenames for'
- ]
- }
- }
-
-
- def callback(self, id, data):
- self.callback_data.append(data)
-
-
- def exclDictExpand(self, exclude):
- #print("Using Fake Testing exclDictExpand()")
- return [
- #'app-portage/layman',
- 'app-portage/eix',
- 'app-portage/gentoolkit',
- #app-portage/portage-utils',
- ]
-
-
- def test_non_destructive(self):
- self.results = {}
- pkgs, deprecated = self.target_class._non_destructive(destructive=False,
- fetch_restricted=False, pkgs_=None)
- self.record_results('non_destructive1', pkgs, deprecated)
-
- pkgs = None
- deprecated = None
- self.callback_data = []
- self.vardb._cpv_all=CPVS[:3]
- self.vardb._props=get_props(CPVS[:3])
- self.portdb._cpv_all=CPVS[:]
- self.portdb._props=get_props(CPVS)
- self.target_class.installed_cpvs = None
- pkgs, deprecated = self.target_class._non_destructive(destructive=True,
- fetch_restricted=True, pkgs_=None)
- self.record_results('non_destructive2', pkgs, deprecated)
-
- pkgs = None
- deprecated = None
- self.callback_data = []
- self.vardb._cpv_all=CPVS[:2]
- self.vardb._props=get_props(CPVS[:2])
- self.portdb._cpv_all=CPVS[:]
- self.portdb._props=get_props(CPVS)
- # set a fetch restricted pkg
- self.portdb._props[CPVS[4]]["RESTRICT"] = 'fetch'
- pkgs = {'sys-apps/devicekit-power-014': 'http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz'}
- pkgs, deprecated = self.target_class._non_destructive(destructive=True,
- fetch_restricted=True, pkgs_=pkgs)
- self.record_results('non_destructive3', pkgs, deprecated)
- self.check_results("test_non_destructive")
-
-
- def check_results(self, test_name):
- print("\nChecking results for %s,............" %test_name)
- for key in sorted(self.results):
- testdata = self.testdata[key]
- results = self.results[key]
- for item in sorted(testdata):
- if sorted(results[item]) == sorted(testdata[item]):
- test = "OK"
- else:
- test = "FAILED"
- print("comparing %s, %s..." %(key, item), test)
- if test == "FAILED":
- print("", sorted(results[item]), "\n", sorted(testdata[item]))
- self.assertEqual(sorted(testdata[item]), sorted(results[item]),
- "\n%s: %s, %s data does not match\n"
- %(test_name, key, item) + \
- "result=" + str(results[item]) + "\ntestdata=" + str(testdata[item])
- )
-
-
- def record_results(self, test, pkgs, deprecated):
- self.results[test] = {'pkgs': pkgs,
- 'deprecated': deprecated,
- 'output': self.callback_data
- }
-
- def test_destructive(self):
- self.results = {}
- pkgs, deprecated = self.target_class._destructive(package_names=False,
- exclude={}, pkgs_=None, installed_included=False )
- self.record_results('destructive1', pkgs, deprecated)
-
- self.callback_data = []
- self.vardb._cpv_all=CPVS[:3]
- self.vardb._props=get_props(CPVS[:3])
- self.portdb._cpv_all=CPVS[:]
- self.portdb._props=get_props(CPVS)
- pkgs, deprecated = self.target_class._destructive(package_names=True,
- exclude={}, pkgs_=None, installed_included=False )
- self.record_results('destructive2', pkgs, deprecated)
-
- self.callback_data = []
- cpvs = CPVS[2:4]
- cpvs.extend(CPVS3)
- self.vardb._cpv_all=sorted(cpvs)
- self.vardb._props= PROPS.update(get_props(CPVS3))
- self.portdb._cpv_all=sorted(CPVS + CPVS2)
- self.portdb._props=get_props(CPVS+CPVS2)
- # set a fetch restricted pkg
- self.portdb._props[CPVS[4]]["RESTRICT"] = 'fetch'
- pkgs = {'sys-apps/devicekit-power-014': 'http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz'}
- pkgs, deprecated = self.target_class._destructive(package_names=True,
- exclude={}, pkgs_=pkgs, installed_included=True )
- self.record_results('destructive3', pkgs, deprecated)
-
- self.callback_data = []
- self.vardb._cpv_all=CPVS[:3]
- self.vardb._props=get_props(CPVS[:3])
- self.portdb._cpv_all=CPVS[:]
- self.portdb._props=get_props(CPVS)
- pkgs, deprecated = self.target_class._destructive(package_names=False,
- exclude=self.exclude, pkgs_=None, installed_included=False )
- self.record_results('destructive4', pkgs, deprecated)
- self.check_results("test_destructive")
-
- self.callback_data = []
- self.vardb._cpv_all=CPVS[:3]
- self.vardb._cpv_all.extend(CPVS3)
- self.vardb._props=get_props(self.vardb._cpv_all)
- self.portdb._cpv_all=CPVS2
- #self.portdb._cpv_all.extend(CPVS2)
- self.portdb._props=PROPS
- pkgs, deprecated = self.target_class._destructive(package_names=False,
- exclude=self.exclude, pkgs_=None, installed_included=False )
- self.record_results('destructive5', pkgs, deprecated)
- self.check_results("test_destructive")
-
-
- def tearDown(self):
- del self.portdb, self.vardb
+ """Tests eclean.search.DistfilesSearch._non_destructive and _destructive
+ functions, with addition useage tests of fetch_restricted() and _unrestricted()
+ """
+
+ def setUp(self):
+ self.vardb = Dbapi(
+ cp_all=[], cpv_all=CPVS, props=PROPS, cp_list=[], name="FAKE VARDB"
+ )
+ self.portdb = Dbapi(
+ cp_all=[],
+ cpv_all=CPVS[:4],
+ props=get_props(CPVS[:4]),
+ cp_list=[],
+ name="FAKE PORTDB",
+ )
+ print(self.portdb)
+ # set a fetch restricted pkg
+ self.portdb._props[CPVS[0]]["RESTRICT"] = "fetch"
+ self.callback_data = []
+ self.output = OutputSimulator(self.callback)
+ self.target_class = DistfilesSearch(self.output.einfo, self.portdb, self.vardb)
+ search.exclDictExpand = self.exclDictExpand
+ self.exclude = parseExcludeFile(
+ os.path.join(
+ os.path.dirname(os.path.abspath(__file__)), "distfiles.exclude"
+ ),
+ self.output.einfo,
+ )
+ # print(self.callback_data)
+ # print(self.exclude)
+ self.callback_data = []
+ self.results = {}
+ self.testdata = {
+ "non_destructive1": {
+ "deprecated": {
+ "app-emulation/emul-linux-x86-baselibs-20100220": "mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz"
+ },
+ "pkgs": {
+ "sys-auth/consolekit-0.4.1": "http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2",
+ "sys-apps/help2man-1.37.1": "mirror://gnu/help2man/help2man-1.37.1.tar.gz",
+ "sys-apps/devicekit-power-014": "http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz",
+ "app-emulation/emul-linux-x86-baselibs-20100220": "mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz",
+ "media-libs/sdl-pango-0.1.2": "mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch",
+ },
+ "output": [
+ " - getting complete ebuild list",
+ " - getting source file names for 5 ebuilds",
+ '!!! "Deprecation Warning: Installed package: app-emulation/emul-linux-x86-baselibs-20100220\n\tIs no longer in the tree or an installed overlay\n',
+ ],
+ },
+ "non_destructive2": {
+ "deprecated": {},
+ "pkgs": {
+ "sys-apps/devicekit-power-014": "http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz",
+ "sys-auth/consolekit-0.4.1": "http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2",
+ "media-libs/sdl-pango-0.1.2": "mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch",
+ },
+ "output": [
+ " - getting complete ebuild list",
+ " - getting source file names for 3 installed ebuilds",
+ " - getting fetch-restricted source file names for 2 remaining ebuilds",
+ ],
+ },
+ "non_destructive3": {
+ "deprecated": {},
+ "pkgs": {
+ "sys-apps/devicekit-power-014": "http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz",
+ "sys-auth/consolekit-0.4.1": "http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2",
+ "app-emulation/emul-linux-x86-baselibs-20100220": "mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz",
+ },
+ "output": [
+ " - getting complete ebuild list",
+ " - getting source file names for 2 installed ebuilds",
+ " - getting fetch-restricted source file names for 3 remaining ebuilds",
+ ],
+ },
+ "destructive1": {
+ "deprecated": {
+ "app-emulation/emul-linux-x86-baselibs-20100220": "mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz"
+ },
+ "pkgs": {
+ "sys-apps/devicekit-power-014": "http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz",
+ "sys-apps/help2man-1.37.1": "mirror://gnu/help2man/help2man-1.37.1.tar.gz",
+ "sys-auth/consolekit-0.4.1": "http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2",
+ "app-emulation/emul-linux-x86-baselibs-20100220": "mirror://gentoo/emul-linux-x86-baselibs-20100220.tar.gz",
+ "media-libs/sdl-pango-0.1.2": "mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch",
+ },
+ "output": [
+ " - processing 5 installed ebuilds",
+ " - processing excluded",
+ " - (5 of 0 total) additional excluded packages to get source filenames for",
+ '!!! "Deprecation Warning: Installed package: app-emulation/emul-linux-x86-baselibs-20100220\n\tIs no longer in the tree or an installed overlay\n',
+ ],
+ },
+ "destructive2": {
+ "deprecated": {},
+ "pkgs": {},
+ "output": [
+ " - processing 0 installed packages",
+ " - processing excluded",
+ " - (0 of 0 total) additional excluded packages to get source filenames for",
+ ],
+ },
+ "destructive3": {
+ "deprecated": {},
+ "pkgs": {
+ "app-portage/gentoolkit-0.3.0_rc8-r1": "mirror://gentoo/gentoolkit-0.3.0_rc8.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc8.tar.gz",
+ "sys-apps/devicekit-power-014": "http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz",
+ "app-portage/gentoolkit-0.3.0_rc8": "mirror://gentoo/gentoolkit-0.3.0_rc8.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc8.tar.gz",
+ "app-portage/gentoolkit-0.2.4.6-r1": "mirror://gentoo/gentoolkit-0.2.4.6.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.6.tar.gz",
+ "app-portage/gentoolkit-0.3.0_rc7": "mirror://gentoo/gentoolkit-0.3.0_rc7.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc7.tar.gz",
+ "app-portage/gentoolkit-0.2.4.6": "mirror://gentoo/gentoolkit-0.2.4.6.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.6.tar.gz",
+ "app-portage/eix-0.19.2": "mirror://sourceforge/eix/eix-0.19.2.tar.xz",
+ "app-portage/gentoolkit-0.2.4.5": "mirror://gentoo/gentoolkit-0.2.4.5.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.5.tar.gz",
+ "app-portage/gentoolkit-0.3.0_rc9": "mirror://gentoo/gentoolkit-0.3.0_rc9.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc9.tar.gz",
+ "app-portage/eix-0.20.1": "mirror://sourceforge/eix/eix-0.20.1.tar.xz",
+ "app-portage/eix-0.20.2": "mirror://berlios/eix/eix-0.20.2.tar.xz",
+ },
+ "output": [
+ " - processing excluded",
+ " - (10 of 10 total) additional excluded packages to get source filenames for",
+ ],
+ },
+ "destructive4": {
+ "deprecated": {},
+ "pkgs": {
+ "sys-auth/consolekit-0.4.1": "http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2",
+ "sys-apps/devicekit-power-014": "http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz",
+ "media-libs/sdl-pango-0.1.2": "mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch",
+ },
+ "output": [
+ " - processing 3 installed ebuilds",
+ " - processing excluded",
+ " - (3 of 0 total) additional excluded packages to get source filenames for",
+ ],
+ },
+ "destructive5": {
+ "deprecated": {},
+ "pkgs": {
+ "x11-base/xorg-server-1.7.5": "http://xorg.freedesktop.org/releases/individual/xserver/xorg-server-1.7.5.tar.bz2",
+ "app-portage/gentoolkit-0.3.0_rc8-r1": "mirror://gentoo/gentoolkit-0.3.0_rc8.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc8.tar.gz",
+ "sys-apps/devicekit-power-014": "http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz",
+ "x11-misc/util-macros-1.6.0": "http://xorg.freedesktop.org/releases/individual/util/util-macros-1.6.0.tar.bz2",
+ "app-portage/eix-0.19.2": "mirror://sourceforge/eix/eix-0.19.2.tar.xz",
+ "app-portage/gentoolkit-0.3.0_rc8": "mirror://gentoo/gentoolkit-0.3.0_rc8.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc8.tar.gz",
+ "app-portage/gentoolkit-0.2.4.6-r1": "mirror://gentoo/gentoolkit-0.2.4.6.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.6.tar.gz",
+ "app-portage/gentoolkit-0.3.0_rc7": "mirror://gentoo/gentoolkit-0.3.0_rc7.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc7.tar.gz",
+ "sys-auth/consolekit-0.4.1": "http://www.freedesktop.org/software/ConsoleKit/dist/ConsoleKit-0.4.1.tar.bz2",
+ "app-portage/gentoolkit-0.2.4.6": "mirror://gentoo/gentoolkit-0.2.4.6.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.6.tar.gz",
+ "media-libs/sdl-pango-0.1.2": "mirror://sourceforge/sdlpango/SDL_Pango-0.1.2.tar.gz http://zarb.org/~gc/t/SDL_Pango-0.1.2-API-adds.patch",
+ "x11-libs/pixman-0.16.4": "http://xorg.freedesktop.org/releases/individual/lib/pixman-0.16.4.tar.bz2",
+ "app-portage/gentoolkit-0.2.4.5": "mirror://gentoo/gentoolkit-0.2.4.5.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.2.4.5.tar.gz",
+ "app-portage/gentoolkit-0.3.0_rc9": "mirror://gentoo/gentoolkit-0.3.0_rc9.tar.gz http://dev.gentoo.org/~fuzzyray/distfiles/gentoolkit-0.3.0_rc9.tar.gz",
+ "app-portage/eix-0.20.1": "mirror://sourceforge/eix/eix-0.20.1.tar.xz",
+ "app-portage/eix-0.20.2": "mirror://berlios/eix/eix-0.20.2.tar.xz",
+ },
+ "output": [
+ " - processing 6 installed ebuilds",
+ " - processing excluded",
+ " - (16 of 10 total) additional excluded packages to get source filenames for",
+ ],
+ },
+ }
+
+ def callback(self, id, data):
+ self.callback_data.append(data)
+
+ def exclDictExpand(self, exclude):
+ # print("Using Fake Testing exclDictExpand()")
+ return [
+ # 'app-portage/layman',
+ "app-portage/eix",
+ "app-portage/gentoolkit",
+ # app-portage/portage-utils',
+ ]
+
+ def test_non_destructive(self):
+ self.results = {}
+ pkgs, deprecated = self.target_class._non_destructive(
+ destructive=False, fetch_restricted=False, pkgs_=None
+ )
+ self.record_results("non_destructive1", pkgs, deprecated)
+
+ pkgs = None
+ deprecated = None
+ self.callback_data = []
+ self.vardb._cpv_all = CPVS[:3]
+ self.vardb._props = get_props(CPVS[:3])
+ self.portdb._cpv_all = CPVS[:]
+ self.portdb._props = get_props(CPVS)
+ self.target_class.installed_cpvs = None
+ pkgs, deprecated = self.target_class._non_destructive(
+ destructive=True, fetch_restricted=True, pkgs_=None
+ )
+ self.record_results("non_destructive2", pkgs, deprecated)
+
+ pkgs = None
+ deprecated = None
+ self.callback_data = []
+ self.vardb._cpv_all = CPVS[:2]
+ self.vardb._props = get_props(CPVS[:2])
+ self.portdb._cpv_all = CPVS[:]
+ self.portdb._props = get_props(CPVS)
+ # set a fetch restricted pkg
+ self.portdb._props[CPVS[4]]["RESTRICT"] = "fetch"
+ pkgs = {
+ "sys-apps/devicekit-power-014": "http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz"
+ }
+ pkgs, deprecated = self.target_class._non_destructive(
+ destructive=True, fetch_restricted=True, pkgs_=pkgs
+ )
+ self.record_results("non_destructive3", pkgs, deprecated)
+ self.check_results("test_non_destructive")
+
+ def check_results(self, test_name):
+ print("\nChecking results for %s,............" % test_name)
+ for key in sorted(self.results):
+ testdata = self.testdata[key]
+ results = self.results[key]
+ for item in sorted(testdata):
+ if sorted(results[item]) == sorted(testdata[item]):
+ test = "OK"
+ else:
+ test = "FAILED"
+ print("comparing %s, %s..." % (key, item), test)
+ if test == "FAILED":
+ print("", sorted(results[item]), "\n", sorted(testdata[item]))
+ self.assertEqual(
+ sorted(testdata[item]),
+ sorted(results[item]),
+ "\n%s: %s, %s data does not match\n" % (test_name, key, item)
+ + "result="
+ + str(results[item])
+ + "\ntestdata="
+ + str(testdata[item]),
+ )
+
+ def record_results(self, test, pkgs, deprecated):
+ self.results[test] = {
+ "pkgs": pkgs,
+ "deprecated": deprecated,
+ "output": self.callback_data,
+ }
+
+ def test_destructive(self):
+ self.results = {}
+ pkgs, deprecated = self.target_class._destructive(
+ package_names=False, exclude={}, pkgs_=None, installed_included=False
+ )
+ self.record_results("destructive1", pkgs, deprecated)
+
+ self.callback_data = []
+ self.vardb._cpv_all = CPVS[:3]
+ self.vardb._props = get_props(CPVS[:3])
+ self.portdb._cpv_all = CPVS[:]
+ self.portdb._props = get_props(CPVS)
+ pkgs, deprecated = self.target_class._destructive(
+ package_names=True, exclude={}, pkgs_=None, installed_included=False
+ )
+ self.record_results("destructive2", pkgs, deprecated)
+
+ self.callback_data = []
+ cpvs = CPVS[2:4]
+ cpvs.extend(CPVS3)
+ self.vardb._cpv_all = sorted(cpvs)
+ self.vardb._props = PROPS.update(get_props(CPVS3))
+ self.portdb._cpv_all = sorted(CPVS + CPVS2)
+ self.portdb._props = get_props(CPVS + CPVS2)
+ # set a fetch restricted pkg
+ self.portdb._props[CPVS[4]]["RESTRICT"] = "fetch"
+ pkgs = {
+ "sys-apps/devicekit-power-014": "http://hal.freedesktop.org/releases/DeviceKit-power-014.tar.gz"
+ }
+ pkgs, deprecated = self.target_class._destructive(
+ package_names=True, exclude={}, pkgs_=pkgs, installed_included=True
+ )
+ self.record_results("destructive3", pkgs, deprecated)
+
+ self.callback_data = []
+ self.vardb._cpv_all = CPVS[:3]
+ self.vardb._props = get_props(CPVS[:3])
+ self.portdb._cpv_all = CPVS[:]
+ self.portdb._props = get_props(CPVS)
+ pkgs, deprecated = self.target_class._destructive(
+ package_names=False,
+ exclude=self.exclude,
+ pkgs_=None,
+ installed_included=False,
+ )
+ self.record_results("destructive4", pkgs, deprecated)
+ self.check_results("test_destructive")
+
+ self.callback_data = []
+ self.vardb._cpv_all = CPVS[:3]
+ self.vardb._cpv_all.extend(CPVS3)
+ self.vardb._props = get_props(self.vardb._cpv_all)
+ self.portdb._cpv_all = CPVS2
+ # self.portdb._cpv_all.extend(CPVS2)
+ self.portdb._props = PROPS
+ pkgs, deprecated = self.target_class._destructive(
+ package_names=False,
+ exclude=self.exclude,
+ pkgs_=None,
+ installed_included=False,
+ )
+ self.record_results("destructive5", pkgs, deprecated)
+ self.check_results("test_destructive")
+
+ def tearDown(self):
+ del self.portdb, self.vardb
class TestRemoveProtected(unittest.TestCase):
- """tests the eclean.search.DistfilesSearch._remove_protected()
- """
+ """tests the eclean.search.DistfilesSearch._remove_protected()"""
+
+ def setUp(self):
+ self.target_class = DistfilesSearch(lambda x: None)
+ self.results = {
+ "layman-1.2.5.tar.gz": "/path/to/some/where/layman-1.2.5.tar.gz"
+ }
+
+ def test_remove_protected(self):
+ results = self.target_class._remove_protected(PKGS, CLEAN_ME)
+ self.assertEqual(
+ results,
+ self.results,
+ "\ntest_remove_protected: data does not match\nresult="
+ + str(results)
+ + "\ntestdata="
+ + str(self.results),
+ )
- def setUp(self):
- self.target_class = DistfilesSearch(lambda x: None)
- self.results = {'layman-1.2.5.tar.gz': '/path/to/some/where/layman-1.2.5.tar.gz'}
- def test_remove_protected(self):
- results = self.target_class._remove_protected(PKGS, CLEAN_ME)
- self.assertEqual(results, self.results,
- "\ntest_remove_protected: data does not match\nresult=" +\
- str(results) + "\ntestdata=" + str(self.results))
+def test_main():
+ suite = unittest.TestLoader()
+ suite.loadTestsFromTestCase(TestCheckLimits)
+ suite.loadTestsFromTestCase(TestFetchRestricted)
+ suite.loadTestsFromTestCase(TestNonDestructive)
+ suite.loadTestsFromTestCase(TestRemoveProtected)
+ unittest.TextTestRunner(verbosity=2).run(suite)
-def test_main():
- suite = unittest.TestLoader()
- suite.loadTestsFromTestCase(TestCheckLimits)
- suite.loadTestsFromTestCase(TestFetchRestricted)
- suite.loadTestsFromTestCase(TestNonDestructive)
- suite.loadTestsFromTestCase(TestRemoveProtected)
- unittest.TextTestRunner(verbosity=2).run(suite)
test_main.__test__ = False
-if __name__ == '__main__':
- test_main()
+if __name__ == "__main__":
+ test_main()
diff --git a/pym/gentoolkit/test/equery/test_init.py b/pym/gentoolkit/test/equery/test_init.py
index 4cad22e..c97c0fd 100644
--- a/pym/gentoolkit/test/equery/test_init.py
+++ b/pym/gentoolkit/test/equery/test_init.py
@@ -2,47 +2,47 @@ import unittest
from gentoolkit import equery
-class TestEqueryInit(unittest.TestCase):
- def setUp(self):
- pass
-
- def tearDown(self):
- pass
-
- def test_expand_module_name(self):
- # Test that module names are properly expanded
- name_map = {
- 'a': 'has',
- 'b': 'belongs',
- 'k': 'check',
- 'd': 'depends',
- 'g': 'depgraph',
- 'f': 'files',
- 'h': 'hasuse',
- 'y': 'keywords',
- 'l': 'list_',
- 'm': 'meta',
- 's': 'size',
- 'u': 'uses',
- 'w': 'which'
- }
- self.assertEqual(equery.NAME_MAP, name_map)
- for short_name, long_name in zip(name_map, name_map.values()):
- self.assertEqual(equery.expand_module_name(short_name),
- long_name)
- self.assertEqual(equery.expand_module_name(long_name),
- long_name)
- unused_keys = set(map(chr, range(0, 256))).difference(name_map.keys())
- for key in unused_keys:
- self.assertRaises(KeyError, equery.expand_module_name, key)
+class TestEqueryInit(unittest.TestCase):
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def test_expand_module_name(self):
+ # Test that module names are properly expanded
+ name_map = {
+ "a": "has",
+ "b": "belongs",
+ "k": "check",
+ "d": "depends",
+ "g": "depgraph",
+ "f": "files",
+ "h": "hasuse",
+ "y": "keywords",
+ "l": "list_",
+ "m": "meta",
+ "s": "size",
+ "u": "uses",
+ "w": "which",
+ }
+ self.assertEqual(equery.NAME_MAP, name_map)
+ for short_name, long_name in zip(name_map, name_map.values()):
+ self.assertEqual(equery.expand_module_name(short_name), long_name)
+ self.assertEqual(equery.expand_module_name(long_name), long_name)
+ unused_keys = set(map(chr, range(0, 256))).difference(name_map.keys())
+ for key in unused_keys:
+ self.assertRaises(KeyError, equery.expand_module_name, key)
def test_main():
- suite = unittest.TestLoader().loadTestsFromTestCase(TestEqueryInit)
- unittest.TextTestRunner(verbosity=2).run(suite)
+ suite = unittest.TestLoader().loadTestsFromTestCase(TestEqueryInit)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+
+
test_main.__test__ = False
-if __name__ == '__main__':
- test_main()
+if __name__ == "__main__":
+ test_main()
diff --git a/pym/gentoolkit/test/test_atom.py b/pym/gentoolkit/test/test_atom.py
index 6df52a9..f5a2a4b 100644
--- a/pym/gentoolkit/test/test_atom.py
+++ b/pym/gentoolkit/test/test_atom.py
@@ -10,132 +10,138 @@ from gentoolkit.cpv import CPV
"""Atom test suite (verbatim) from pkgcore."""
-class TestGentoolkitAtom(unittest.TestCase):
- def assertEqual2(self, o1, o2):
- # logic bugs hidden behind short circuiting comparisons for metadata
- # is why we test the comparison *both* ways.
- self.assertEqual(o1, o2)
- self.assertEqual(o2, o1)
-
- def assertNotEqual2(self, o1, o2):
- # is why we test the comparison *both* ways.
- self.assertNotEqual(o1, o2)
- self.assertNotEqual(o2, o1)
-
- def test_comparison(self):
- self.assertEqual2(Atom('cat/pkg'), Atom('cat/pkg'))
- self.assertNotEqual2(Atom('cat/pkg'), Atom('cat/pkgb'))
- self.assertNotEqual2(Atom('cata/pkg'), Atom('cat/pkg'))
- self.assertNotEqual2(Atom('cat/pkg'), Atom('!cat/pkg'))
- self.assertEqual2(Atom('!cat/pkg'), Atom('!cat/pkg'))
- self.assertNotEqual2(Atom('=cat/pkg-0.1:0'),
- Atom('=cat/pkg-0.1'))
- self.assertNotEqual2(Atom('=cat/pkg-1[foon]'),
- Atom('=cat/pkg-1'))
- self.assertEqual2(Atom('=cat/pkg-0'), Atom('=cat/pkg-0'))
- self.assertNotEqual2(Atom('<cat/pkg-2'), Atom('>cat/pkg-2'))
- self.assertNotEqual2(Atom('=cat/pkg-2*'), Atom('=cat/pkg-2'))
- # Portage Atom doesn't have 'negate_version' capability
- #self.assertNotEqual2(Atom('=cat/pkg-2', True), Atom('=cat/pkg-2'))
-
- # use...
- self.assertNotEqual2(Atom('cat/pkg[foo]'), Atom('cat/pkg'))
- self.assertNotEqual2(Atom('cat/pkg[foo]'),
- Atom('cat/pkg[-foo]'))
- self.assertEqual2(Atom('cat/pkg[foo,-bar]'),
- Atom('cat/pkg[-bar,foo]'))
-
- # repoid not supported by Portage Atom yet
- ## repoid
- #self.assertEqual2(Atom('cat/pkg::a'), Atom('cat/pkg::a'))
- #self.assertNotEqual2(Atom('cat/pkg::a'), Atom('cat/pkg::b'))
- #self.assertNotEqual2(Atom('cat/pkg::a'), Atom('cat/pkg'))
-
- # slots.
- self.assertNotEqual2(Atom('cat/pkg:1'), Atom('cat/pkg'))
- self.assertEqual2(Atom('cat/pkg:2'), Atom('cat/pkg:2'))
- # http://dev.gentoo.org/~tanderson/pms/eapi-2-approved/pms.html#x1-190002.1.2
- self.assertEqual2(Atom('cat/pkg:AZaz09+_.-'), Atom('cat/pkg:AZaz09+_.-'))
- for lesser, greater in (('0.1', '1'), ('1', '1-r1'), ('1.1', '1.2')):
- self.assertTrue(Atom('=d/b-%s' % lesser) <
- Atom('=d/b-%s' % greater),
- msg="d/b-%s < d/b-%s" % (lesser, greater))
- self.assertFalse(Atom('=d/b-%s' % lesser) >
- Atom('=d/b-%s' % greater),
- msg="!: d/b-%s < d/b-%s" % (lesser, greater))
- self.assertTrue(Atom('=d/b-%s' % greater) >
- Atom('=d/b-%s' % lesser),
- msg="d/b-%s > d/b-%s" % (greater, lesser))
- self.assertFalse(Atom('=d/b-%s' % greater) <
- Atom('=d/b-%s' % lesser),
- msg="!: d/b-%s > d/b-%s" % (greater, lesser))
-
- #self.assertTrue(Atom("!!=d/b-1", eapi=2) > Atom("!=d/b-1"))
- self.assertTrue(Atom("!=d/b-1") < Atom("!!=d/b-1"))
- self.assertEqual(Atom("!=d/b-1"), Atom("!=d/b-1"))
-
- def test_intersects(self):
- for this, that, result in [
- ('cat/pkg', 'pkg/cat', False),
- ('cat/pkg', 'cat/pkg', True),
- ('cat/pkg:1', 'cat/pkg:1', True),
- ('cat/pkg:1', 'cat/pkg:2', False),
- ('cat/pkg:1', 'cat/pkg[foo]', True),
- ('cat/pkg[foo]', 'cat/pkg[-bar]', True),
- ('cat/pkg[foo]', 'cat/pkg[-foo]', False),
- ('>cat/pkg-3', '>cat/pkg-1', True),
- ('>cat/pkg-3', '<cat/pkg-3', False),
- ('>=cat/pkg-3', '<cat/pkg-3', False),
- ('>cat/pkg-2', '=cat/pkg-2*', True),
- # Portage vercmp disagrees with this one:
- #('<cat/pkg-2_alpha1', '=cat/pkg-2*', True),
- ('=cat/pkg-2', '=cat/pkg-2', True),
- ('=cat/pkg-3', '=cat/pkg-2', False),
- ('=cat/pkg-2', '>cat/pkg-2', False),
- ('=cat/pkg-2', '>=cat/pkg-2', True),
- ('~cat/pkg-2', '~cat/pkg-2', True),
- ('~cat/pkg-2', '~cat/pkg-2.1', False),
- ('=cat/pkg-2*', '=cat/pkg-2.3*', True),
- ('>cat/pkg-2.4', '=cat/pkg-2*', True),
- ('<cat/pkg-2.4', '=cat/pkg-2*', True),
- ('<cat/pkg-1', '=cat/pkg-2*', False),
- ('~cat/pkg-2', '>cat/pkg-2-r1', True),
- ('~cat/pkg-2', '<=cat/pkg-2', True),
- ('=cat/pkg-2-r2*', '<=cat/pkg-2-r20', True),
- ('=cat/pkg-2-r2*', '<cat/pkg-2-r20', True),
- ('=cat/pkg-2-r2*', '<=cat/pkg-2-r2', True),
- ('~cat/pkg-2', '<cat/pkg-2', False),
- ('=cat/pkg-1-r10*', '~cat/pkg-1', True),
- ('=cat/pkg-1-r1*', '<cat/pkg-1-r1', False),
- ('=cat/pkg-1*', '>cat/pkg-2', False),
- ('>=cat/pkg-8.4', '=cat/pkg-8.3.4*', False),
- ('cat/pkg::gentoo', 'cat/pkg', True),
- ('cat/pkg::gentoo', 'cat/pkg::foo', False),
- ('=sys-devel/gcc-4.1.1-r3', '=sys-devel/gcc-3.3*', False),
- ('=sys-libs/db-4*', '~sys-libs/db-4.3.29', True),
- ]:
- this_atom = Atom(this)
- that_atom = Atom(that)
- self.assertEqual(
- result, this_atom.intersects(that_atom),
- '%s intersecting %s should be %s' % (this, that, result))
- self.assertEqual(
- result, that_atom.intersects(this_atom),
- '%s intersecting %s should be %s' % (that, this, result))
-
- def test_intersects_nameonly(self):
- atom = Atom('cat/pkg')
- self.assertTrue(atom.intersects(CPV('pkg')))
- self.assertFalse(atom.intersects(CPV('other')))
- self.assertFalse(atom.intersects(CPV('dkg')))
+class TestGentoolkitAtom(unittest.TestCase):
+ def assertEqual2(self, o1, o2):
+ # logic bugs hidden behind short circuiting comparisons for metadata
+ # is why we test the comparison *both* ways.
+ self.assertEqual(o1, o2)
+ self.assertEqual(o2, o1)
+
+ def assertNotEqual2(self, o1, o2):
+ # is why we test the comparison *both* ways.
+ self.assertNotEqual(o1, o2)
+ self.assertNotEqual(o2, o1)
+
+ def test_comparison(self):
+ self.assertEqual2(Atom("cat/pkg"), Atom("cat/pkg"))
+ self.assertNotEqual2(Atom("cat/pkg"), Atom("cat/pkgb"))
+ self.assertNotEqual2(Atom("cata/pkg"), Atom("cat/pkg"))
+ self.assertNotEqual2(Atom("cat/pkg"), Atom("!cat/pkg"))
+ self.assertEqual2(Atom("!cat/pkg"), Atom("!cat/pkg"))
+ self.assertNotEqual2(Atom("=cat/pkg-0.1:0"), Atom("=cat/pkg-0.1"))
+ self.assertNotEqual2(Atom("=cat/pkg-1[foon]"), Atom("=cat/pkg-1"))
+ self.assertEqual2(Atom("=cat/pkg-0"), Atom("=cat/pkg-0"))
+ self.assertNotEqual2(Atom("<cat/pkg-2"), Atom(">cat/pkg-2"))
+ self.assertNotEqual2(Atom("=cat/pkg-2*"), Atom("=cat/pkg-2"))
+ # Portage Atom doesn't have 'negate_version' capability
+ # self.assertNotEqual2(Atom('=cat/pkg-2', True), Atom('=cat/pkg-2'))
+
+ # use...
+ self.assertNotEqual2(Atom("cat/pkg[foo]"), Atom("cat/pkg"))
+ self.assertNotEqual2(Atom("cat/pkg[foo]"), Atom("cat/pkg[-foo]"))
+ self.assertEqual2(Atom("cat/pkg[foo,-bar]"), Atom("cat/pkg[-bar,foo]"))
+
+ # repoid not supported by Portage Atom yet
+ # repoid
+ # self.assertEqual2(Atom('cat/pkg::a'), Atom('cat/pkg::a'))
+ # self.assertNotEqual2(Atom('cat/pkg::a'), Atom('cat/pkg::b'))
+ # self.assertNotEqual2(Atom('cat/pkg::a'), Atom('cat/pkg'))
+
+ # slots.
+ self.assertNotEqual2(Atom("cat/pkg:1"), Atom("cat/pkg"))
+ self.assertEqual2(Atom("cat/pkg:2"), Atom("cat/pkg:2"))
+ # http://dev.gentoo.org/~tanderson/pms/eapi-2-approved/pms.html#x1-190002.1.2
+ self.assertEqual2(Atom("cat/pkg:AZaz09+_.-"), Atom("cat/pkg:AZaz09+_.-"))
+ for lesser, greater in (("0.1", "1"), ("1", "1-r1"), ("1.1", "1.2")):
+ self.assertTrue(
+ Atom("=d/b-%s" % lesser) < Atom("=d/b-%s" % greater),
+ msg="d/b-%s < d/b-%s" % (lesser, greater),
+ )
+ self.assertFalse(
+ Atom("=d/b-%s" % lesser) > Atom("=d/b-%s" % greater),
+ msg="!: d/b-%s < d/b-%s" % (lesser, greater),
+ )
+ self.assertTrue(
+ Atom("=d/b-%s" % greater) > Atom("=d/b-%s" % lesser),
+ msg="d/b-%s > d/b-%s" % (greater, lesser),
+ )
+ self.assertFalse(
+ Atom("=d/b-%s" % greater) < Atom("=d/b-%s" % lesser),
+ msg="!: d/b-%s > d/b-%s" % (greater, lesser),
+ )
+
+ # self.assertTrue(Atom("!!=d/b-1", eapi=2) > Atom("!=d/b-1"))
+ self.assertTrue(Atom("!=d/b-1") < Atom("!!=d/b-1"))
+ self.assertEqual(Atom("!=d/b-1"), Atom("!=d/b-1"))
+
+ def test_intersects(self):
+ for this, that, result in [
+ ("cat/pkg", "pkg/cat", False),
+ ("cat/pkg", "cat/pkg", True),
+ ("cat/pkg:1", "cat/pkg:1", True),
+ ("cat/pkg:1", "cat/pkg:2", False),
+ ("cat/pkg:1", "cat/pkg[foo]", True),
+ ("cat/pkg[foo]", "cat/pkg[-bar]", True),
+ ("cat/pkg[foo]", "cat/pkg[-foo]", False),
+ (">cat/pkg-3", ">cat/pkg-1", True),
+ (">cat/pkg-3", "<cat/pkg-3", False),
+ (">=cat/pkg-3", "<cat/pkg-3", False),
+ (">cat/pkg-2", "=cat/pkg-2*", True),
+ # Portage vercmp disagrees with this one:
+ # ('<cat/pkg-2_alpha1', '=cat/pkg-2*', True),
+ ("=cat/pkg-2", "=cat/pkg-2", True),
+ ("=cat/pkg-3", "=cat/pkg-2", False),
+ ("=cat/pkg-2", ">cat/pkg-2", False),
+ ("=cat/pkg-2", ">=cat/pkg-2", True),
+ ("~cat/pkg-2", "~cat/pkg-2", True),
+ ("~cat/pkg-2", "~cat/pkg-2.1", False),
+ ("=cat/pkg-2*", "=cat/pkg-2.3*", True),
+ (">cat/pkg-2.4", "=cat/pkg-2*", True),
+ ("<cat/pkg-2.4", "=cat/pkg-2*", True),
+ ("<cat/pkg-1", "=cat/pkg-2*", False),
+ ("~cat/pkg-2", ">cat/pkg-2-r1", True),
+ ("~cat/pkg-2", "<=cat/pkg-2", True),
+ ("=cat/pkg-2-r2*", "<=cat/pkg-2-r20", True),
+ ("=cat/pkg-2-r2*", "<cat/pkg-2-r20", True),
+ ("=cat/pkg-2-r2*", "<=cat/pkg-2-r2", True),
+ ("~cat/pkg-2", "<cat/pkg-2", False),
+ ("=cat/pkg-1-r10*", "~cat/pkg-1", True),
+ ("=cat/pkg-1-r1*", "<cat/pkg-1-r1", False),
+ ("=cat/pkg-1*", ">cat/pkg-2", False),
+ (">=cat/pkg-8.4", "=cat/pkg-8.3.4*", False),
+ ("cat/pkg::gentoo", "cat/pkg", True),
+ ("cat/pkg::gentoo", "cat/pkg::foo", False),
+ ("=sys-devel/gcc-4.1.1-r3", "=sys-devel/gcc-3.3*", False),
+ ("=sys-libs/db-4*", "~sys-libs/db-4.3.29", True),
+ ]:
+ this_atom = Atom(this)
+ that_atom = Atom(that)
+ self.assertEqual(
+ result,
+ this_atom.intersects(that_atom),
+ "%s intersecting %s should be %s" % (this, that, result),
+ )
+ self.assertEqual(
+ result,
+ that_atom.intersects(this_atom),
+ "%s intersecting %s should be %s" % (that, this, result),
+ )
+
+ def test_intersects_nameonly(self):
+ atom = Atom("cat/pkg")
+ self.assertTrue(atom.intersects(CPV("pkg")))
+ self.assertFalse(atom.intersects(CPV("other")))
+ self.assertFalse(atom.intersects(CPV("dkg")))
def test_main():
- suite = unittest.TestLoader().loadTestsFromTestCase(TestGentoolkitAtom)
- unittest.TextTestRunner(verbosity=2).run(suite)
+ suite = unittest.TestLoader().loadTestsFromTestCase(TestGentoolkitAtom)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+
+
test_main.__test__ = False
-if __name__ == '__main__':
- test_main()
+if __name__ == "__main__":
+ test_main()
diff --git a/pym/gentoolkit/test/test_cpv.py b/pym/gentoolkit/test/test_cpv.py
index 92ffba5..c45e37a 100644
--- a/pym/gentoolkit/test/test_cpv.py
+++ b/pym/gentoolkit/test/test_cpv.py
@@ -8,117 +8,132 @@ import unittest
from gentoolkit.cpv import CPV, compare_strs
-class TestGentoolkitCPV(unittest.TestCase):
- def assertEqual2(self, o1, o2):
- # logic bugs hidden behind short circuiting comparisons for metadata
- # is why we test the comparison *both* ways.
- self.assertEqual(o1, o2)
- self.assertEqual(o2, o1)
+class TestGentoolkitCPV(unittest.TestCase):
+ def assertEqual2(self, o1, o2):
+ # logic bugs hidden behind short circuiting comparisons for metadata
+ # is why we test the comparison *both* ways.
+ self.assertEqual(o1, o2)
+ self.assertEqual(o2, o1)
- def assertNotEqual2(self, o1, o2):
- # is why we test the comparison *both* ways.
- self.assertNotEqual(o1, o2)
- self.assertNotEqual(o2, o1)
+ def assertNotEqual2(self, o1, o2):
+ # is why we test the comparison *both* ways.
+ self.assertNotEqual(o1, o2)
+ self.assertNotEqual(o2, o1)
- def test_comparison(self):
- self.assertEqual2(CPV('pkg'), CPV('pkg'))
- self.assertNotEqual2(CPV('pkg'), CPV('pkg1'))
- self.assertEqual2(CPV('cat/pkg'), CPV('cat/pkg'))
- self.assertNotEqual2(CPV('cat/pkg'), CPV('cat/pkgb'))
- self.assertNotEqual2(CPV('cata/pkg'), CPV('cat/pkg'))
- self.assertEqual2(CPV('cat/pkg-0.1'), CPV('cat/pkg-0.1'))
- self.assertNotEqual2(CPV('cat/pkg-1.0'), CPV('cat/pkg-1'))
- self.assertEqual2(CPV('cat/pkg-0'), CPV('cat/pkg-0'))
- self.assertEqual2(CPV('cat/pkg-1-r1'), CPV('cat/pkg-1-r1'))
- self.assertNotEqual2(CPV('cat/pkg-2-r1'), CPV('cat/pkg-2-r10'))
- self.assertEqual2(CPV('cat/pkg-1_rc2'), CPV('cat/pkg-1_rc2'))
- self.assertNotEqual2(CPV('cat/pkg-2_rc2-r1'), CPV('cat/pkg-2_rc1-r1'))
+ def test_comparison(self):
+ self.assertEqual2(CPV("pkg"), CPV("pkg"))
+ self.assertNotEqual2(CPV("pkg"), CPV("pkg1"))
+ self.assertEqual2(CPV("cat/pkg"), CPV("cat/pkg"))
+ self.assertNotEqual2(CPV("cat/pkg"), CPV("cat/pkgb"))
+ self.assertNotEqual2(CPV("cata/pkg"), CPV("cat/pkg"))
+ self.assertEqual2(CPV("cat/pkg-0.1"), CPV("cat/pkg-0.1"))
+ self.assertNotEqual2(CPV("cat/pkg-1.0"), CPV("cat/pkg-1"))
+ self.assertEqual2(CPV("cat/pkg-0"), CPV("cat/pkg-0"))
+ self.assertEqual2(CPV("cat/pkg-1-r1"), CPV("cat/pkg-1-r1"))
+ self.assertNotEqual2(CPV("cat/pkg-2-r1"), CPV("cat/pkg-2-r10"))
+ self.assertEqual2(CPV("cat/pkg-1_rc2"), CPV("cat/pkg-1_rc2"))
+ self.assertNotEqual2(CPV("cat/pkg-2_rc2-r1"), CPV("cat/pkg-2_rc1-r1"))
- def test_compare_strs(self):
- # Test ordering of package strings, Portage has test for vercmp,
- # so just do the rest
- version_tests = [
- # different categories
- ('sys-apps/portage-2.1.6.8', 'sys-auth/pambase-20080318'),
- # different package names
- ('sys-apps/pkgcore-0.4.7.15-r1', 'sys-apps/portage-2.1.6.8'),
- # different package versions
- ('sys-apps/portage-2.1.6.8', 'sys-apps/portage-2.2_rc25')
- ]
- # Check less than
- for vt in version_tests:
- self.assertTrue(compare_strs(vt[0], vt[1]) == -1)
- # Check greater than
- for vt in version_tests:
- self.assertTrue(compare_strs(vt[1], vt[0]) == 1)
- # Check equal
- vt = ('sys-auth/pambase-20080318', 'sys-auth/pambase-20080318')
- self.assertTrue(compare_strs(vt[0], vt[1]) == 0)
+ def test_compare_strs(self):
+ # Test ordering of package strings, Portage has test for vercmp,
+ # so just do the rest
+ version_tests = [
+ # different categories
+ ("sys-apps/portage-2.1.6.8", "sys-auth/pambase-20080318"),
+ # different package names
+ ("sys-apps/pkgcore-0.4.7.15-r1", "sys-apps/portage-2.1.6.8"),
+ # different package versions
+ ("sys-apps/portage-2.1.6.8", "sys-apps/portage-2.2_rc25"),
+ ]
+ # Check less than
+ for vt in version_tests:
+ self.assertTrue(compare_strs(vt[0], vt[1]) == -1)
+ # Check greater than
+ for vt in version_tests:
+ self.assertTrue(compare_strs(vt[1], vt[0]) == 1)
+ # Check equal
+ vt = ("sys-auth/pambase-20080318", "sys-auth/pambase-20080318")
+ self.assertTrue(compare_strs(vt[0], vt[1]) == 0)
- def test_chunk_splitting(self):
- all_tests = [
- # simple
- ('sys-apps/portage-2.2', {
- 'category': 'sys-apps',
- 'name': 'portage',
- 'cp': 'sys-apps/portage',
- 'version': '2.2',
- 'revision': '',
- 'fullversion': '2.2'
- }),
- # with rc
- ('sys-apps/portage-2.2_rc10', {
- 'category': 'sys-apps',
- 'name': 'portage',
- 'cp': 'sys-apps/portage',
- 'version': '2.2_rc10',
- 'revision': '',
- 'fullversion': '2.2_rc10'
- }),
- # with revision
- ('sys-apps/portage-2.2_rc10-r1', {
- 'category': 'sys-apps',
- 'name': 'portage',
- 'cp': 'sys-apps/portage',
- 'version': '2.2_rc10',
- 'revision': 'r1',
- 'fullversion': '2.2_rc10-r1'
- }),
- # with dash (-) in name (Bug #316961)
- ('c-portage', {
- 'category': '',
- 'name': 'c-portage',
- 'cp': 'c-portage',
- 'version': '',
- 'revision': '',
- 'fullversion': ''
- }),
- # with dash (-) in name (Bug #316961)
- ('sys-apps/c-portage-2.2_rc10-r1', {
- 'category': 'sys-apps',
- 'name': 'c-portage',
- 'cp': 'sys-apps/c-portage',
- 'version': '2.2_rc10',
- 'revision': 'r1',
- 'fullversion': '2.2_rc10-r1'
- }),
- ]
+ def test_chunk_splitting(self):
+ all_tests = [
+ # simple
+ (
+ "sys-apps/portage-2.2",
+ {
+ "category": "sys-apps",
+ "name": "portage",
+ "cp": "sys-apps/portage",
+ "version": "2.2",
+ "revision": "",
+ "fullversion": "2.2",
+ },
+ ),
+ # with rc
+ (
+ "sys-apps/portage-2.2_rc10",
+ {
+ "category": "sys-apps",
+ "name": "portage",
+ "cp": "sys-apps/portage",
+ "version": "2.2_rc10",
+ "revision": "",
+ "fullversion": "2.2_rc10",
+ },
+ ),
+ # with revision
+ (
+ "sys-apps/portage-2.2_rc10-r1",
+ {
+ "category": "sys-apps",
+ "name": "portage",
+ "cp": "sys-apps/portage",
+ "version": "2.2_rc10",
+ "revision": "r1",
+ "fullversion": "2.2_rc10-r1",
+ },
+ ),
+ # with dash (-) in name (Bug #316961)
+ (
+ "c-portage",
+ {
+ "category": "",
+ "name": "c-portage",
+ "cp": "c-portage",
+ "version": "",
+ "revision": "",
+ "fullversion": "",
+ },
+ ),
+ # with dash (-) in name (Bug #316961)
+ (
+ "sys-apps/c-portage-2.2_rc10-r1",
+ {
+ "category": "sys-apps",
+ "name": "c-portage",
+ "cp": "sys-apps/c-portage",
+ "version": "2.2_rc10",
+ "revision": "r1",
+ "fullversion": "2.2_rc10-r1",
+ },
+ ),
+ ]
- for test in all_tests:
- cpv = CPV(test[0])
- keys = ('category', 'name', 'cp', 'version', 'revision', 'fullversion')
- for k in keys:
- self.assertEqual(
- getattr(cpv, k), test[1][k]
- )
+ for test in all_tests:
+ cpv = CPV(test[0])
+ keys = ("category", "name", "cp", "version", "revision", "fullversion")
+ for k in keys:
+ self.assertEqual(getattr(cpv, k), test[1][k])
def test_main():
- suite = unittest.TestLoader().loadTestsFromTestCase(TestGentoolkitCPV)
- unittest.TextTestRunner(verbosity=2).run(suite)
+ suite = unittest.TestLoader().loadTestsFromTestCase(TestGentoolkitCPV)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+
+
test_main.__test__ = False
-if __name__ == '__main__':
- test_main()
+if __name__ == "__main__":
+ test_main()
diff --git a/pym/gentoolkit/test/test_helpers.py b/pym/gentoolkit/test/test_helpers.py
index be27835..e92568d 100644
--- a/pym/gentoolkit/test/test_helpers.py
+++ b/pym/gentoolkit/test/test_helpers.py
@@ -7,70 +7,71 @@ from gentoolkit import helpers
class TestFileOwner(unittest.TestCase):
-
- def setUp(self):
- pass
-
- def tearDown(self):
- pass
-
- def test_expand_abspaths(self):
- expand_abspaths = helpers.FileOwner.expand_abspaths
-
- initial_file_list = ['foo0', '/foo1', '~/foo2', './foo3']
- # This function should only effect foo3, and not ordering:
-
- final_file_list = [
- 'foo0',
- '/foo1',
- '~/foo2',
- os.path.join(os.getcwd(), os.path.normpath(initial_file_list[3]))
- ]
-
- self.assertEqual(expand_abspaths(initial_file_list), final_file_list)
-
- def test_extend_realpaths(self):
- extend_realpaths = helpers.FileOwner.extend_realpaths
-
- # Test that symlinks's realpaths are extended
- f1 = NamedTemporaryFile(prefix='equeryunittest')
- f2 = NamedTemporaryFile(prefix='equeryunittest')
- f3 = NamedTemporaryFile(prefix='equeryunittest')
- with warnings.catch_warnings():
- warnings.simplefilter("ignore")
- sym1 = mktemp()
- os.symlink(f1.name, sym1)
- sym2 = mktemp()
- os.symlink(f3.name, sym2)
- # We've created 3 files and 2 symlinks for testing. We're going to pass
- # in only the first two files and both symlinks. sym1 points to f1.
- # Since f1 is already in the list, sym1's realpath should not be added.
- # sym2 points to f3, but f3's not in our list, so sym2's realpath
- # should be added to the list.
- p = [f1.name, f2.name, sym1, sym2]
- p_xr = extend_realpaths(p)
-
- self.assertEqual(p_xr[0], f1.name)
- self.assertEqual(p_xr[1], f2.name)
- self.assertEqual(p_xr[2], sym1)
- self.assertEqual(p_xr[3], sym2)
- self.assertEqual(p_xr[4], f3.name)
-
- # Clean up
- os.unlink(sym1)
- os.unlink(sym2)
-
- # Make sure we raise an exception if we don't get acceptable input
- self.assertRaises(AttributeError, extend_realpaths, 'str')
- self.assertRaises(AttributeError, extend_realpaths, set())
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def test_expand_abspaths(self):
+ expand_abspaths = helpers.FileOwner.expand_abspaths
+
+ initial_file_list = ["foo0", "/foo1", "~/foo2", "./foo3"]
+ # This function should only effect foo3, and not ordering:
+
+ final_file_list = [
+ "foo0",
+ "/foo1",
+ "~/foo2",
+ os.path.join(os.getcwd(), os.path.normpath(initial_file_list[3])),
+ ]
+
+ self.assertEqual(expand_abspaths(initial_file_list), final_file_list)
+
+ def test_extend_realpaths(self):
+ extend_realpaths = helpers.FileOwner.extend_realpaths
+
+ # Test that symlinks's realpaths are extended
+ f1 = NamedTemporaryFile(prefix="equeryunittest")
+ f2 = NamedTemporaryFile(prefix="equeryunittest")
+ f3 = NamedTemporaryFile(prefix="equeryunittest")
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ sym1 = mktemp()
+ os.symlink(f1.name, sym1)
+ sym2 = mktemp()
+ os.symlink(f3.name, sym2)
+ # We've created 3 files and 2 symlinks for testing. We're going to pass
+ # in only the first two files and both symlinks. sym1 points to f1.
+ # Since f1 is already in the list, sym1's realpath should not be added.
+ # sym2 points to f3, but f3's not in our list, so sym2's realpath
+ # should be added to the list.
+ p = [f1.name, f2.name, sym1, sym2]
+ p_xr = extend_realpaths(p)
+
+ self.assertEqual(p_xr[0], f1.name)
+ self.assertEqual(p_xr[1], f2.name)
+ self.assertEqual(p_xr[2], sym1)
+ self.assertEqual(p_xr[3], sym2)
+ self.assertEqual(p_xr[4], f3.name)
+
+ # Clean up
+ os.unlink(sym1)
+ os.unlink(sym2)
+
+ # Make sure we raise an exception if we don't get acceptable input
+ self.assertRaises(AttributeError, extend_realpaths, "str")
+ self.assertRaises(AttributeError, extend_realpaths, set())
def test_main():
- suite = unittest.TestLoader()
- suite.loadTestsFromTestCase(TestFileOwner)
- unittest.TextTestRunner(verbosity=2).run(suite)
+ suite = unittest.TestLoader()
+ suite.loadTestsFromTestCase(TestFileOwner)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+
+
test_main.__test__ = False
-if __name__ == '__main__':
- test_main()
+if __name__ == "__main__":
+ test_main()
diff --git a/pym/gentoolkit/test/test_keyword.py b/pym/gentoolkit/test/test_keyword.py
index 8ba5e30..5ded638 100644
--- a/pym/gentoolkit/test/test_keyword.py
+++ b/pym/gentoolkit/test/test_keyword.py
@@ -2,49 +2,62 @@ import unittest
from gentoolkit import keyword
-class TestGentoolkitKeyword(unittest.TestCase):
- def test_compare_strs(self):
- compare_strs = keyword.compare_strs
-
- # Test ordering of keyword strings
- version_tests = [
- # different archs
- ('amd64', 'x86'),
- # stable vs. unstable
- ('amd64-linux', '~amd64-linux'),
- # different OSes
- ('~x86-linux', '~x86-solaris'),
- # OS vs. no OS
- ('x86', '~amd64-linux')
- ]
- # Check less than
- for vt in version_tests:
- self.assertTrue(compare_strs(vt[0], vt[1]) == -1)
- # Check greater than
- for vt in version_tests:
- self.assertTrue(compare_strs(vt[1], vt[0]) == 1)
- # Check equal
- vt = ('~amd64-linux', '~amd64-linux')
- self.assertTrue(compare_strs(vt[0], vt[1]) == 0)
-
- kwds_presort = [
- '~amd64', '~amd64-linux', '~ppc', '~ppc-macos', '~x86',
- '~x86-linux', '~x86-macos', '~x86-solaris'
- ]
- kwds_postsort = [
- '~amd64', '~ppc', '~x86', '~amd64-linux', '~x86-linux',
- '~ppc-macos', '~x86-macos', '~x86-solaris'
- ]
- self.assertEqual(sorted(kwds_presort, key = keyword.Keyword), kwds_postsort)
+class TestGentoolkitKeyword(unittest.TestCase):
+ def test_compare_strs(self):
+ compare_strs = keyword.compare_strs
+
+ # Test ordering of keyword strings
+ version_tests = [
+ # different archs
+ ("amd64", "x86"),
+ # stable vs. unstable
+ ("amd64-linux", "~amd64-linux"),
+ # different OSes
+ ("~x86-linux", "~x86-solaris"),
+ # OS vs. no OS
+ ("x86", "~amd64-linux"),
+ ]
+ # Check less than
+ for vt in version_tests:
+ self.assertTrue(compare_strs(vt[0], vt[1]) == -1)
+ # Check greater than
+ for vt in version_tests:
+ self.assertTrue(compare_strs(vt[1], vt[0]) == 1)
+ # Check equal
+ vt = ("~amd64-linux", "~amd64-linux")
+ self.assertTrue(compare_strs(vt[0], vt[1]) == 0)
+
+ kwds_presort = [
+ "~amd64",
+ "~amd64-linux",
+ "~ppc",
+ "~ppc-macos",
+ "~x86",
+ "~x86-linux",
+ "~x86-macos",
+ "~x86-solaris",
+ ]
+ kwds_postsort = [
+ "~amd64",
+ "~ppc",
+ "~x86",
+ "~amd64-linux",
+ "~x86-linux",
+ "~ppc-macos",
+ "~x86-macos",
+ "~x86-solaris",
+ ]
+ self.assertEqual(sorted(kwds_presort, key=keyword.Keyword), kwds_postsort)
def test_main():
- suite = unittest.TestLoader().loadTestsFromTestCase(
- TestGentoolkitKeyword)
- unittest.TextTestRunner(verbosity=2).run(suite)
+ suite = unittest.TestLoader().loadTestsFromTestCase(TestGentoolkitKeyword)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+
+
test_main.__test__ = False
-if __name__ == '__main__':
- test_main()
+if __name__ == "__main__":
+ test_main()
diff --git a/pym/gentoolkit/test/test_profile.py b/pym/gentoolkit/test/test_profile.py
index f91de6d..04d4d7b 100644
--- a/pym/gentoolkit/test/test_profile.py
+++ b/pym/gentoolkit/test/test_profile.py
@@ -10,52 +10,52 @@ import unittest
from gentoolkit.profile import load_profile_data
-TESTDIR = os.path.join(os.path.dirname(__file__), '../ekeyword/tests')
+TESTDIR = os.path.join(os.path.dirname(__file__), "../ekeyword/tests")
class TestLoadProfileData(unittest.TestCase):
- """Tests for load_profile_data"""
-
- def _test(self, subdir):
- portdir = os.path.join(TESTDIR, 'profiles', subdir)
- return load_profile_data(portdir=portdir)
-
- def testLoadBoth(self):
- """Test loading both arch.list and profiles.desc"""
- ret = self._test('both')
- self.assertIn('arm', ret)
- self.assertEqual(ret['arm'], ('stable', 'arch'))
- self.assertIn('arm64', ret)
- self.assertEqual(ret['arm64'], ('exp', 'arch'))
-
- def testLoadArchOnly(self):
- """Test loading only arch.list"""
- ret = self._test('arch-only')
- self.assertIn('arm', ret)
- self.assertEqual(ret['arm'], (None, 'arch'))
- self.assertIn('x86-solaris', ret)
-
- def testLoadProfilesOnly(self):
- """Test loading only profiles.desc"""
- ret = self._test('profiles-only')
- self.assertIn('arm', ret)
- self.assertEqual(ret['arm'], ('stable', 'arch'))
- self.assertIn('arm64', ret)
- self.assertEqual(ret['arm64'], ('exp', 'arch'))
-
- def testLoadArchesDesc(self):
- """Test loading arch.list, arches.desc and profiles.desc"""
- ret = self._test('arches-desc')
- self.assertIn('arm', ret)
- self.assertEqual(ret['arm'], ('stable', 'arch'))
- self.assertIn('arm64', ret)
- self.assertEqual(ret['arm64'], ('exp', 'arch'))
- self.assertIn('alpha', ret)
- self.assertEqual(ret['alpha'], ('stable', '~arch'))
- self.assertIn('sparc-fbsd', ret)
- self.assertEqual(ret['sparc-fbsd'], ('exp', '~arch'))
-
- def testLoadNone(self):
- """Test running when neither files exists"""
- ret = self._test('none')
- self.assertEqual(ret, {})
+ """Tests for load_profile_data"""
+
+ def _test(self, subdir):
+ portdir = os.path.join(TESTDIR, "profiles", subdir)
+ return load_profile_data(portdir=portdir)
+
+ def testLoadBoth(self):
+ """Test loading both arch.list and profiles.desc"""
+ ret = self._test("both")
+ self.assertIn("arm", ret)
+ self.assertEqual(ret["arm"], ("stable", "arch"))
+ self.assertIn("arm64", ret)
+ self.assertEqual(ret["arm64"], ("exp", "arch"))
+
+ def testLoadArchOnly(self):
+ """Test loading only arch.list"""
+ ret = self._test("arch-only")
+ self.assertIn("arm", ret)
+ self.assertEqual(ret["arm"], (None, "arch"))
+ self.assertIn("x86-solaris", ret)
+
+ def testLoadProfilesOnly(self):
+ """Test loading only profiles.desc"""
+ ret = self._test("profiles-only")
+ self.assertIn("arm", ret)
+ self.assertEqual(ret["arm"], ("stable", "arch"))
+ self.assertIn("arm64", ret)
+ self.assertEqual(ret["arm64"], ("exp", "arch"))
+
+ def testLoadArchesDesc(self):
+ """Test loading arch.list, arches.desc and profiles.desc"""
+ ret = self._test("arches-desc")
+ self.assertIn("arm", ret)
+ self.assertEqual(ret["arm"], ("stable", "arch"))
+ self.assertIn("arm64", ret)
+ self.assertEqual(ret["arm64"], ("exp", "arch"))
+ self.assertIn("alpha", ret)
+ self.assertEqual(ret["alpha"], ("stable", "~arch"))
+ self.assertIn("sparc-fbsd", ret)
+ self.assertEqual(ret["sparc-fbsd"], ("exp", "~arch"))
+
+ def testLoadNone(self):
+ """Test running when neither files exists"""
+ ret = self._test("none")
+ self.assertEqual(ret, {})
diff --git a/pym/gentoolkit/test/test_query.py b/pym/gentoolkit/test/test_query.py
index 8eb0159..6b8cf14 100644
--- a/pym/gentoolkit/test/test_query.py
+++ b/pym/gentoolkit/test/test_query.py
@@ -5,99 +5,96 @@ from gentoolkit import errors
class TestQuery(unittest.TestCase):
-
- def setUp(self):
- pass
-
- def tearDown(self):
- pass
-
- def test_init(self):
- # valid queries must have at least one ascii letter or digit or
- # '*'
- invalid_queries = [
- '',
- '/',
- ]
- for q in invalid_queries:
- self.assertRaises(errors.GentoolkitInvalidPackage,
- query.Query, q
- )
-
- q1 = query.Query('gentoolkit')
- q1_tests = [
- (q1.query, 'gentoolkit'),
- (q1.is_regex, False),
- (q1.repo_filter, None),
- (q1.query_type, "simple")
- ]
- for t in q1_tests:
- self.assertEqual(t[0], t[1])
-
- q2 = query.Query('gentoolkit-.*', is_regex=True)
- q2_tests = [
- (q2.query, 'gentoolkit-.*'),
- (q2.is_regex, True),
- (q2.repo_filter, None),
- (q2.query_type, "complex")
- ]
- for t in q2_tests:
- self.assertEqual(t[0], t[1])
-
- q3 = query.Query('*::gentoo')
- q3_tests = [
- (q3.query, '*'),
- (q3.is_regex, False),
- (q3.repo_filter, 'gentoo'),
- (q3.query_type, "complex")
- ]
- for t in q3_tests:
- self.assertEqual(t[0], t[1])
-
- q4 = query.Query('gcc:4.3')
- q4_tests = [
- (q4.query, 'gcc:4.3'),
- (q4.is_regex, False),
- (q4.repo_filter, None),
- (q4.query_type, "simple")
- ]
- for t in q4_tests:
- self.assertEqual(t[0], t[1])
-
- q5 = query.Query('@system')
- q5_tests = [
- (q5.query, '@system'),
- (q5.is_regex, False),
- (q5.repo_filter, None),
- (q5.query_type, "set")
- ]
- for t in q5_tests:
- self.assertEqual(t[0], t[1])
-
- def test_uses_globbing(self):
- globbing_tests = [
- ('sys-apps/portage-2.1.6.13', False),
- ('>=sys-apps/portage-2.1.6.13', False),
- ('<=sys-apps/portage-2.1.6.13', False),
- ('~sys-apps/portage-2.1.6.13', False),
- ('=sys-apps/portage-2*', False),
- ('sys-*/*-2.1.6.13', True),
- ('sys-app?/portage-2.1.6.13', True),
- ('sys-apps/[bp]ortage-2.1.6.13', True),
- ('sys-apps/[!p]ortage*', True)
- ]
-
- for gt in globbing_tests:
- self.assertTrue(
- query.Query(gt[0]).uses_globbing() == gt[1]
- )
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def test_init(self):
+ # valid queries must have at least one ascii letter or digit or
+ # '*'
+ invalid_queries = [
+ "",
+ "/",
+ ]
+ for q in invalid_queries:
+ self.assertRaises(errors.GentoolkitInvalidPackage, query.Query, q)
+
+ q1 = query.Query("gentoolkit")
+ q1_tests = [
+ (q1.query, "gentoolkit"),
+ (q1.is_regex, False),
+ (q1.repo_filter, None),
+ (q1.query_type, "simple"),
+ ]
+ for t in q1_tests:
+ self.assertEqual(t[0], t[1])
+
+ q2 = query.Query("gentoolkit-.*", is_regex=True)
+ q2_tests = [
+ (q2.query, "gentoolkit-.*"),
+ (q2.is_regex, True),
+ (q2.repo_filter, None),
+ (q2.query_type, "complex"),
+ ]
+ for t in q2_tests:
+ self.assertEqual(t[0], t[1])
+
+ q3 = query.Query("*::gentoo")
+ q3_tests = [
+ (q3.query, "*"),
+ (q3.is_regex, False),
+ (q3.repo_filter, "gentoo"),
+ (q3.query_type, "complex"),
+ ]
+ for t in q3_tests:
+ self.assertEqual(t[0], t[1])
+
+ q4 = query.Query("gcc:4.3")
+ q4_tests = [
+ (q4.query, "gcc:4.3"),
+ (q4.is_regex, False),
+ (q4.repo_filter, None),
+ (q4.query_type, "simple"),
+ ]
+ for t in q4_tests:
+ self.assertEqual(t[0], t[1])
+
+ q5 = query.Query("@system")
+ q5_tests = [
+ (q5.query, "@system"),
+ (q5.is_regex, False),
+ (q5.repo_filter, None),
+ (q5.query_type, "set"),
+ ]
+ for t in q5_tests:
+ self.assertEqual(t[0], t[1])
+
+ def test_uses_globbing(self):
+ globbing_tests = [
+ ("sys-apps/portage-2.1.6.13", False),
+ (">=sys-apps/portage-2.1.6.13", False),
+ ("<=sys-apps/portage-2.1.6.13", False),
+ ("~sys-apps/portage-2.1.6.13", False),
+ ("=sys-apps/portage-2*", False),
+ ("sys-*/*-2.1.6.13", True),
+ ("sys-app?/portage-2.1.6.13", True),
+ ("sys-apps/[bp]ortage-2.1.6.13", True),
+ ("sys-apps/[!p]ortage*", True),
+ ]
+
+ for gt in globbing_tests:
+ self.assertTrue(query.Query(gt[0]).uses_globbing() == gt[1])
def test_main():
- suite = unittest.TestLoader().loadTestsFromTestCase(TestQuery)
- unittest.TextTestRunner(verbosity=2).run(suite)
+ suite = unittest.TestLoader().loadTestsFromTestCase(TestQuery)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+
+
test_main.__test__ = False
-if __name__ == '__main__':
- test_main()
+if __name__ == "__main__":
+ test_main()
diff --git a/pym/gentoolkit/test/test_syntax.py b/pym/gentoolkit/test/test_syntax.py
index 7a990ca..525bcc1 100644
--- a/pym/gentoolkit/test/test_syntax.py
+++ b/pym/gentoolkit/test/test_syntax.py
@@ -2,36 +2,36 @@ import unittest
import py_compile
import os
+
osp = os.path
"""Does a basic syntax check by compiling all modules. From Portage."""
pym_dirs = os.walk(osp.dirname(osp.dirname(osp.dirname(__file__))))
-blacklist_dirs = frozenset(('.svn', 'test'))
+blacklist_dirs = frozenset((".svn", "test"))
-class TestForSyntaxErrors(unittest.TestCase):
- def test_compileability(self):
- compileables = []
- for thisdir, subdirs, files in pym_dirs:
- if os.path.basename(thisdir) in blacklist_dirs:
- continue
- compileables.extend([
- osp.join(thisdir, f)
- for f in files
- if osp.splitext(f)[1] == '.py'
- ])
+class TestForSyntaxErrors(unittest.TestCase):
+ def test_compileability(self):
+ compileables = []
+ for thisdir, subdirs, files in pym_dirs:
+ if os.path.basename(thisdir) in blacklist_dirs:
+ continue
+ compileables.extend(
+ [osp.join(thisdir, f) for f in files if osp.splitext(f)[1] == ".py"]
+ )
- for c in compileables:
- py_compile.compile(c, doraise=True)
+ for c in compileables:
+ py_compile.compile(c, doraise=True)
def test_main():
- suite = unittest.TestLoader().loadTestsFromTestCase(
- TestForSyntaxErrors)
- unittest.TextTestRunner(verbosity=2).run(suite)
+ suite = unittest.TestLoader().loadTestsFromTestCase(TestForSyntaxErrors)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+
+
test_main.__test__ = False
-if __name__ == '__main__':
- test_main()
+if __name__ == "__main__":
+ test_main()
diff --git a/pym/gentoolkit/textwrap_.py b/pym/gentoolkit/textwrap_.py
index 07c0831..fd28c6a 100644
--- a/pym/gentoolkit/textwrap_.py
+++ b/pym/gentoolkit/textwrap_.py
@@ -5,95 +5,97 @@ prevent the splitting of ANSI colors as well as package names and versions."""
import re
import textwrap
+
class TextWrapper(textwrap.TextWrapper):
- """Ignore ANSI escape codes while wrapping text"""
-
- def _split(self, text):
- """_split(text : string) -> [string]
-
- Split the text to wrap into indivisible chunks.
- """
- # Only split on whitespace to avoid mangling ANSI escape codes or
- # package names.
- wordsep_re = re.compile(r'(\s+)')
- chunks = wordsep_re.split(text)
- chunks = [x for x in chunks if x is not None]
- return chunks
-
- def _wrap_chunks(self, chunks):
- """_wrap_chunks(chunks : [string]) -> [string]
-
- Wrap a sequence of text chunks and return a list of lines of
- length 'self.width' or less. (If 'break_long_words' is false,
- some lines may be longer than this.) Chunks correspond roughly
- to words and the whitespace between them: each chunk is
- indivisible (modulo 'break_long_words'), but a line break can
- come between any two chunks. Chunks should not have internal
- whitespace; ie. a chunk is either all whitespace or a "word".
- Whitespace chunks will be removed from the beginning and end of
- lines, but apart from that whitespace is preserved.
- """
- lines = []
- if self.width <= 0:
- raise ValueError("invalid width %r (must be > 0)" % self.width)
-
- # Arrange in reverse order so items can be efficiently popped
- # from a stack of chunks.
- chunks.reverse()
-
- # Regex to strip ANSI escape codes. It's only used for the
- # length calculations of indent and each chuck.
- ansi_re = re.compile(r'\x1b\[[0-9;]*m')
-
- while chunks:
-
- # Start the list of chunks that will make up the current line.
- # cur_len is just the length of all the chunks in cur_line.
- cur_line = []
- cur_len = 0
-
- # Figure out which static string will prefix this line.
- if lines:
- indent = self.subsequent_indent
- else:
- indent = self.initial_indent
-
- # Maximum width for this line. Ingore ANSI escape codes.
- width = self.width - len(re.sub(ansi_re, '', indent))
-
- # First chunk on line is whitespace -- drop it, unless this
- # is the very beginning of the text (ie. no lines started yet).
- if chunks[-1].strip() == '' and lines:
- del chunks[-1]
-
- while chunks:
- # Ignore ANSI escape codes.
- chunk_len = len(re.sub(ansi_re, '', chunks[-1]))
-
- # Can at least squeeze this chunk onto the current line.
- if cur_len + chunk_len <= width:
- cur_line.append(chunks.pop())
- cur_len += chunk_len
-
- # Nope, this line is full.
- else:
- break
-
- # The current line is full, and the next chunk is too big to
- # fit on *any* line (not just this one).
- # Ignore ANSI escape codes.
- if chunks and len(re.sub(ansi_re, '', chunks[-1])) > width:
- self._handle_long_word(chunks, cur_line, cur_len, width)
-
- # If the last chunk on this line is all whitespace, drop it.
- if cur_line and cur_line[-1].strip() == '':
- del cur_line[-1]
-
- # Convert current line back to a string and store it in list
- # of all lines (return value).
- if cur_line:
- lines.append(indent + ''.join(cur_line))
-
- return lines
+ """Ignore ANSI escape codes while wrapping text"""
+
+ def _split(self, text):
+ """_split(text : string) -> [string]
+
+ Split the text to wrap into indivisible chunks.
+ """
+ # Only split on whitespace to avoid mangling ANSI escape codes or
+ # package names.
+ wordsep_re = re.compile(r"(\s+)")
+ chunks = wordsep_re.split(text)
+ chunks = [x for x in chunks if x is not None]
+ return chunks
+
+ def _wrap_chunks(self, chunks):
+ """_wrap_chunks(chunks : [string]) -> [string]
+
+ Wrap a sequence of text chunks and return a list of lines of
+ length 'self.width' or less. (If 'break_long_words' is false,
+ some lines may be longer than this.) Chunks correspond roughly
+ to words and the whitespace between them: each chunk is
+ indivisible (modulo 'break_long_words'), but a line break can
+ come between any two chunks. Chunks should not have internal
+ whitespace; ie. a chunk is either all whitespace or a "word".
+ Whitespace chunks will be removed from the beginning and end of
+ lines, but apart from that whitespace is preserved.
+ """
+ lines = []
+ if self.width <= 0:
+ raise ValueError("invalid width %r (must be > 0)" % self.width)
+
+ # Arrange in reverse order so items can be efficiently popped
+ # from a stack of chunks.
+ chunks.reverse()
+
+ # Regex to strip ANSI escape codes. It's only used for the
+ # length calculations of indent and each chuck.
+ ansi_re = re.compile(r"\x1b\[[0-9;]*m")
+
+ while chunks:
+
+ # Start the list of chunks that will make up the current line.
+ # cur_len is just the length of all the chunks in cur_line.
+ cur_line = []
+ cur_len = 0
+
+ # Figure out which static string will prefix this line.
+ if lines:
+ indent = self.subsequent_indent
+ else:
+ indent = self.initial_indent
+
+ # Maximum width for this line. Ingore ANSI escape codes.
+ width = self.width - len(re.sub(ansi_re, "", indent))
+
+ # First chunk on line is whitespace -- drop it, unless this
+ # is the very beginning of the text (ie. no lines started yet).
+ if chunks[-1].strip() == "" and lines:
+ del chunks[-1]
+
+ while chunks:
+ # Ignore ANSI escape codes.
+ chunk_len = len(re.sub(ansi_re, "", chunks[-1]))
+
+ # Can at least squeeze this chunk onto the current line.
+ if cur_len + chunk_len <= width:
+ cur_line.append(chunks.pop())
+ cur_len += chunk_len
+
+ # Nope, this line is full.
+ else:
+ break
+
+ # The current line is full, and the next chunk is too big to
+ # fit on *any* line (not just this one).
+ # Ignore ANSI escape codes.
+ if chunks and len(re.sub(ansi_re, "", chunks[-1])) > width:
+ self._handle_long_word(chunks, cur_line, cur_len, width)
+
+ # If the last chunk on this line is all whitespace, drop it.
+ if cur_line and cur_line[-1].strip() == "":
+ del cur_line[-1]
+
+ # Convert current line back to a string and store it in list
+ # of all lines (return value).
+ if cur_line:
+ lines.append(indent + "".join(cur_line))
+
+ return lines
+
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/versionmatch.py b/pym/gentoolkit/versionmatch.py
index 9287c13..48c12ad 100644
--- a/pym/gentoolkit/versionmatch.py
+++ b/pym/gentoolkit/versionmatch.py
@@ -21,112 +21,109 @@ from gentoolkit.cpv import CPV
# Classes
# =======
+
class VersionMatch:
- """Gentoo version comparison object from pkgcore.ebuild.atom_restricts.
-
- Any overriding of this class *must* maintain numerical order of
- self.vals, see intersect for reason why. vals also must be a tuple.
- """
- _convert_op2int = {(-1,):"<", (-1, 0): "<=", (0,):"=",
- (0, 1):">=", (1,):">"}
-
- _convert_int2op = dict([(v, k) for k, v in _convert_op2int.items()])
-
- def __init__(self, cpv, op='='):
- """Initialize a VersionMatch instance.
-
- @type cpv: L{gentoolkit.cpv.CPV}
- @param cpv: cpv object
- @type op: str
- @keyword op: operator
- """
-
- if not isinstance(cpv, (CPV, self.__class__)):
- err = "cpv must be a gentoolkit.cpv.CPV "
- err += "or gentoolkit.versionmatch.VersionMatch instance"
- raise ValueError(err)
- self.cpv = cpv
- self.operator = op
- self.version = cpv.version
- self.revision = cpv.revision
- self.fullversion = cpv.fullversion
-
- if self.operator != "~" and self.operator not in self._convert_int2op:
- raise errors.GentoolkitInvalidVersion(
- "invalid operator '%s'" % self.operator)
-
- if self.operator == "~":
- if not self.version:
- raise errors.GentoolkitInvalidVersion(
- "for ~ op, ver must be specified")
- self.droprevision = True
- self.values = (0,)
- else:
- self.droprevision = False
- self.values = self._convert_int2op[self.operator]
-
- def match(self, other):
- """See whether a passed in VersionMatch or CPV instance matches self.
-
- Example usage:
- >>> from gentoolkit.versionmatch import VersionMatch
- >>> from gentoolkit.cpv import CPV
- >>> VersionMatch(CPV('foo/bar-1.5'), op='>').match(
- ... VersionMatch(CPV('foo/bar-2.0')))
- True
-
- @type other: gentoolkit.versionmatch.VersionMatch OR
- gentoolkit.cpv.CPV
- @param other: version to compare with self's version
- @rtype: bool
- """
-
- if self.droprevision:
- ver1, ver2 = self.version, other.version
- else:
- ver1, ver2 = self.fullversion, other.fullversion
-
- return vercmp(ver2, ver1) in self.values
-
- def __str__(self):
- operator = self._convert_op2int[self.values]
-
- if self.droprevision or not self.revision:
- return "ver %s %s" % (operator, self.version)
- return "ver-rev %s %s-%s" % (
- operator, self.version, self.revision
- )
-
- def __repr__(self):
- return "<%s %r>" % (self.__class__.__name__, str(self))
-
- @staticmethod
- def _convert_ops(inst):
- if inst.droprevision:
- return inst.values
- return tuple(sorted(set((-1, 0, 1)).difference(inst.values)))
-
- def __eq__(self, other):
- if self is other:
- return True
- if isinstance(other, self.__class__):
- if (self.droprevision != other.droprevision or
- self.version != other.version or
- self.revision != other.revision):
- return False
- return self._convert_ops(self) == self._convert_ops(other)
-
- return False
-
- def __ne__(self, other):
- return not self == other
-
- def __hash__(self):
- return hash((
- self.droprevision,
- self.version,
- self.revision,
- self.values
- ))
+ """Gentoo version comparison object from pkgcore.ebuild.atom_restricts.
+
+ Any overriding of this class *must* maintain numerical order of
+ self.vals, see intersect for reason why. vals also must be a tuple.
+ """
+
+ _convert_op2int = {(-1,): "<", (-1, 0): "<=", (0,): "=", (0, 1): ">=", (1,): ">"}
+
+ _convert_int2op = dict([(v, k) for k, v in _convert_op2int.items()])
+
+ def __init__(self, cpv, op="="):
+ """Initialize a VersionMatch instance.
+
+ @type cpv: L{gentoolkit.cpv.CPV}
+ @param cpv: cpv object
+ @type op: str
+ @keyword op: operator
+ """
+
+ if not isinstance(cpv, (CPV, self.__class__)):
+ err = "cpv must be a gentoolkit.cpv.CPV "
+ err += "or gentoolkit.versionmatch.VersionMatch instance"
+ raise ValueError(err)
+ self.cpv = cpv
+ self.operator = op
+ self.version = cpv.version
+ self.revision = cpv.revision
+ self.fullversion = cpv.fullversion
+
+ if self.operator != "~" and self.operator not in self._convert_int2op:
+ raise errors.GentoolkitInvalidVersion(
+ "invalid operator '%s'" % self.operator
+ )
+
+ if self.operator == "~":
+ if not self.version:
+ raise errors.GentoolkitInvalidVersion("for ~ op, ver must be specified")
+ self.droprevision = True
+ self.values = (0,)
+ else:
+ self.droprevision = False
+ self.values = self._convert_int2op[self.operator]
+
+ def match(self, other):
+ """See whether a passed in VersionMatch or CPV instance matches self.
+
+ Example usage:
+ >>> from gentoolkit.versionmatch import VersionMatch
+ >>> from gentoolkit.cpv import CPV
+ >>> VersionMatch(CPV('foo/bar-1.5'), op='>').match(
+ ... VersionMatch(CPV('foo/bar-2.0')))
+ True
+
+ @type other: gentoolkit.versionmatch.VersionMatch OR
+ gentoolkit.cpv.CPV
+ @param other: version to compare with self's version
+ @rtype: bool
+ """
+
+ if self.droprevision:
+ ver1, ver2 = self.version, other.version
+ else:
+ ver1, ver2 = self.fullversion, other.fullversion
+
+ return vercmp(ver2, ver1) in self.values
+
+ def __str__(self):
+ operator = self._convert_op2int[self.values]
+
+ if self.droprevision or not self.revision:
+ return "ver %s %s" % (operator, self.version)
+ return "ver-rev %s %s-%s" % (operator, self.version, self.revision)
+
+ def __repr__(self):
+ return "<%s %r>" % (self.__class__.__name__, str(self))
+
+ @staticmethod
+ def _convert_ops(inst):
+ if inst.droprevision:
+ return inst.values
+ return tuple(sorted(set((-1, 0, 1)).difference(inst.values)))
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ if isinstance(other, self.__class__):
+ if (
+ self.droprevision != other.droprevision
+ or self.version != other.version
+ or self.revision != other.revision
+ ):
+ return False
+ return self._convert_ops(self) == self._convert_ops(other)
+
+ return False
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash((self.droprevision, self.version, self.revision, self.values))
+
# vim: set ts=4 sw=4 tw=79: