From: fuzzyray Date: Thu, 10 Dec 2009 15:21:04 +0000 (-0000) Subject: Merge with rev 120 from the genscripts repo X-Git-Tag: gentoolkit-0.3.0_rc10~39 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=5fe3381eba19698f3f75f4c9628aac3eb2d765ff;p=gentoolkit.git Merge with rev 120 from the genscripts repo svn path=/trunk/gentoolkit/; revision=712 --- diff --git a/AUTHORS b/AUTHORS index 5b074e6..c8b89aa 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,7 +13,7 @@ * equery Original author: Karl Trygve Kalleberg - Modular redesign: Douglas Anderson + 0.3.0 author: Douglas Anderson * eread Original author: Donnie Berkholz diff --git a/pylintrc b/pylintrc index 9a08a7c..863a3f8 100644 --- a/pylintrc +++ b/pylintrc @@ -252,7 +252,8 @@ max-args=10 max-locals=15 # Maximum number of return / yield for function / method body -max-returns=6 +# was max-returns=6 +max-returns=10 # Maximum number of branch for function / method body max-branchs=12 diff --git a/pym/gentoolkit/atom.py b/pym/gentoolkit/atom.py index 749b585..d7823a9 100644 --- a/pym/gentoolkit/atom.py +++ b/pym/gentoolkit/atom.py @@ -27,7 +27,20 @@ from gentoolkit import errors # ======= class Atom(portage.dep.Atom, CPV): - """Portage's Atom class with an improved intersects method from pkgcore. + """Portage's Atom class with an improvements from pkgcore. + + Gentoolkit's Atom is not backwards compatible with Portage's because we set + parts and combinations of parts of cpv as attributes on Atom.cpv instead of + putting them directly in Atom's namespace like Portage does, for one. + For example: + Gentoolkit.Atom: str(atom.cpv) # cpv string + atom.cpv.category # category + Portage.Atom: atom.cpv # cpv string + atom.category # category + + Also, Portage's Atom.slot is a string, whereas + Gentoolkit's Atom.slot is a tuple as in pkgcore, since multiple slots are + OK portage.dep.Atom provides the following instance variables: @@ -37,7 +50,7 @@ class Atom(portage.dep.Atom, CPV): @ivar cp: cat/pkg @type cpv: str @ivar cpv: cat/pkg-ver (if ver) - @type slot: str or None + @type slot: str or None (modified to tuple if not None) @ivar slot: slot passed in as cpv:# """ @@ -46,22 +59,141 @@ class Atom(portage.dep.Atom, CPV): 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, err: - raise errors.GentoolkitInvalidAtom(err) + except portage.exception.InvalidAtom: + raise errors.GentoolkitInvalidAtom(atom) # Make operator compatible with intersects if self.operator is None: self.operator = '=' + # Make slot a tuple if defined + # pylint screwup: + # E1101: 75:Atom.__init__: Instance of 'tuple' has no 'split' member + # pylint: disable-msg=E1101 + if self.slot is not None: + self.slot = tuple(sorted(self.slot.split(','))) + self.cpv = CPV(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 self.cpv != other.cpv: + 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 + + # 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_id, other.repo_id) + return True + + def __ne__(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 __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 self.cpv != other.cpv: + return self.cpv < other.cpv + + 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: + return self.slot < other.slot + + 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 this_use < that_use + + # Not supported by Portage Atom yet + #return cmp(self.repo_id, other.repo_id) + + 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 '' @@ -104,6 +236,34 @@ class Atom(portage.dep.Atom, CPV): return True return False + # Slot dep only matters if we both have one. If we do they + # must be identical: + if (self.slot is not None and other.slot is not None and + self.slot != other.slot): + return False + + # TODO: Uncomment when Portage's Atom supports repo + #if (self.repo_id is not None and other.repo_id is not None and + # self.repo_id != other.repo_id): + # 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: + if self.use and other.use: + # Set of flags we do not have in common: + flags = set(self.use.tokens) ^ set(other.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 @@ -142,19 +302,23 @@ class Atom(portage.dep.Atom, CPV): # If we get here at least one of us is a <, <=, > or >=: if self.operator in ('<', '<=', '>', '>='): - ranged, other = self, other - ranged.operator = self.operator + # pylint screwup: + # E0601: Using variable 'ranged' before assignment + # pylint: disable-msg=E0601 + ranged, ranged.operator = self, self.operator else: - ranged, other = other, self - ranged.operator = other.operator + 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.cpv, op=other.operator).match(ranged) and - VersionMatch(ranged.cpv, op=ranged.operator).match(other.cpv)) + return ( + VersionMatch(other.cpv, op=other.operator).match(ranged.cpv) and + VersionMatch(ranged.cpv, op=ranged.operator).match(other.cpv) + ) if other.operator == '~': # Other definitely matches its own version. If ranged also @@ -176,7 +340,7 @@ class Atom(portage.dep.Atom, CPV): if '<' in ranged.operator: # If other.revision is not defined then other does not # match anything smaller than its own fullversion: - if not other.cpv.revision: + if other.cpv.revision: return False # If other.revision is defined then we can always diff --git a/pym/gentoolkit/cpv.py b/pym/gentoolkit/cpv.py index 7dc54e5..e5b4a48 100644 --- a/pym/gentoolkit/cpv.py +++ b/pym/gentoolkit/cpv.py @@ -99,7 +99,21 @@ class CPV(object): raise TypeError("other isn't of %s type, is %s" % ( self.__class__, other.__class__) ) - return not self < other and not self == other + 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)) diff --git a/pym/gentoolkit/equery/__init__.py b/pym/gentoolkit/equery/__init__.py index 13ff6ba..d993953 100644 --- a/pym/gentoolkit/equery/__init__.py +++ b/pym/gentoolkit/equery/__init__.py @@ -39,7 +39,7 @@ from gentoolkit.textwrap_ import TextWrapper __productname__ = "equery" __authors__ = ( 'Karl Trygve Kalleberg - Original author', - 'Douglas Anderson - Modular redesign; author of meta, changes' + 'Douglas Anderson - 0.3.0 author' ) # ======= @@ -220,7 +220,7 @@ def initialize_configuration(): def main_usage(): - """Print 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:"), @@ -232,7 +232,7 @@ def main_usage(): def mod_usage(mod_name="module", arg="pkgspec", optional=False): - """Provide a consistant 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) diff --git a/pym/gentoolkit/test/equery/test_init.py b/pym/gentoolkit/test/equery/test_init.py index d135aa5..98e2648 100644 --- a/pym/gentoolkit/test/equery/test_init.py +++ b/pym/gentoolkit/test/equery/test_init.py @@ -37,12 +37,6 @@ class TestEqueryInit(unittest.TestCase): for key in unused_keys: self.failUnlessRaises(KeyError, equery.expand_module_name, key) - def test_format_timestamp(self): - # Test that a certain timetamp produces the correct formatted string - tstamp = 1257626685.6503389 - tstr = '2009-11-07 15:44:45' - self.failUnlessEqual(equery.format_timestamp(tstamp), tstr) - def test_main(): test_support.run_unittest(TestEqueryInit) diff --git a/pym/gentoolkit/test/test_atom.py b/pym/gentoolkit/test/test_atom.py new file mode 100644 index 0000000..ea85e2a --- /dev/null +++ b/pym/gentoolkit/test/test_atom.py @@ -0,0 +1,148 @@ +# Copyright(c) 2009, Gentoo Foundation +# Copyright: 2006-2008 Brian Harring +# +# License: GPL2/BSD + +# $Header$ + +import unittest +from test import test_support + +from gentoolkit.atom import * + +"""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) + c = cmp(o1, o2) + self.assertEqual(c, 0, + msg="checking cmp for %r, %r, aren't equal: got %i" % (o1, o2, c)) + self.assertEqual(o2, o1) + c = cmp(o2, o1) + self.assertEqual(c, 0, + msg="checking cmp for %r, %r,aren't equal: got %i" % (o2, o1, c)) + + def assertNotEqual2(self, o1, o2): + # is why we test the comparison *both* ways. + self.assertNotEqual(o1, o2) + c = cmp(o1, o2) + self.assertNotEqual(c, 0, + msg="checking cmp for %r, %r, not supposed to be equal, got %i" + % (o1, o2, c)) + self.assertNotEqual(o2, o1) + c = cmp(o2, o1) + self.assertNotEqual(c, 0, + msg="checking cmp for %r, %r, not supposed to be equal, got %i" + % (o2, o1, c)) + + 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')) + 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')) + self.assertEqual2(Atom('cat/pkg:2,1'), Atom('cat/pkg:2,1')) + self.assertEqual2(Atom('cat/pkg:2,1'), Atom('cat/pkg:1,2')) + 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', 'cat/pkg-2', '=cat/pkg-2*', True), + # Portage vercmp disagrees with this one: + #('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-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', 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_main(): + test_support.run_unittest(TestGentoolkitAtom) + +if __name__ == '__main__': + test_main() diff --git a/pym/gentoolkit/test/test_helpers.py b/pym/gentoolkit/test/test_helpers.py index 22509b7..e46e03b 100644 --- a/pym/gentoolkit/test/test_helpers.py +++ b/pym/gentoolkit/test/test_helpers.py @@ -51,7 +51,7 @@ class TestFileOwner(unittest.TestCase): self.failUnlessRaises(AttributeError, extend_realpaths, set()) -class TestGentoolkitHelpers2(unittest.TestCase): +class TestGentoolkitHelpers(unittest.TestCase): def test_compare_package_strings(self): # Test ordering of package strings, Portage has test for vercmp, diff --git a/pym/gentoolkit/versionmatch.py b/pym/gentoolkit/versionmatch.py index 12f6732..018a531 100644 --- a/pym/gentoolkit/versionmatch.py +++ b/pym/gentoolkit/versionmatch.py @@ -45,7 +45,7 @@ class VersionMatch(object): if not isinstance(cpv, CPV): raise ValueError("cpv must be a gentoolkit.cpv.CPV instance") - self.cpv = cpv + #self.cpv = cpv self.operator = op self.version = cpv.version self.revision = cpv.revision @@ -70,8 +70,9 @@ class VersionMatch(object): Example usage: >>> from gentoolkit.versionmatch import VersionMatch - >>> VersionMatch(op='>',ver='1.5',rev='').match( - ... VersionMatch(op='=',ver='2.0',rev='')) + >>> 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 @@ -90,7 +91,7 @@ class VersionMatch(object): def __str__(self): operator = self._convert_op2int[self.values] - if self.droprevision or not self.cpv.revision: + 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