aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS2
-rw-r--r--pylintrc3
-rw-r--r--pym/gentoolkit/atom.py186
-rw-r--r--pym/gentoolkit/cpv.py16
-rw-r--r--pym/gentoolkit/equery/__init__.py6
-rw-r--r--pym/gentoolkit/test/equery/test_init.py6
-rw-r--r--pym/gentoolkit/test/test_atom.py148
-rw-r--r--pym/gentoolkit/test/test_helpers.py2
-rw-r--r--pym/gentoolkit/versionmatch.py9
9 files changed, 350 insertions, 28 deletions
diff --git a/AUTHORS b/AUTHORS
index 5b074e6..c8b89aa 100644
--- 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>
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 <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()
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