summaryrefslogtreecommitdiff
path: root/pym
diff options
context:
space:
mode:
Diffstat (limited to 'pym')
-rw-r--r--pym/gentoolkit/equery/__init__.py4
-rw-r--r--pym/gentoolkit/equery/changes.py2
-rw-r--r--pym/gentoolkit/equery/depends.py2
-rw-r--r--pym/gentoolkit/equery/meta.py37
-rw-r--r--pym/gentoolkit/package.py86
-rw-r--r--pym/gentoolkit/pprinter.py56
-rw-r--r--pym/gentoolkit/query.py34
-rw-r--r--pym/gentoolkit/test/test_cpv.py59
8 files changed, 206 insertions, 74 deletions
diff --git a/pym/gentoolkit/equery/__init__.py b/pym/gentoolkit/equery/__init__.py
index d993953..07eb3dd 100644
--- a/pym/gentoolkit/equery/__init__.py
+++ b/pym/gentoolkit/equery/__init__.py
@@ -87,9 +87,9 @@ def print_help(with_description=True):
print pp.command("modules") + " (" + pp.command("short name") + ")"
print format_options((
(" (b)elongs", "list what package FILES belong to"),
- (" (c)hanges", "list changelog entries for PKG"),
+ (" (c)hanges", "list changelog entries for ATOM"),
(" chec(k)", "verify checksums and timestamps for PKG"),
- (" (d)epends", "list all packages directly depending on 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)asuse", "list all packages that have USE flag"),
diff --git a/pym/gentoolkit/equery/changes.py b/pym/gentoolkit/equery/changes.py
index ef35ec9..28611f9 100644
--- a/pym/gentoolkit/equery/changes.py
+++ b/pym/gentoolkit/equery/changes.py
@@ -4,7 +4,7 @@
#
# $Header: $
-"""Displays the ChangeLog entry for the latest installable version of a package"""
+"""Displays the ChangeLog entry for the latest installable version of an atom"""
# Move to Imports sections when Python 2.6 is stable
from __future__ import with_statement
diff --git a/pym/gentoolkit/equery/depends.py b/pym/gentoolkit/equery/depends.py
index b60a0cc..18e08af 100644
--- a/pym/gentoolkit/equery/depends.py
+++ b/pym/gentoolkit/equery/depends.py
@@ -4,7 +4,7 @@
#
# $Header: $
-"""List all packages that depend on a given query"""
+"""List all packages that depend on a atom given query"""
__docformat__ = 'epytext'
diff --git a/pym/gentoolkit/equery/meta.py b/pym/gentoolkit/equery/meta.py
index 763e30d..1fc8964 100644
--- a/pym/gentoolkit/equery/meta.py
+++ b/pym/gentoolkit/equery/meta.py
@@ -76,9 +76,11 @@ def print_help(with_description=True, with_usage=True):
def filter_keywords(matches):
- """Filter non-unique keywords per slot.
+ """Filters non-unique keywords per slot.
- This view apparently makes version bumps easier for package maintainers.
+ 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
@@ -88,19 +90,31 @@ def filter_keywords(matches):
'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'))
+ 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(keywords)
+ slot_map[slot].update(del_archmask(add_unstable(keywords)))
except KeyError:
- slot_map[slot] = set(keywords)
+ slot_map[slot] = set(del_archmask(add_unstable(keywords)))
return result
@@ -200,12 +214,15 @@ def format_keywords(keywords):
result = []
for kw in sorted(keywords):
- if kw.startswith(('~', '-')):
- # keyword (~) or arch (-) masked
- kw = pp.useflag(kw, enabled=False)
+ 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:
- # unmasked
- kw = pp.useflag(kw, enabled=True)
+ # stable
+ kw = pp.keyword(kw, stable=True, hard_masked=False)
result.append(kw)
return ' '.join(result)
diff --git a/pym/gentoolkit/package.py b/pym/gentoolkit/package.py
index 1759a8c..c020f63 100644
--- a/pym/gentoolkit/package.py
+++ b/pym/gentoolkit/package.py
@@ -9,9 +9,19 @@
"""Provides an interface to package information stored by package managers.
-The package class is the heart of much of Gentoolkit. Given a CPV
-(category/package-version string),
-TODO: finish this docstring
+The Package class is the heart of much of Gentoolkit. Given a CPV
+(category/package-version) string, it can reveal the package's status in the
+tree and VARDB (/var/db/), provide rich comparison and sorting, and expose
+important parts of Portage's back-end.
+
+Example usage:
+ >>> portage = Package('sys-apps/portage-2.1.6.13')
+ >>> portage.ebuild_path()
+ '/usr/portage/sys-apps/portage/portage-2.1.6.13.ebuild'
+ >>> portage.is_masked()
+ False
+ >>> portage.is_installed()
+ True
"""
__all__ = (
@@ -40,7 +50,7 @@ from gentoolkit.metadata import MetaData
# =======
class Package(CPV):
- """Provides methods for ascertaining the state of a given CPV."""
+ """Exposes the state of a given CPV."""
def __init__(self, cpv):
if isinstance(cpv, CPV):
@@ -86,19 +96,6 @@ class Package(CPV):
def __str__(self):
return str(self.cpv)
- def _get_trees(self):
- """Return dbapi objects for each repository that contains self."""
-
- result = []
- if self.is_installed():
- result.append(VARDB)
- if self.exists():
- result.append(PORTDB)
- if not result:
- raise errors.GentoolkitFatalError("Could not find package tree")
-
- return result
-
@property
def metadata(self):
"""Instantiate a L{gentoolkit.metadata.MetaData} object here."""
@@ -134,7 +131,7 @@ class Package(CPV):
return self._deps
- def environment(self, envvars, tree=None):
+ def environment(self, envvars, prefer_vdb=True, no_fallback=False):
"""Returns one or more of the predefined environment variables.
Available envvars are:
@@ -156,21 +153,43 @@ class Package(CPV):
@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 no_fallback: bool
+ @keyword no_fallback: query only the preferred db
@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)
"""
- if tree is None:
- tree = self._get_trees()[0]
got_string = False
if isinstance(envvars, basestring):
got_string = True
envvars = (envvars,)
- try:
- result = tree.aux_get(str(self.cpv), envvars)
- except (KeyError, errors.GentoolkitFatalError):
- err = "aux_get returned unexpected results"
- raise errors.GentoolkitFatalError(err)
+ if prefer_vdb:
+ try:
+ result = VARDB.aux_get(str(self.cpv), envvars)
+ except KeyError:
+ try:
+ if no_fallback:
+ raise KeyError
+ result = PORTDB.aux_get(str(self.cpv), envvars)
+ except KeyError:
+ err = "aux_get returned unexpected results"
+ raise errors.GentoolkitFatalError(err)
+ else:
+ try:
+ result = PORTDB.aux_get(str(self.cpv), envvars)
+ except KeyError:
+ try:
+ if no_fallback:
+ raise KeyError
+ result = VARDB.aux_get(str(self.cpv), envvars)
+ except KeyError:
+ err = "aux_get returned unexpected results"
+ raise errors.GentoolkitFatalError(err)
if got_string:
return result[0]
@@ -255,14 +274,12 @@ class Package(CPV):
return VARDB.findname(str(self.cpv))
return PORTDB.findname(str(self.cpv))
- def package_path(self):
+ def package_path(self, in_vartree=False):
"""Return the path to where the ebuilds and other files reside."""
- if self._package_path is None:
- path_split = self.ebuild_path().split(os.sep)
- self._package_path = os.sep.join(path_split[:-1])
-
- return self._package_path
+ if in_vartree:
+ return self.dblink.getpath()
+ return os.sep.join(self.ebuild_path().split(os.sep)[:-1])
def repo_id(self):
"""Using the package path, determine the repository id.
@@ -365,9 +382,14 @@ class PackageFormatter(object):
def __str__(self):
if self.do_format:
maskmodes = [' ', ' ~', ' -', 'M ', 'M~', 'M-', 'XX']
+ maskmode = maskmodes[self.format_mask_status()[0]]
return "[%(location)s] [%(mask)s] %(package)s:%(slot)s" % {
'location': self.location,
- 'mask': pp.maskflag(maskmodes[self.format_mask_status()[0]]),
+ 'mask': pp.keyword(
+ maskmode,
+ stable=not maskmode.strip(),
+ hard_masked=set(('M', 'X', '-')).intersection(maskmode)
+ ),
'package': pp.cpv(str(self.pkg.cpv)),
'slot': pp.slot(self.pkg.environment("SLOT"))
}
diff --git a/pym/gentoolkit/pprinter.py b/pym/gentoolkit/pprinter.py
index 8f619e3..bd5e6cb 100644
--- a/pym/gentoolkit/pprinter.py
+++ b/pym/gentoolkit/pprinter.py
@@ -17,7 +17,6 @@ __all__ = (
'globaloption',
'installedflag',
'localoption',
- 'maskflag',
'number',
'path',
'path_symlink',
@@ -48,84 +47,85 @@ import portage.output as output
# pylint: disable-msg=E1101
def command(string):
- """Print a program command string."""
+ """Returns a program command string."""
return output.green(string)
def cpv(string):
- """Print a category/package-<version> string."""
+ """Returns a category/package-<version> string."""
return output.green(string)
def die(err, string):
- """Print an error string and die with an error code."""
+ """Returns an error string and die with an error code."""
sys.stderr.write(error(string))
sys.exit(err)
def emph(string):
- """Print a string as emphasized."""
+ """Returns a string as emphasized."""
return output.bold(string)
def error(string):
- """Prints an error string to stderr."""
+ """Prints an error string."""
return output.red("!!! ") + string + "\n"
def globaloption(string):
- """Print a global option string, i.e. the program global options."""
+ """Returns a global option string, i.e. the program global options."""
return output.yellow(string)
-def installedflag(string):
- """Print an installed flag string"""
- return output.bold(string)
-
def localoption(string):
- """Print a local option string, i.e. the program local options."""
+ """Returns a local option string, i.e. the program local options."""
return output.green(string)
-def maskflag(string):
- """Print a masking flag string"""
- return output.red(string)
-
def number(string):
- """Print a number string"""
+ """Returns a number string."""
return output.turquoise(string)
def path(string):
- """Print a file or directory path string"""
+ """Returns a file or directory path string."""
return output.bold(string)
def path_symlink(string):
- """Print a symlink string."""
+ """Returns a symlink string."""
return output.turquoise(string)
def pkgquery(string):
- """Print a package query string."""
+ """Returns a package query string."""
return output.bold(string)
def productname(string):
- """Print a product name string, i.e. the program name."""
+ """Returns a product name string, i.e. the program name."""
return output.turquoise(string)
def regexpquery(string):
- """Print a regular expression string"""
+ """Returns a regular expression string."""
return output.bold(string)
def section(string):
- """Print a string as a section header."""
+ """Returns a string as a section header."""
return output.turquoise(string)
def slot(string):
- """Print a slot string"""
+ """Returns a slot string"""
return output.bold(string)
def subsection(string):
- """Print a string as a subsection header."""
+ """Returns a string as a subsection header."""
return output.turquoise(string)
def useflag(string, enabled=True):
- """Print a USE flag string"""
- return output.green(string) if enabled else output.blue(string)
+ """Returns a USE flag string."""
+ return output.blue(string) if enabled else output.red(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)
def warn(string):
- """Print a warning string to stderr."""
+ """Returns a warning string."""
return "!!! " + string + "\n"
# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/query.py b/pym/gentoolkit/query.py
new file mode 100644
index 0000000..24f8c18
--- /dev/null
+++ b/pym/gentoolkit/query.py
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+#
+# Copyright(c) 2004-2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header$
+
+"""Provides common methods on a package query."""
+
+__all__ = (
+ 'Query',
+)
+
+# =======
+# Imports
+# =======
+
+from gentoolkit.cpv import CPV
+#from gentoolkit.helpers import *
+
+# =======
+# Classes
+# =======
+
+class Query(CPV):
+ """Provides common methods on a package query."""
+
+ def __init__(self, cpv):
+ if isinstance(cpv, CPV):
+ self.cpv = cpv
+ else:
+ self.cpv = CPV(cpv)
+ del cpv
diff --git a/pym/gentoolkit/test/test_cpv.py b/pym/gentoolkit/test/test_cpv.py
new file mode 100644
index 0000000..9b36cc3
--- /dev/null
+++ b/pym/gentoolkit/test/test_cpv.py
@@ -0,0 +1,59 @@
+#!/usr/bin/python
+#
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header$
+
+import unittest
+from test import test_support
+
+from gentoolkit.cpv import *
+
+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)
+ 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(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_main():
+ test_support.run_unittest(TestGentoolkitCPV)
+
+if __name__ == '__main__':
+ test_main()