diff options
Diffstat (limited to 'pym')
| -rw-r--r-- | pym/gentoolkit/equery/__init__.py | 4 | ||||
| -rw-r--r-- | pym/gentoolkit/equery/changes.py | 2 | ||||
| -rw-r--r-- | pym/gentoolkit/equery/depends.py | 2 | ||||
| -rw-r--r-- | pym/gentoolkit/equery/meta.py | 37 | ||||
| -rw-r--r-- | pym/gentoolkit/package.py | 86 | ||||
| -rw-r--r-- | pym/gentoolkit/pprinter.py | 56 | ||||
| -rw-r--r-- | pym/gentoolkit/query.py | 34 | ||||
| -rw-r--r-- | pym/gentoolkit/test/test_cpv.py | 59 |
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() |
