Merge with rev 120 from the genscripts repo
authorfuzzyray <fuzzyray@gentoo.org>
Thu, 10 Dec 2009 15:21:04 +0000 (15:21 -0000)
committerfuzzyray <fuzzyray@gentoo.org>
Thu, 10 Dec 2009 15:21:04 +0000 (15:21 -0000)
svn path=/trunk/gentoolkit/; revision=712

AUTHORS
pylintrc
pym/gentoolkit/atom.py
pym/gentoolkit/cpv.py
pym/gentoolkit/equery/__init__.py
pym/gentoolkit/test/equery/test_init.py
pym/gentoolkit/test/test_atom.py [new file with mode: 0644]
pym/gentoolkit/test/test_helpers.py
pym/gentoolkit/versionmatch.py

diff --git a/AUTHORS b/AUTHORS
index 5b074e6d07d43ab67c7af843dd2ed8a8b3bcf6d5..c8b89aa3574ca41bc84a8c111623060cdb710f28 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -13,7 +13,7 @@
 
 * equery
   Original author: Karl Trygve Kalleberg <karltk@gentoo.org>
-  Modular redesign: Douglas Anderson <douglasjanderson@gmail.com>
+  0.3.0 author: Douglas Anderson <douglasjanderson@gmail.com>
 
 * eread
   Original author: Donnie Berkholz <dberkholz@gentoo.org>
index 9a08a7c0eaef2627ddabec44653861d929340cf9..863a3f8a9453dfeb9245adc89cc19b40c4d8749b 100644 (file)
--- 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
index 749b58517f30f540903f2950aa67fab5fc5e7686..d7823a9acffb15e19c271bc50723769a2d526862 100644 (file)
@@ -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
index 7dc54e5859316fe3fc2dc015f20a0358c1da3c82..e5b4a486c799fb45aaafd0be703f71db17604fbf 100644 (file)
@@ -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))
index 13ff6bacdd4b7ea91c121be883a502515c9dee53..d99395360ef95c5f1cd9475228cee62a015d0b90 100644 (file)
@@ -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)
index d135aa51522671317f4b7f3c3b548a620abe077b..98e2648e4e838b26eae11b1eaeafd7887e38653e 100644 (file)
@@ -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 (file)
index 0000000..ea85e2a
--- /dev/null
@@ -0,0 +1,148 @@
+# Copyright(c) 2009, Gentoo Foundation
+# Copyright: 2006-2008 Brian Harring <ferringb@gmail.com>
+#
+# 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'), 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', 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_main():
+       test_support.run_unittest(TestGentoolkitAtom)
+
+if __name__ == '__main__':
+       test_main()
index 22509b706d9a50fd5144591a078f6fdb658ccb23..e46e03bc5332a435fdf14f71fce1fe68275d82ea 100644 (file)
@@ -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,
index 12f67326c4b2bc5ab22f9bfa4e0b5b4575d935ab..018a531d6924e60d8043f4066a498ded13a353a4 100644 (file)
@@ -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