aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfuzzyray <fuzzyray@gentoo.org>2009-05-05 17:39:24 +0000
committerfuzzyray <fuzzyray@gentoo.org>2009-05-05 17:39:24 +0000
commitc819d146be6bce86d97019494173253e71b85d2f (patch)
tree200d00c2b9a420540ff9c4e0d8b3080b762fb562 /pym/gentoolkit/equery/__init__.py
parentAdd some useful informations when using $EDITOR. (diff)
downloadgentoolkit-c819d146be6bce86d97019494173253e71b85d2f.tar.gz
gentoolkit-c819d146be6bce86d97019494173253e71b85d2f.tar.bz2
gentoolkit-c819d146be6bce86d97019494173253e71b85d2f.zip
Rearrange trunk to support gentoolkit version 0.3. Split into gentoolkit, gentoolkit-dev, and deprecated. Import djanderson's work on the gentoolkit library and equery
svn path=/trunk/gentoolkit/; revision=589
Diffstat (limited to 'pym/gentoolkit/equery/__init__.py')
-rw-r--r--pym/gentoolkit/equery/__init__.py407
1 files changed, 407 insertions, 0 deletions
diff --git a/pym/gentoolkit/equery/__init__.py b/pym/gentoolkit/equery/__init__.py
new file mode 100644
index 0000000..6bb04a9
--- /dev/null
+++ b/pym/gentoolkit/equery/__init__.py
@@ -0,0 +1,407 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header: $
+
+"""Gentoo package query tool"""
+
+# Move to Imports section after Python 2.6 is stable
+from __future__ import with_statement
+
+__all__ = (
+ 'format_options',
+ 'format_package_names',
+ 'mod_usage'
+)
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import errno
+import sys
+import time
+from getopt import getopt, GetoptError
+
+import gentoolkit
+import gentoolkit.pprinter as pp
+from gentoolkit import catpkgsplit, settings, Package, Config
+from gentoolkit.textwrap_ import TextWrapper
+
+__productname__ = "equery"
+__authors__ = """\
+Karl Trygve Kalleberg - Original author
+Douglas Anderson - Modular redesign; author of meta, changes"""
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @param with_description (bool): Option to print module's __doc__ or not
+ """
+
+ if with_description:
+ print __doc__
+ print main_usage()
+ print
+ print pp.globaloption("global options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -q, --quiet", "minimal output"),
+ (" -C, --no-color", "turn off colors"),
+ (" -N, --no-pipe", "turn off pipe detection"),
+ (" -V, --version", "display version info")
+ ))
+ print
+ 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"),
+ (" chec(k)", "verify checksums and timestamps for PKG"),
+ (" (d)epends", "list all packages directly depending on PKG"),
+ (" 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"),
+ (" (l)ist", "list package matching PKG"),
+ (" (m)eta", "display metadata about PKG"),
+ (" (s)ize", "display total size of all files owned by PKG"),
+ (" (u)ses", "display USE flags for PKG"),
+ (" (w)hich", "print full path to ebuild for PKG")
+ ))
+
+
+def expand_module_name(module_name):
+ """Returns one of the values of name_map or raises KeyError"""
+
+ name_map = {
+ 'b': 'belongs',
+ 'c': 'changes',
+ 'k': 'check',
+ 'd': 'depends',
+ 'g': 'depgraph',
+ 'f': 'files',
+ 'h': 'hasuse',
+ 'l': 'list_',
+ 'm': 'meta',
+ 's': 'size',
+ 'u': 'uses',
+ 'w': 'which'
+ }
+
+ if module_name == 'list':
+ # list is a Python builtin type, so we must rename our module
+ return 'list_'
+ elif module_name in name_map.values():
+ return module_name
+ else:
+ return name_map[module_name]
+
+
+def format_options(options):
+ """Format module options.
+
+ @type options: list
+ @param options: [('option 1', 'description 1'), ('option 2', 'des... )]
+ @rtype: str
+ @return: formatted options string
+ """
+
+ result = []
+ twrap = TextWrapper(width=Config['termWidth'])
+ opts = (x[0] for x in options)
+ descs = (x[1] for x in options)
+ for opt, desc in zip(opts, descs):
+ twrap.initial_indent = pp.emph(opt.ljust(25))
+ twrap.subsequent_indent = " " * 25
+ result.append(twrap.fill(desc))
+
+ return '\n'.join(result)
+
+
+def format_package_names(match_set, status):
+ """Add location and mask status to package names.
+
+ @type match_set: list of gentoolkit.package.Package
+ @param match_set: packages to format
+ @rtype: list
+ @return: formatted packages
+ """
+
+ arch = gentoolkit.settings["ARCH"]
+ formatted_packages = []
+ pfxmodes = ['---', 'I--', '-P-', '--O']
+ maskmodes = [' ', ' ~', ' -', 'M ', 'M~', 'M-']
+
+ for pkg in match_set:
+ mask = get_mask_status(pkg, arch)
+ pkgcpv = pkg.get_cpv()
+ slot = pkg.get_env_var("SLOT")
+
+ formatted_packages.append("[%s] [%s] %s (%s)" %
+ (pfxmodes[status],
+ pp.maskflag(maskmodes[mask]),
+ pp.cpv(pkgcpv),
+ str(slot)))
+
+ return formatted_packages
+
+
+def format_filetype(path, fdesc, show_type=False, show_md5=False,
+ show_timestamp=False):
+ """Format a path for printing.
+
+ @type path: str
+ @param path: the path
+ @type fdesc: list
+ @param fdesc: [file_type, timestamp, MD5 sum/symlink target]
+ file_type is one of dev, dir, obj, sym.
+ If file_type is dir, there is no timestamp or MD5 sum.
+ If file_type is sym, fdesc[2] is the target of the symlink.
+ @type show_type: bool
+ @param show_type: if True, prepend the file's type to the formatted string
+ @type show_md5: bool
+ @param show_md5: if True, append MD5 sum to the formatted string
+ @type show_timestamp: bool
+ @param show_timestamp: if True, append time-of-creation after pathname
+ @rtype: str
+ @return: formatted pathname with optional added information
+ """
+
+ ftype = fpath = stamp = md5sum = ""
+
+ if fdesc[0] == "obj":
+ ftype = "file"
+ fpath = path
+ stamp = format_timestamp(fdesc[1])
+ md5sum = fdesc[2]
+ elif fdesc[0] == "dir":
+ ftype = "dir"
+ fpath = pp.path(path)
+ elif fdesc[0] == "sym":
+ ftype = "sym"
+ stamp = format_timestamp(fdesc[1])
+ tgt = fdesc[2].split()[0]
+ if Config["piping"]:
+ fpath = path
+ else:
+ fpath = pp.path_symlink(path + " -> " + tgt)
+ elif fdesc[0] == "dev":
+ ftype = "dev"
+ fpath = path
+ else:
+ pp.print_error("%s has unknown type: %s" % (path, fdesc[0]))
+
+ result = ""
+ if show_type:
+ result += "%4s " % ftype
+ result += fpath
+ if show_timestamp:
+ result += " " + stamp
+ if show_md5:
+ result += " " + md5sum
+
+ return result
+
+
+def format_timestamp(timestamp):
+ """Format a timestamp into, e.g., '2009-01-31 21:19:44' format"""
+
+ return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(timestamp)))
+
+
+def get_mask_status(pkg, arch):
+ """Get the mask status of a given package.
+
+ @type pkg: gentoolkit.package.Package
+ @param pkg: pkg to get mask status of
+ @type arch: str
+ @param arch: output of gentoolkit.settings["ARCH"]
+ @rtype: int
+ @return: an index for this list: [" ", " ~", " -", "M ", "M~", "M-"]
+ 0 = not masked
+ 1 = keyword masked
+ 2 = arch masked
+ 3 = hard masked
+ 4 = hard and keyword masked,
+ 5 = hard and arch masked
+ """
+
+ # Determining mask status
+ keywords = pkg.get_env_var("KEYWORDS").split()
+ mask_status = 0
+ if pkg.is_masked():
+ mask_status += 3
+ if ("~%s" % arch) in keywords:
+ mask_status += 1
+ elif ("-%s" % arch) in keywords or "-*" in keywords:
+ mask_status += 2
+
+ return mask_status
+
+
+def initialize_configuration():
+ """Setup the standard equery config"""
+
+ # Get terminal size
+ term_width = pp.output.get_term_size()[1]
+ if term_width == -1:
+ # get_term_size() failed. Set a sane default width:
+ term_width = 80
+
+ # Terminal size, minus a 1-char margin for text wrapping
+ Config['termWidth'] = term_width - 1
+
+ # Color handling: -1: Use Portage settings, 0: Force off, 1: Force on
+ Config['color'] = -1
+
+ # Guess color output
+ if (Config['color'] == -1 and (not sys.stdout.isatty() or
+ settings["NOCOLOR"] in ("yes", "true")) or
+ Config['color'] == 0):
+ pp.output.nocolor()
+
+ # Guess piping output
+ if not sys.stdout.isatty():
+ Config["piping"] = True
+ else:
+ Config["piping"] = False
+
+
+def main_usage():
+ """Print the main usage message for equery"""
+
+ return "%(usage)s %(product)s [%(g_opts)s] %(mod_name)s [%(mod_opts)s]" % {
+ 'usage': pp.emph("Usage:"),
+ 'product': pp.productname(__productname__),
+ 'g_opts': pp.globaloption("global-options"),
+ 'mod_name': pp.command("module-name"),
+ 'mod_opts': pp.localoption("module-options")
+ }
+
+
+def mod_usage(mod_name="module", arg="pkgspec", optional=False):
+ """Provide a consistant usage message to the calling module.
+
+ @type arg: string
+ @param arg: what kind of argument the module takes (pkgspec, filename, etc)
+ @type optional: bool
+ @param optional: is the argument optional?
+ """
+
+ return "%(usage)s: %(mod_name)s [%(opts)s] %(arg)s" % {
+ 'usage': pp.emph("Usage"),
+ 'mod_name': pp.command(mod_name),
+ 'opts': pp.localoption("options"),
+ 'arg': ("[%s]" % pp.emph(arg)) if optional else pp.emph(arg)
+ }
+
+
+def parse_global_options(global_opts, args):
+ """Parse global input args and return True if we should display help for
+ the called module, else False (or display help and exit from here).
+ """
+
+ need_help = False
+ opts = (opt[0] for opt in global_opts)
+ for opt in opts:
+ if opt in ('-h', '--help'):
+ if args:
+ need_help = True
+ else:
+ print_help()
+ sys.exit(0)
+ elif opt in ('-q','--quiet'):
+ Config["verbosityLevel"] = 0
+ elif opt in ('-C', '--no-color', '--nocolor'):
+ Config['color'] = 0
+ pp.output.nocolor()
+ elif opt in ('-N', '--no-pipe'):
+ Config["piping"] = False
+ elif opt in ('-V', '--version'):
+ print_version()
+ sys.exit(0)
+
+ return need_help
+
+
+def print_version():
+ """Print the version of this tool to the console."""
+
+ try:
+ with open('/etc/gentoolkit-version') as gentoolkit_version:
+ version = gentoolkit_version.read().strip()
+ except IOError, err:
+ pp.die(2, str(err))
+
+ print "%(product)s (%(version)s) - %(docstring)s" % {
+ "product": pp.productname(__productname__),
+ "version": version,
+ "docstring": __doc__
+ }
+ print
+ print __authors__
+
+
+def split_arguments(args):
+ """Separate module name from module arguments"""
+
+ return args.pop(0), args
+
+
+def main():
+ """Parse input and run the program."""
+
+ initialize_configuration()
+
+ short_opts = "hqCNV"
+ long_opts = ('help', 'quiet', 'nocolor', 'no-color', 'no-pipe', 'version')
+
+ try:
+ global_opts, args = getopt(sys.argv[1:], short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Global %s" % err)
+ print_help(with_description=False)
+ sys.exit(2)
+
+
+ # Parse global options
+ need_help = parse_global_options(global_opts, args)
+
+ try:
+ module_name, module_args = split_arguments(args)
+ except IndexError:
+ print_help()
+ sys.exit(2)
+
+ if need_help:
+ module_args.append('--help')
+
+ try:
+ expanded_module_name = expand_module_name(module_name)
+ except KeyError:
+ pp.print_error("Unknown module '%s'" % module_name)
+ print_help(with_description=False)
+ sys.exit(2)
+
+ try:
+ loaded_module = __import__(expanded_module_name, globals(),
+ locals(), [], -1)
+ loaded_module.main(module_args)
+ except ValueError, err:
+ if isinstance(err[0], list):
+ pp.print_error("Ambiguous package name. Use one of: ")
+ while err[0]:
+ print " " + err[0].pop()
+ else:
+ pp.print_error("Internal portage error, terminating")
+ if err:
+ pp.print_error(str(err[0]))
+ sys.exit(1)
+ except IOError, err:
+ if err.errno != errno.EPIPE:
+ raise