+++ /dev/null
-Thomas de Grenier de Latour (tgl) <degrenier@easyconnect.fr>
+++ /dev/null
-2005-12-19 Paul Varner <fuzzyray@gentoo.org>
- * Add support for reqular expression matching for file names in the
- exclude files.
-
-2005-08-28 Thomas de Grenier de Latour (tgl) <degrenier@easyconnect.fr>
- * Version 0.4.1
- * added support for some "eclean-dist" and "eclean-pkg" symlinks on eclean
- (and thus refactored command-line parsing and help screen code)
- * accept file names in exclude files for specific distfiles protection
- (useful to protect the OOo i18n files for instance, which are not in
- $SRC_URI but put there manually)
- * minor rewrite of some findDistfiles() code
- * added /usr/lib/portage/pym python path, just to be sure it comes first
- (after all, "ouput" is a pretty generic name for a python module...)
- * updated manpage
-
-2005-08-27 Thomas de Grenier de Latour (tgl) <degrenier@easyconnect.fr>
- * Version 0.4
- * added exclusion files support
- * added time limit option
- * added size limit option (for distfiles only)
- * added fetch-restricted distfile optionnal protection
- * added --package-names option for protection of all versions of installed
- packages.
- * removed support of multiple actions on command-line. That would have been
- hell with action-specific options.
- * updated manpage
+++ /dev/null
-# Copyright 2004 Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright 2004 Gentoo Technologies, Inc.
-# Distributed under the terms of the GNU General Public License v2
-#
-# $Header$
-
-include ../../makedefs.mak
-
-all:
-
-dist:
- mkdir -p ../../$(distdir)/src/eclean
- cp eclean eclean.1 Makefile *.exclude ../../$(distdir)/src/eclean
- cp AUTHORS THANKS TODO ChangeLog ../../$(distdir)/src/eclean
-
-install:
- install -m 0755 eclean $(bindir)/
- ln -sf eclean $(bindir)/eclean-pkg
- ln -sf eclean $(bindir)/eclean-dist
- install -d $(sysconfdir)/eclean
- install -m 0644 distfiles.exclude packages.exclude $(sysconfdir)/eclean/
- install -d $(docdir)/eclean
- install -m 0644 AUTHORS THANKS TODO ChangeLog $(docdir)/eclean/
- install -m 0644 eclean.1 $(mandir)/
+++ /dev/null
-The starting point ideas were found here:
-http://forums.gentoo.org/viewtopic.php?t=3011
-
-Thanks to eswanson and far for their contributions, and to wolf31o2 for his
-support. Thanks also to karltk, some of this code was at some point inspired
-by his "equery" tool. And thanks to people who had a look on bug #33877:
-Benjamin Braatz, fuzzyray, genone, etc.
+++ /dev/null
-- exclusion file syntax could be improved (maybe it should support real
- dep-atoms, or wildcards, etc.)
-
-- some policy to keep the X latest versions of a package (in each of its
- SLOT maybe) would be really cool...
-
-- add an option to protect system binary packages
- => yup, but later... (needs some portage modifications to be done right)
-
-- add actions for PORT_LOGDIR and/or /var/tmp/portage cleaning?
- => bah, don't know... imho tmpreaper or find+rm onliners are enough here
-
-- cleanup of DISTDIR/cvs-src when action=distfiles
- => i never use cvs ebuilds, i should check what it does exactly
-
-- rewrite for a decent Portage API if there ever is one
+++ /dev/null
-# /etc/eclean/distfiles.exclude
-# In this file you can list some categories or cat/pkg-name for which you want
-# to protect distfiles from "ecleaning". You can also name some specific files.
-# See `man eclean` for syntax details.
-metadata.dtd
+++ /dev/null
-#!/usr/bin/python
-# Copyright 2003-2005 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-# $Header: $
-
-from __future__ import with_statement
-
-###############################################################################
-# Meta:
-__author__ = "Thomas de Grenier de Latour (tgl)"
-__email__ = "degrenier@easyconnect.fr"
-__version__ = "0.4.1"
-__productname__ = "eclean"
-__description__ = "A cleaning tool for Gentoo distfiles and binaries."
-
-
-###############################################################################
-# Python imports:
-
-import sys
-import os, stat
-import re
-import time
-import getopt
-import fpformat
-import signal
-try:
- import portage
-except ImportError:
- sys.path.insert(0, "/usr/lib/portage/pym")
- import portage
-try:
- from portage.output import *
-except ImportError:
- from output import *
-
-listdir = portage.listdir
-
-###############################################################################
-# Misc. shortcuts to some portage stuff:
-port_settings = portage.settings
-distdir = port_settings["DISTDIR"]
-pkgdir = port_settings["PKGDIR"]
-
-###############################################################################
-# printVersion:
-def printVersion():
- print "%s (version %s) - %s" \
- % (__productname__, __version__, __description__)
- print "Author: %s <%s>" % (__author__,__email__)
- print "Copyright 2003-2005 Gentoo Foundation"
- print "Distributed under the terms of the GNU General Public License v2"
-
-
-###############################################################################
-# printUsage: print help message. May also print partial help to stderr if an
-# error from {'options','actions'} is specified.
-def printUsage(error=None,help=None):
- out = sys.stdout
- if error: out = sys.stderr
- if not error in ('actions', 'global-options', \
- 'packages-options', 'distfiles-options', \
- 'merged-packages-options', 'merged-distfiles-options', \
- 'time', 'size'):
- error = None
- if not error and not help: help = 'all'
- if error == 'time':
- eerror("Wrong time specification")
- print >>out, "Time specification should be an integer followed by a"+ \
- " single letter unit."
- print >>out, "Available units are: y (years), m (months), w (weeks), "+ \
- "d (days) and h (hours)."
- print >>out, "For instance: \"1y\" is \"one year\", \"2w\" is \"two"+ \
- " weeks\", etc. "
- return
- if error == 'size':
- eerror("Wrong size specification")
- print >>out, "Size specification should be an integer followed by a"+ \
- " single letter unit."
- print >>out, "Available units are: G, M, K and B."
- print >>out, "For instance: \"10M\" is \"ten megabytes\", \"200K\" "+ \
- "is \"two hundreds kilobytes\", etc."
- return
- if error in ('global-options', 'packages-options', 'distfiles-options', \
- 'merged-packages-options', 'merged-distfiles-options',):
- eerror("Wrong option on command line.")
- print >>out
- elif error == 'actions':
- eerror("Wrong or missing action name on command line.")
- print >>out
- print >>out, white("Usage:")
- if error in ('actions','global-options', 'packages-options', \
- 'distfiles-options') or help == 'all':
- print >>out, " "+turquoise(__productname__), \
- yellow("[global-option] ..."), \
- green("<action>"), \
- yellow("[action-option] ...")
- if error == 'merged-distfiles-options' or help in ('all','distfiles'):
- print >>out, " "+turquoise(__productname__+'-dist'), \
- yellow("[global-option, distfiles-option] ...")
- if error == 'merged-packages-options' or help in ('all','packages'):
- print >>out, " "+turquoise(__productname__+'-pkg'), \
- yellow("[global-option, packages-option] ...")
- if error in ('global-options', 'actions'):
- print >>out, " "+turquoise(__productname__), \
- yellow("[--help, --version]")
- if help == 'all':
- print >>out, " "+turquoise(__productname__+"(-dist,-pkg)"), \
- yellow("[--help, --version]")
- if error == 'merged-packages-options' or help == 'packages':
- print >>out, " "+turquoise(__productname__+'-pkg'), \
- yellow("[--help, --version]")
- if error == 'merged-distfiles-options' or help == 'distfiles':
- print >>out, " "+turquoise(__productname__+'-dist'), \
- yellow("[--help, --version]")
- print >>out
- if error in ('global-options', 'merged-packages-options', \
- 'merged-distfiles-options') or help:
- print >>out, "Available global", yellow("options")+":"
- print >>out, yellow(" -C, --nocolor")+ \
- " - turn off colors on output"
- print >>out, yellow(" -d, --destructive")+ \
- " - only keep the minimum for a reinstallation"
- print >>out, yellow(" -e, --exclude-file=<path>")+ \
- " - path to the exclusion file"
- print >>out, yellow(" -i, --interactive")+ \
- " - ask confirmation before deletions"
- print >>out, yellow(" -n, --package-names")+ \
- " - protect all versions (when --destructive)"
- print >>out, yellow(" -p, --pretend")+ \
- " - only display what would be cleaned"
- print >>out, yellow(" -q, --quiet")+ \
- " - be as quiet as possible"
- print >>out, yellow(" -t, --time-limit=<time>")+ \
- " - don't delete files modified since "+yellow("<time>")
- print >>out, " "+yellow("<time>"), "is a duration: \"1y\" is"+ \
- " \"one year\", \"2w\" is \"two weeks\", etc. "
- print >>out, " "+"Units are: y (years), m (months), w (weeks), "+ \
- "d (days) and h (hours)."
- print >>out, yellow(" -h, --help")+ \
- " - display the help screen"
- print >>out, yellow(" -V, --version")+ \
- " - display version info"
- print >>out
- if error == 'actions' or help == 'all':
- print >>out, "Available", green("actions")+":"
- print >>out, green(" packages")+ \
- " - clean outdated binary packages from:"
- print >>out, " ",teal(pkgdir)
- print >>out, green(" distfiles")+ \
- " - clean outdated packages sources files from:"
- print >>out, " ",teal(distdir)
- print >>out
- if error in ('packages-options','merged-packages-options') \
- or help in ('all','packages'):
- print >>out, "Available", yellow("options"),"for the", \
- green("packages"),"action:"
- print >>out, yellow(" NONE :)")
- print >>out
- if error in ('distfiles-options', 'merged-distfiles-options') \
- or help in ('all','distfiles'):
- print >>out, "Available", yellow("options"),"for the", \
- green("distfiles"),"action:"
- print >>out, yellow(" -f, --fetch-restricted")+ \
- " - protect fetch-restricted files (when --destructive)"
- print >>out, yellow(" -s, --size-limit=<size>")+ \
- " - don't delete distfiles bigger than "+yellow("<size>")
- print >>out, " "+yellow("<size>"), "is a size specification: "+ \
- "\"10M\" is \"ten megabytes\", \"200K\" is"
- print >>out, " "+"\"two hundreds kilobytes\", etc. Units are: "+ \
- "G, M, K and B."
- print >>out
- print >>out, "More detailed instruction can be found in", \
- turquoise("`man %s`" % __productname__)
-
-
-###############################################################################
-# einfo: display an info message depending on a color mode
-def einfo(message="", nocolor=False):
- if not nocolor: prefix = " "+green('*')
- else: prefix = ">>>"
- print prefix,message
-
-
-###############################################################################
-# eerror: display an error depending on a color mode
-def eerror(message="", nocolor=False):
- if not nocolor: prefix = " "+red('*')
- else: prefix = "!!!"
- print >>sys.stderr,prefix,message
-
-
-###############################################################################
-# eprompt: display a user question depending on a color mode.
-def eprompt(message, nocolor=False):
- if not nocolor: prefix = " "+red('>')+" "
- else: prefix = "??? "
- sys.stdout.write(prefix+message)
- sys.stdout.flush()
-
-
-###############################################################################
-# prettySize: integer -> byte/kilo/mega/giga converter. Optionnally justify the
-# result. Output is a string.
-def prettySize(size,justify=False):
- units = [" G"," M"," K"," B"]
- approx = 0
- while len(units) and size >= 1000:
- approx = 1
- size = size / 1024.
- units.pop()
- sizestr = fpformat.fix(size,approx)+units[-1]
- if justify:
- sizestr = " " + blue("[ ") + " "*(7-len(sizestr)) \
- + green(sizestr) + blue(" ]")
- return sizestr
-
-
-###############################################################################
-# yesNoAllPrompt: print a prompt until user answer in yes/no/all. Return a
-# boolean for answer, and also may affect the 'accept_all' option.
-# Note: i gave up with getch-like functions, to much bugs in case of escape
-# sequences. Back to raw_input.
-def yesNoAllPrompt(myoptions,message="Do you want to proceed?"):
- user_string="xxx"
- while not user_string.lower() in ["","y","n","a","yes","no","all"]:
- eprompt(message+" [Y/n/a]: ", myoptions['nocolor'])
- user_string = raw_input()
- if user_string.lower() in ["a","all"]:
- myoptions['accept_all'] = True
- myanswer = user_string.lower() in ["","y","a","yes","all"]
- return myanswer
-
-
-###############################################################################
-# ParseArgsException: for parseArgs() -> main() communication
-class ParseArgsException(Exception):
- def __init__(self, value):
- self.value = value
- def __str__(self):
- return repr(self.value)
-
-
-###############################################################################
-# parseSize: convert a file size "Xu" ("X" is an integer, and "u" in [G,M,K,B])
-# into an integer (file size in Bytes). Raises ParseArgsException('size') in
-# case of failure.
-def parseSize(size):
- myunits = { \
- 'G': (1024**3), \
- 'M': (1024**2), \
- 'K': 1024, \
- 'B': 1 \
- }
- try:
- mymatch = re.match(r"^(?P<value>\d+)(?P<unit>[GMKBgmkb])?$",size)
- mysize = int(mymatch.group('value'))
- if mymatch.group('unit'):
- mysize *= myunits[mymatch.group('unit').capitalize()]
- except:
- raise ParseArgsException('size')
- return mysize
-
-
-###############################################################################
-# parseTime: convert a duration "Xu" ("X" is an int, and "u" a time unit in
-# [Y,M,W,D,H]) into an integer which is a past EPOCH date.
-# Raises ParseArgsException('time') in case of failure.
-# (yep, big approximations inside... who cares?)
-def parseTime(timespec):
- myunits = {'H' : (60 * 60)}
- myunits['D'] = myunits['H'] * 24
- myunits['W'] = myunits['D'] * 7
- myunits['M'] = myunits['D'] * 30
- myunits['Y'] = myunits['D'] * 365
- try:
- # parse the time specification
- mymatch = re.match(r"^(?P<value>\d+)(?P<unit>[YMWDHymwdh])?$",timespec)
- myvalue = int(mymatch.group('value'))
- if not mymatch.group('unit'): myunit = 'D'
- else: myunit = mymatch.group('unit').capitalize()
- except: raise ParseArgsException('time')
- # calculate the limit EPOCH date
- mytime = time.time() - (myvalue * myunits[myunit])
- return mytime
-
-
-###############################################################################
-# parseCmdLine: parse the command line arguments. Raise exceptions on errors or
-# non-action modes (help/version). Returns an action, and affect the options
-# dict.
-def parseArgs(myoptions={}):
-
- # local function for interpreting command line options
- # and setting myoptions accordingly
- def optionSwitch(myoption,opts,action=None):
- return_code = True
- for o, a in opts:
- if o in ("-h", "--help"):
- if action: raise ParseArgsException('help-'+action)
- else: raise ParseArgsException('help')
- elif o in ("-V", "--version"):
- raise ParseArgsException('version')
- elif o in ("-C", "--nocolor"):
- myoptions['nocolor'] = True
- nocolor()
- elif o in ("-d", "--destructive"):
- myoptions['destructive'] = True
- elif o in ("-i", "--interactive") and not myoptions['pretend']:
- myoptions['interactive'] = True
- elif o in ("-p", "--pretend"):
- myoptions['pretend'] = True
- myoptions['interactive'] = False
- elif o in ("-q", "--quiet"):
- myoptions['quiet'] = True
- elif o in ("-t", "--time-limit"):
- myoptions['time-limit'] = parseTime(a)
- elif o in ("-e", "--exclude-file"):
- myoptions['exclude-file'] = a
- elif o in ("-n", "--package-names"):
- myoptions['package-names'] = True
- elif o in ("-f", "--fetch-restricted"):
- myoptions['fetch-restricted'] = True
- elif o in ("-s", "--size-limit"):
- myoptions['size-limit'] = parseSize(a)
- else: return_code = False
- # sanity check of --destructive only options:
- for myopt in ('fetch-restricted', 'package-names'):
- if (not myoptions['destructive']) and myoptions[myopt]:
- if not myoptions['quiet']:
- eerror("--%s only makes sense in --destructive mode." \
- % myopt, myoptions['nocolor'])
- myoptions[myopt] = False
- return return_code
-
- # here are the different allowed command line options (getopt args)
- getopt_options = {'short':{}, 'long':{}}
- getopt_options['short']['global'] = "Cdipqe:t:nhV"
- getopt_options['long']['global'] = ["nocolor", "destructive", \
- "interactive", "pretend", "quiet", "exclude-file=", "time-limit=", \
- "package-names", "help", "version"]
- getopt_options['short']['distfiles'] = "fs:"
- getopt_options['long']['distfiles'] = ["fetch-restricted", "size-limit="]
- getopt_options['short']['packages'] = ""
- getopt_options['long']['packages'] = [""]
- # set default options, except 'nocolor', which is set in main()
- myoptions['interactive'] = False
- myoptions['pretend'] = False
- myoptions['quiet'] = False
- myoptions['accept_all'] = False
- myoptions['destructive'] = False
- myoptions['time-limit'] = 0
- myoptions['package-names'] = False
- myoptions['fetch-restricted'] = False
- myoptions['size-limit'] = 0
- # if called by a well-named symlink, set the acction accordingly:
- myaction = None
- if os.path.basename(sys.argv[0]) in \
- (__productname__+'-pkg', __productname__+'-packages'):
- myaction = 'packages'
- elif os.path.basename(sys.argv[0]) in \
- (__productname__+'-dist', __productname__+'-distfiles'):
- myaction = 'distfiles'
- # prepare for the first getopt
- if myaction:
- short_opts = getopt_options['short']['global'] \
- + getopt_options['short'][myaction]
- long_opts = getopt_options['long']['global'] \
- + getopt_options['long'][myaction]
- opts_mode = 'merged-'+myaction
- else:
- short_opts = getopt_options['short']['global']
- long_opts = getopt_options['long']['global']
- opts_mode = 'global'
- # apply getopts to command line, show partial help on failure
- try: opts, args = getopt.getopt(sys.argv[1:], short_opts, long_opts)
- except: raise ParseArgsException(opts_mode+'-options')
- # set myoptions accordingly
- optionSwitch(myoptions,opts,action=myaction)
- # if action was already set, there should be no more args
- if myaction and len(args): raise ParseArgsException(opts_mode+'-options')
- # if action was set, there is nothing left to do
- if myaction: return myaction
- # So, we are in "eclean --foo action --bar" mode. Parse remaining args...
- # Only two actions are allowed: 'packages' and 'distfiles'.
- if not len(args) or not args[0] in ('packages','distfiles'):
- raise ParseArgsException('actions')
- myaction = args.pop(0)
- # parse the action specific options
- try: opts, args = getopt.getopt(args, \
- getopt_options['short'][myaction], \
- getopt_options['long'][myaction])
- except: raise ParseArgsException(myaction+'-options')
- # set myoptions again, for action-specific options
- optionSwitch(myoptions,opts,action=myaction)
- # any remaning args? Then die!
- if len(args): raise ParseArgsException(myaction+'-options')
- # returns the action. Options dictionary is modified by side-effect.
- return myaction
-
-###############################################################################
-# isValidCP: check wether a string is a valid cat/pkg-name
-# This is for 2.0.51 vs. CVS HEAD compatibility, i've not found any function
-# for that which would exists in both. Weird...
-def isValidCP(cp):
- if not '/' in cp: return False
- try: portage.cpv_getkey(cp+"-0")
- except: return False
- else: return True
-
-
-###############################################################################
-# ParseExcludeFileException: for parseExcludeFile() -> main() communication
-class ParseExcludeFileException(Exception):
- def __init__(self, value):
- self.value = value
- def __str__(self):
- return repr(self.value)
-
-
-###############################################################################
-# parseExcludeFile: parses an exclusion file, returns an exclusion dictionnary
-# Raises ParseExcludeFileException in case of fatal error.
-def parseExcludeFile(filepath):
- excl_dict = { \
- 'categories':{}, \
- 'packages':{}, \
- 'anti-packages':{}, \
- 'garbage':{} }
- try: file = open(filepath,"r")
- except IOError:
- raise ParseExcludeFileException("Could not open exclusion file.")
- filecontents = file.readlines()
- file.close()
- cat_re = re.compile('^(?P<cat>[a-zA-Z0-9]+-[a-zA-Z0-9]+)(/\*)?$')
- cp_re = re.compile('^(?P<cp>[-a-zA-Z0-9_]+/[-a-zA-Z0-9_]+)$')
- for line in filecontents:
- line = line.strip()
- if not len(line): continue
- if line[0] == '#': continue
- try: mycat = cat_re.match(line).group('cat')
- except: pass
- else:
- if not mycat in portage.settings.categories:
- raise ParseExcludeFileException("Invalid category: "+mycat)
- excl_dict['categories'][mycat] = None
- continue
- dict_key = 'packages'
- if line[0] == '!':
- dict_key = 'anti-packages'
- line = line[1:]
- try:
- mycp = cp_re.match(line).group('cp')
- if isValidCP(mycp):
- excl_dict[dict_key][mycp] = None
- continue
- else: raise ParseExcludeFileException("Invalid cat/pkg: "+mycp)
- except: pass
- #raise ParseExcludeFileException("Invalid line: "+line)
- try:
- excl_dict['garbage'][line] = re.compile(line)
- except:
- try:
- excl_dict['garbage'][line] = re.compile(re.escape(line))
- except:
- raise ParseExcludeFileException("Invalid file name/regular expression: "+line)
- return excl_dict
-
-
-###############################################################################
-# exclDictExpand: returns a dictionary of all CP from porttree which match
-# the exclusion dictionary
-def exclDictExpand(excl_dict):
- mydict = {}
- if 'categories' in excl_dict:
- # XXX: i smell an access to something which is really out of API...
- for mytree in portage.portdb.porttrees:
- for mycat in excl_dict['categories']:
- for mypkg in listdir(os.path.join(mytree,mycat),ignorecvs=1):
- mydict[mycat+'/'+mypkg] = None
- if 'packages' in excl_dict:
- for mycp in excl_dict['packages']:
- mydict[mycp] = None
- if 'anti-packages' in excl_dict:
- for mycp in excl_dict['anti-packages']:
- if mycp in mydict:
- del mydict[mycp]
- return mydict
-
-
-###############################################################################
-# exclDictMatch: checks whether a CP matches the exclusion rules
-def exclDictMatch(excl_dict,pkg):
- if 'anti-packages' in excl_dict \
- and pkg in excl_dict['anti-packages']:
- return False
- if 'packages' in excl_dict \
- and pkg in excl_dict['packages']:
- return True
- mycat = pkg.split('/')[0]
- if 'categories' in excl_dict \
- and mycat in excl_dict['categories']:
- return True
- return False
-
-
-###############################################################################
-# findDistfiles: find all obsolete distfiles.
-# XXX: what about cvs ebuilds? i should install some to see where it goes...
-def findDistfiles( \
- myoptions, \
- exclude_dict={}, \
- destructive=False,\
- fetch_restricted=False, \
- package_names=False, \
- time_limit=0, \
- size_limit=0,):
- # this regexp extracts files names from SRC_URI. It is not very precise,
- # but we don't care (may return empty strings, etc.), since it is fast.
- file_regexp = re.compile('([a-zA-Z0-9_,\.\-\+\~]*)[\s\)]')
- clean_dict = {}
- keep = []
- pkg_dict = {}
-
- # create a big CPV->SRC_URI dict of packages whose distfiles should be kept
- if (not destructive) or fetch_restricted:
- # list all CPV from portree (yeah, that takes time...)
- for package in portage.portdb.cp_all():
- for my_cpv in portage.portdb.cp_list(package):
- # get SRC_URI and RESTRICT from aux_get
- try: (src_uri,restrict) = \
- portage.portdb.aux_get(my_cpv,["SRC_URI","RESTRICT"])
- except KeyError: continue
- # keep either all or fetch-restricted only
- if (not destructive) or ('fetch' in restrict):
- pkg_dict[my_cpv] = src_uri
- if destructive:
- if not package_names:
- # list all CPV from vartree
- pkg_list = portage.db[portage.root]["vartree"].dbapi.cpv_all()
- else:
- # list all CPV from portree for CP in vartree
- pkg_list = []
- for package in portage.db[portage.root]["vartree"].dbapi.cp_all():
- pkg_list += portage.portdb.cp_list(package)
- for my_cp in exclDictExpand(exclude_dict):
- # add packages from the exclude file
- pkg_list += portage.portdb.cp_list(my_cp)
- for my_cpv in pkg_list:
- # skip non-existing CPV (avoids ugly aux_get messages)
- if not portage.portdb.cpv_exists(my_cpv): continue
- # get SRC_URI from aux_get
- try: pkg_dict[my_cpv] = \
- portage.portdb.aux_get(my_cpv,["SRC_URI"])[0]
- except KeyError: continue
- del pkg_list
-
- # create a dictionary of files which should be deleted
- if not (os.path.isdir(distdir)):
- eerror("%s does not appear to be a directory." % distdir, myoptions['nocolor'])
- eerror("Please set DISTDIR to a sane value.", myoptions['nocolor'])
- eerror("(Check your /etc/make.conf and environment).", myoptions['nocolor'])
- exit(1)
- for file in os.listdir(distdir):
- filepath = os.path.join(distdir, file)
- try: file_stat = os.stat(filepath)
- except: continue
- if not stat.S_ISREG(file_stat[stat.ST_MODE]): continue
- if size_limit and (file_stat[stat.ST_SIZE] >= size_limit):
- continue
- if time_limit and (file_stat[stat.ST_MTIME] >= time_limit):
- continue
- if 'garbage' in exclude_dict:
- # Try to match file name directly
- if file in exclude_dict['garbage']:
- file_match = True
- # See if file matches via regular expression matching
- else:
- file_match = False
- for file_entry in exclude_dict['garbage']:
- if exclude_dict['garbage'][file_entry].match(file):
- file_match = True
- break
-
- if file_match:
- continue
- # this is a candidate for cleaning
- clean_dict[file]=[filepath]
- # remove files owned by some protected packages
- for my_cpv in pkg_dict:
- for file in file_regexp.findall(pkg_dict[my_cpv]+"\n"):
- if file in clean_dict:
- del clean_dict[file]
- # no need to waste IO time if there is nothing left to clean
- if not len(clean_dict): return clean_dict
- return clean_dict
-
-
-###############################################################################
-# findPackages: find all obsolete binary packages.
-# XXX: packages are found only by symlinks. Maybe i should also return .tbz2
-# files from All/ that have no corresponding symlinks.
-def findPackages( \
- myoptions, \
- exclude_dict={}, \
- destructive=False, \
- time_limit=0, \
- package_names=False):
- clean_dict = {}
- # create a full package dictionary
-
- if not (os.path.isdir(pkgdir)):
- eerror("%s does not appear to be a directory." % pkgdir, myoptions['nocolor'])
- eerror("Please set PKGDIR to a sane value.", myoptions['nocolor'])
- eerror("(Check your /etc/make.conf and environment).", myoptions['nocolor'])
- exit(1)
- for root, dirs, files in os.walk(pkgdir):
- if root[-3:] == 'All': continue
- for file in files:
- if not file[-5:] == ".tbz2":
- # ignore non-tbz2 files
- continue
- path = os.path.join(root, file)
- category = os.path.split(root)[-1]
- cpv = category+"/"+file[:-5]
- mystat = os.lstat(path)
- if time_limit and (mystat[stat.ST_MTIME] >= time_limit):
- # time-limit exclusion
- continue
- # dict is cpv->[files] (2 files in general, because of symlink)
- clean_dict[cpv] = [path]
- #if os.path.islink(path):
- if stat.S_ISLNK(mystat[stat.ST_MODE]):
- clean_dict[cpv].append(os.path.realpath(path))
- # keep only obsolete ones
- if destructive:
- mydbapi = portage.db[portage.root]["vartree"].dbapi
- if package_names: cp_all = dict.fromkeys(mydbapi.cp_all())
- else: cp_all = {}
- else:
- mydbapi = portage.db[portage.root]["porttree"].dbapi
- cp_all = {}
- for mycpv in clean_dict.keys():
- if exclDictMatch(exclude_dict,portage.cpv_getkey(mycpv)):
- # exclusion because of the exclude file
- del clean_dict[mycpv]
- continue
- if mydbapi.cpv_exists(mycpv):
- # exclusion because pkg still exists (in porttree or vartree)
- del clean_dict[mycpv]
- continue
- if portage.cpv_getkey(mycpv) in cp_all:
- # exlusion because of --package-names
- del clean_dict[mycpv]
-
- return clean_dict
-
-
-###############################################################################
-# doCleanup: takes a dictionnary {'display name':[list of files]}. Calculate
-# size of each entry for display, prompt user if needed, delete files if needed
-# and return the total size of files that [have been / would be] deleted.
-def doCleanup(clean_dict,action,myoptions):
- # define vocabulary of this action
- if action == 'distfiles': file_type = 'file'
- else: file_type = 'binary package'
- # sorting helps reading
- clean_keys = clean_dict.keys()
- clean_keys.sort()
- clean_size = 0
- # clean all entries one by one
- for mykey in clean_keys:
- key_size = 0
- for file in clean_dict[mykey]:
- # get total size for an entry (may be several files, and
- # symlinks count zero)
- if os.path.islink(file): continue
- try: key_size += os.path.getsize(file)
- except: eerror("Could not read size of "+file, \
- myoptions['nocolor'])
- if not myoptions['quiet']:
- # pretty print mode
- print prettySize(key_size,True),teal(mykey)
- elif myoptions['pretend'] or myoptions['interactive']:
- # file list mode
- for file in clean_dict[mykey]: print file
- #else: actually delete stuff, but don't print anything
- if myoptions['pretend']: clean_size += key_size
- elif not myoptions['interactive'] \
- or myoptions['accept_all'] \
- or yesNoAllPrompt(myoptions, \
- "Do you want to delete this " \
- + file_type+"?"):
- # non-interactive mode or positive answer.
- # For each file, try to delete the file and clean it out
- # of Packages metadata file
- if action == 'packages':
- metadata = portage.getbinpkg.PackageIndex()
- with open(os.path.join(pkgdir, 'Packages')) as metadata_file:
- metadata.read(metadata_file)
- for file in clean_dict[mykey]:
- # ...get its size...
- filesize = 0
- if not os.path.exists(file): continue
- if not os.path.islink(file):
- try: filesize = os.path.getsize(file)
- except: eerror("Could not read size of "\
- +file, myoptions['nocolor'])
- # ...and try to delete it.
- try:
- os.unlink(file)
- except:
- eerror("Could not delete "+file, \
- myoptions['nocolor'])
- # only count size if successfully deleted
- else:
- clean_size += filesize
- if action == 'packages':
- metadata.packages[:] = [p for p in metadata.packages if 'CPV' in p and p['CPV'] != file]
-
- if action == 'packages':
- with open(os.path.join(pkgdir, 'Packages'), 'w') as metadata_file:
- metadata.write(metadata_file)
-
- # return total size of deleted or to delete files
- return clean_size
-
-
-###############################################################################
-# doAction: execute one action, ie display a few message, call the right find*
-# function, and then call doCleanup with its result.
-def doAction(action,myoptions,exclude_dict={}):
- # define vocabulary for the output
- if action == 'packages': files_type = "binary packages"
- else: files_type = "distfiles"
- # find files to delete, depending on the action
- if not myoptions['quiet']:
- einfo("Building file list for "+action+" cleaning...", \
- myoptions['nocolor'])
- if action == 'packages':
- clean_dict = findPackages(
- myoptions, \
- exclude_dict=exclude_dict, \
- destructive=myoptions['destructive'], \
- package_names=myoptions['package-names'], \
- time_limit=myoptions['time-limit'])
- else:
- clean_dict = findDistfiles( \
- myoptions, \
- exclude_dict=exclude_dict, \
- destructive=myoptions['destructive'], \
- fetch_restricted=myoptions['fetch-restricted'], \
- package_names=myoptions['package-names'], \
- time_limit=myoptions['time-limit'], \
- size_limit=myoptions['size-limit'])
- # actually clean files if something was found
- if len(clean_dict.keys()):
- # verbose pretend message
- if myoptions['pretend'] and not myoptions['quiet']:
- einfo("Here are "+files_type+" that would be deleted:", \
- myoptions['nocolor'])
- # verbose non-pretend message
- elif not myoptions['quiet']:
- einfo("Cleaning "+files_type+"...",myoptions['nocolor'])
- # do the cleanup, and get size of deleted files
- clean_size = doCleanup(clean_dict,action,myoptions)
- # vocabulary for final message
- if myoptions['pretend']: verb = "would be"
- else: verb = "has been"
- # display freed space
- if not myoptions['quiet']:
- einfo("Total space that "+verb+" freed in " \
- + action + " directory: " \
- + red(prettySize(clean_size)), \
- myoptions['nocolor'])
- # nothing was found, return
- elif not myoptions['quiet']:
- einfo("Your "+action+" directory was already clean.", \
- myoptions['nocolor'])
-
-
-###############################################################################
-# main: parse command line and execute all actions
-def main():
- # set default options
- myoptions = {}
- myoptions['nocolor'] = port_settings["NOCOLOR"] in ('yes','true') \
- and sys.stdout.isatty()
- if myoptions['nocolor']: nocolor()
- # parse command line options and actions
- try: myaction = parseArgs(myoptions)
- # filter exception to know what message to display
- except ParseArgsException, e:
- if e.value == 'help':
- printUsage(help='all')
- sys.exit(0)
- elif e.value[:5] == 'help-':
- printUsage(help=e.value[5:])
- sys.exit(0)
- elif e.value == 'version':
- printVersion()
- sys.exit(0)
- else:
- printUsage(e.value)
- sys.exit(2)
- # parse the exclusion file
- if not 'exclude-file' in myoptions:
- my_exclude_file = "/etc/%s/%s.exclude" % (__productname__ , myaction)
- if os.path.isfile(my_exclude_file):
- myoptions['exclude-file'] = my_exclude_file
- if 'exclude-file' in myoptions:
- try: exclude_dict = parseExcludeFile(myoptions['exclude-file'])
- except ParseExcludeFileException, e:
- eerror(e, myoptions['nocolor'])
- eerror("Invalid exclusion file: %s" % myoptions['exclude-file'], \
- myoptions['nocolor'])
- eerror("See format of this file in `man %s`" % __productname__, \
- myoptions['nocolor'])
- sys.exit(1)
- else: exclude_dict={}
- # security check for non-pretend mode
- if not myoptions['pretend'] and portage.secpass == 0:
- eerror("Permission denied: you must be root or belong to the portage group.", \
- myoptions['nocolor'])
- sys.exit(1)
- # execute action
- doAction(myaction, myoptions, exclude_dict=exclude_dict)
-
-
-###############################################################################
-# actually call main() if launched as a script
-if __name__ == "__main__":
- try: main()
- except KeyboardInterrupt:
- print "Aborted."
- sys.exit(130)
- sys.exit(0)
-
+++ /dev/null
-.TH "eclean" "1" "0.4.1" "gentoolkit"
-.SH "NAME"
-eclean \- A cleaning tool for Gentoo distfiles and binary packages.
-.SH "SYNOPSIS"
-.LP
-.B eclean \fR[\fIglobal\-options\fR] ... <\fIactions\fR> \fR[\fIaction\-options\fR] ...
-.LP
-.B eclean\-dist \fR[\fIglobal\-options, distfiles\-options\fR] ...
-.LP
-.B eclean\-pkg \fR[\fIglobal\-options, packages\-options\fR] ...
-.LP
-.B eclean(-dist,-pkg) \fR[\fI\-\-help, \-\-version\fR]
-.SH "DESCRIPTION"
-\fBeclean\fP is small tool to remove obsolete portage sources files and binary packages.
-Used on a regular basis, it prevents your DISTDIR and PKGDIR directories to
-infinitely grow, while not deleting files which may still be useful.
-.PP
-By default, eclean will protect all distfiles or binary packages corresponding to some
-ebuilds available in the Portage tree. This is the safest mode, since it will protect
-whatever may still be useful, for instance to downgrade a package without downloading
-its sources for the second time, or to reinstall a package you unmerge by mistake
-without recompiling it. Sure, it's also a mode in which your DISTDIR and PKGDIR will
-stay rather big (although still not growing infinitely). For the 'distfiles', this
-mode is also quit slow mode because it requiries some access to the whole Portage tree.
-.PP
-If you use the \-\-destructive option, eclean will only protect files corresponding to
-some currently installed package (taking their exact version into account). It will
-save much more space, while still preserving sources files around for minor revision
-bumps, and binaries for reinstallation of corrupted packages. But it won't keep files
-for less usual operations like downgrading or reinstalling an unmerged package. This
-is also the fastest execution mode (big difference for distfiles), and the one used by
-most other cleaning scripts around like yacleaner (at least in its version 0.3).
-.PP
-Somewhere in the middle, adding the \-\-package\-names option when using \-\-destructive
-will protect files corresponding to all existing versions of installed packages. It will
-allow easy downgrading without recompilation or redownloading in case of trouble, but
-won't protect you against package uninstallation.
-.PP
-In addition to this main modes, some options allow to declare a few special cases file
-protection rules:
-.IP o
-\-\-time-limit is useful to protect files which are more recent than a given amount of time.
-.IP o
-\-\-size-limit (for distfiles only) is useful if you want to protect files bigger than a given size.
-.IP o
-\-\-fetch-restricted (for distfiles only) is useful to protect manually downloaded files.
-But it's also very slow (again, it's a reading of the whole Portage tree data)...
-.IP o
-Finally, you can list some categories or package names to protect in exclusion files (see
-\fBEXCLUSION FILES\fP below).
-.SH "PARAMETERS"
-.SS "Global options"
-.TP
-\fB\-C, \-\-nocolor\fP turn off colors on output
-.TP
-\fB\-d, \-\-destructive\fP only keep the minimum for a reinstallation
-.TP
-\fB\-e, \-\-exclude\-file=<path>\fP path to the exclusion file
-\fB<path>\fP is the absolute path to the exclusion file you want to use.
-When this option is not used, default paths are /etc/eclean/{packages,distfiles}.exclude
-(if they exist). Use /dev/null if you have such a file at it standard location and
-you want to temporary ignore it.
-.TP
-\fB\-i, \-\-interactive\fP ask confirmation before deleting
-.TP
-\fB\-n, \-\-package\-names\fP protect all versions (\-\-destructive only)
-.TP
-\fB\-p, \-\-pretend\fP only display what would be cleaned
-.TP
-\fB\-q, \-\-quiet\fP be as quiet as possible, only display errors
-.TP
-\fB\-t, \-\-time-limit=<time>\fP don't delete files modified since <time>
-\fB<time>\fP is an amount of time: "1y" is "one year", "2w" is "two weeks", etc.
-.br
-Units are: y (years), m (months), w (weeks), d (days) and h (hours).
-.TP
-\fB\-h, \-\-help\fP display the help screen
-.TP
-\fB\-V, \-\-version\fP display version informations
-.SS "Actions"
-.TP
-\fBdistfiles\fR
-Clean files from /usr/portage/distfiles (or whatever else is your DISTDIR in /etc/make.conf).
-This action should be useful to almost any Gentoo user, we all have to big DISTDIRs sometime...
-.br
-\fBeclean\-dist\fP is a shortcut to call eclean with the "distfiles" action, for simplified
-command\-line.
-.TP
-\fBpackages\fR
-Clean files from /usr/portage/packages (or whatever else is your PKGDIR in /etc/make.conf).
-This action is in particular useful for people who use the "buildpkg" or "buildsyspkg"
-FEATURES flags.
-.br
-\fBeclean\-pkg\fP is a shortcut to call eclean with the "packages" action, for simplified
-command\-line.
-.SS "Options for the 'distfiles' action"
-.TP
-\fB\-f, \-\-fetch-restricted\fP protect fetch-restricted files (\-\-destructive only)
-.TP
-\fB\-s, \-\-size-limit=<size>\fP don't delete distfiles bigger than <size>
-<size> is a size specification: "10M" is "ten megabytes", "200K" is "two hundreds kilobytes",
-etc.
-.br
-Units are: G, M, K and B.
-.SS "Options for the 'packages' action"
-.TP
-There is no specific option for this action.
-.SH "EXCLUSION FILES"
-Exclusions files are lists of packages names or categories you want to protect
-in particular. This may be useful to protect more binary packages for some system
-related packages for instance. Syntax is the following:
-.IP o
-blank lines and lines starting with a "#" (comments) are ignored.
-.IP o
-only one entry per line is allowed.
-.IP o
-if a line contains a category name, like "sys\-apps", then all packages from this
-category will be protected. "sys\-apps/*" is also allowed for aesthetic reasons, but
-that does NOT mean that wildcard are supported in any way for any other usage.
-.IP o
-if a line contains a package name ("app\-shells/bash"), then this package will be
-protected. Versioned atoms like ">=app\-shells/bash\-3" are NOT supported. Also, the
-full package name (with category) is mandatory.
-.IP o
-if a line contains a package name with an exclamation mark in front ("!sys\-apps/portage"),
-then this package will be excluded from protection. This is only useful if the category
-itself was protected.
-.IP o
-for distfiles protection, a line can also a filename to protect. This is useful if you have
-there some files which are not registered by the ebuilds, like OpenOffice.org i18n files
-("helpcontent_33_unix.tgz" for instance).
-.LP
-By default, if it exists, /etc/eclean/packages.exclude (resp. distfiles.exclude) will be use
-when action is "packages" (resp. "distfiles"). This can be overide with the \-\-exclude\-file
-option.
-.SH "EXAMPLES"
-.LP
-Clean distfiles only, with per file confirmation prompt:
-.br
-.B # eclean \-i distfiles
-.LP
-Check which binary packages could be removed, with a no-color display:
-.br
-.B # eclean \-Cp packages
-.LP
-Clean binary packages of uninstalled packages, but keep all versions of installed ones:
-.br
-.B # eclean-pkg \-d \-n
-.LP
-Clean all distfiles except for installed packages (exact version), those which
-are less than one month old, bigger than 50MB, or fetch-restricted:
-.br
-.B # eclean-dist \-d \-t1m -s50M -f
-.LP
-From a crontab, silently clean packages in the safest mode, and then distfiles in destructive
-mode but protecting files less than a week old, every sunday at 1am:
-.br
-.B 0 1 * * sun \ \ eclean \-C \-q packages ; eclean \-C \-q \-d \-t1w distfiles
-.".SH "BUGS"
-.".TP
-."The policy used to decide wether a distfile can be removed or not relies on the SRC_URI variables ."of ebuilds. It means that if an ebuild uses files that are not part of its SRC_URI, eclean will ."probably remove them. This are ebuilds bugs, please report them as such on ."http://bugs.gentoo.org.
-.".TP
-."In safest mode (default, without the \-\-destructive option), this script can be very slow. There
-."is not much to do about it without hacking outside of the portage API.
-.SH "SEE ALSO"
-.TP
-The Gentoo forum thread that gave birth to eclean:
-.B http://forums.gentoo.org/viewtopic.php?t=3011
-.TP
-The bug report requesting eclean inclusion in gentoolkit:
-.B http://bugs.gentoo.org/show_bug.cgi?id=33877
-.TP
-Yacleaner, one of the other similar tools:
-.B http://blog.tacvbo.net/data/files/yacleaner/
-.SH "AUTHORS"
-Thomas de Grenier de Latour (tgl) <degrenier@easyconnect.fr>
+++ /dev/null
-# /etc/eclean/packages.exclude
-# In this file you can list some categories or cat/pkg-name for which you want
-# to protect binary packages from "ecleaning".
-# See `man eclean` for syntax details.
+++ /dev/null
-# Copyright 2007 Gentoo Foundation.
-# Distributed under the terms of the GNU General Public License v2
-#
-# $Header$
-
-include ../../makedefs.mak
-
-all:
- echo "CLIXBY (adj.) Politely rude. Bliskly vague. Firmly uninformative."
-
-dist:
- mkdir -p ../../$(distdir)/src/epkginfo
- cp Makefile epkginfo epkginfo.1 ../../$(distdir)/src/epkginfo/
-
-install:
- install -m 0755 epkginfo $(bindir)/
- install -m 0644 epkginfo.1 $(mandir)/
+++ /dev/null
-#!/usr/bin/python
-##############################################################################
-# $Header: $
-##############################################################################
-# Distributed under the terms of the GNU General Public License, v2 or later
-# Author: Ned Ludd <solar@gentoo.org> (glue all the parts together)
-# Author: Eldad Zack <eldad@gentoo.org> (earch)
-# Author : Eric Olinger <EvvL AT RustedHalo DOT net> (metadata)
-
-# Gentoo metadata xml and arch keyword checking tool.
-
-import os
-import sys
-try:
- import portage
-except ImportError:
- sys.path.insert(0, "/usr/lib/portage/pym")
- import portage
-import re
-from stat import *
-try:
- from portage.output import *
-except ImportError:
- from output import *
-from xml.sax import saxutils, make_parser, handler
-from xml.sax.handler import feature_namespaces
-
-version="0.4.1"
-
-def getvar(pkg, var):
- file = open(pkg + ".ebuild")
- for line in file.readlines():
- line = line.rstrip()
- if re.match("^"+var+"=",line):
- vars = re.split("\"",line)[1]
- file.close
- return re.split(" ",vars)
- file.close
-
-def earch(workdir):
- """Prints arch keywords for a given dir"""
- portdir = portage.settings["PORTDIR"]
- #workdir = "."
- os.chdir(workdir)
-
- archdict = {}
- ebuildlist = []
- for file in os.listdir(workdir):
- if re.search("\.ebuild$",file):
- ebuildlist.append(re.split("\.ebuild$",file)[0])
-
- ebuildlist.sort(lambda x,y: portage.pkgcmp(portage.pkgsplit(x),portage.pkgsplit(y)))
-
- for pkg in ebuildlist:
- keywords = getvar(pkg, "KEYWORDS")
- for arch in keywords:
- if arch == "":
- arch = None
- archdict[arch] = pkg
-
- archlist = archdict.keys();
- archlist.sort()
-
- for pkg in ebuildlist:
- print darkgreen("Keywords: ") + pkg + ":",
- for value in archlist:
- if (value and archdict[value] == pkg):
- if value[0] == "-":
- print red(value),
- elif "~" == value[0]:
- print blue(value),
- else:
- print green(value),
- print ""
-
-
-class Metadata_XML(handler.ContentHandler):
- _inside_herd="No"
- _inside_maintainer="No"
- _inside_email="No"
- _inside_longdescription="No"
-
- _herd = ""
- _maintainers = []
- _longdescription = ""
-
- def startElement(self, tag, attr):
- if tag == "herd":
- self._inside_herd="Yes"
- if tag == "longdescription":
- self._inside_longdescription="Yes"
- if tag == "maintainer":
- self._inside_maintainer="Yes"
- if tag == "email":
- self._inside_email="Yes"
-
- def endElement(self, tag):
- if tag == "herd":
- self._inside_herd="No"
- if tag == "longdescription":
- self._inside_longdescription="No"
- if tag == "maintainer":
- self._inside_maintainer="No"
- if tag == "email":
- self._inside_email="No"
-
- def characters(self, contents):
- if self._inside_herd == "Yes":
- self._herd = contents
-
- if self._inside_longdescription == "Yes":
- self._longdescription = contents
-
- if self._inside_maintainer=="Yes" and self._inside_email=="Yes":
- self._maintainers.append(contents)
-
-
-def check_metadata(full_package):
- """Checks that the primary maintainer is still an active dev and list the hed the package belongs to"""
- metadata_file=portage.settings["PORTDIR"] + "/" + portage.pkgsplit(full_package)[0] + "/metadata.xml"
- if not os.path.exists(metadata_file):
- print darkgreen("Maintainer: ") + red("Error (Missing metadata.xml)")
- return 1
-
- parser = make_parser()
- handler = Metadata_XML()
- handler._maintainers = []
- parser.setContentHandler(handler)
- parser.parse( metadata_file )
-
- if len(handler._herd) < 1:
- print darkgreen("Herd: ") + red("Error (No Herd)")
- return 1
- else:
- print darkgreen("Herd: ") + handler._herd
-
- if len(handler._maintainers) < 1:
- print darkgreen("Maintainer: ") + handler._herd
- else:
- print darkgreen("Maintainer: ") + ", ".join(handler._maintainers)
-
- if len(handler._longdescription) > 1:
- print darkgreen("Description: ") + handler._longdescription
- print darkgreen("Location: ") + os.path.normpath(portage.settings["PORTDIR"] + "/" + portage.pkgsplit(full_package)[0])
-
-
-def usage(code):
- """Prints the uage information for this script"""
- print green("epkginfo v" + version + "\n")
- print "Usage: epkginfo [package-cat/]package"
- sys.exit(code)
-
-
-# default color setup
-if ( not sys.stdout.isatty() ) or ( portage.settings["NOCOLOR"] in ["yes","true"] ):
- nocolor()
-
-def fc(x,y):
- return cmp(y[0], x[0])
-
-
-def grab_changelog_devs(catpkg):
- try:
- os.chdir(portage.settings["PORTDIR"] + "/" + catpkg)
- foo=""
- r=re.compile("<[^@]+@gentoo.org>", re.I)
- s="\n".join(portage.grabfile("ChangeLog"))
- d={}
- for x in r.findall(s):
- if x not in d:
- d[x] = 0
- d[x] += 1
-
- l=[(d[x], x) for x in d.keys()]
- #l.sort(lambda x,y: cmp(y[0], x[0]))
- l.sort(fc)
- for x in l:
- p = str(x[0]) +" "+ x[1].lstrip("<").rstrip(">")
- foo += p[:p.find("@")]+", "
- return foo
- except:
- raise
-
-def main ():
- if len( sys.argv ) < 2:
- usage(1)
-
- for pkg in sys.argv[1:]:
-
- if sys.argv[1:][:1] == "-":
- print "NOT WORKING?=="+sys.argv[1:]
- continue
-
- try:
- package_list = portage.portdb.xmatch("match-all", pkg)
- if package_list:
-
- catpkg = portage.pkgsplit(package_list[0])[0]
-
- print darkgreen("Package: ") + catpkg
- check_metadata(package_list[0])
- earch(portage.settings["PORTDIR"] + "/" + catpkg)
- #print darkgreen("ChangeLog: ") + grab_changelog_devs(catpkg)
- print ""
- except:
- print red("Error: "+pkg+"\n")
-
-
-if __name__ == '__main__':
- main()
+++ /dev/null
-.TH "epkginfo" "1" "0.4.1" "Ned Ludd" "gentoolkit"
-.SH "NAME"
-.LP
-epkginfo \- Displays metadata information from packages in portage
-.SH "SYNTAX"
-.LP
-epkginfo [\fIpackage\-cat/\fP]package
-.SH "EXAMPLES"
-$ epkginfo app\-portage/gentoolkit
-.br
-\fBPackage:\fR app\-portage/gentoolkit
-.br
-\fBHerd:\fR tools\-portage
-.br
-\fBMaintainer:\fR tools\-portage
-.br
-\fBLocation:\fR /usr/portage/app\-portage/gentoolkit
-.br
-\fBKeywords:\fR gentoolkit\-0.2.2:
-.br
-\fBKeywords:\fR gentoolkit\-0.2.3: mips
-.br
-\fBKeywords:\fR gentoolkit\-0.2.3\-r1: ppc ppc64 alpha arm s390 amd64 hppa x86 sparc ia64 m68k sh
-.br
-\fBKeywords:\fR gentoolkit\-0.2.4_pre3:
-.br
-\fBKeywords:\fR gentoolkit\-0.2.4_pre4:
-.br
-\fBKeywords:\fR gentoolkit\-0.2.4_pre5: ~arm ~hppa ~x86 ~m68k ~amd64 ~ppc ~sh ~x86\-fbsd ~ia64 ~alpha ~sparc ~ppc64 ~sparc\-fbsd ~mips ~s390
-.SH "AUTHORS"
-.LP
-Ned Ludd <solar@gentoo.org>
-.SH "BUGS"
-Please report any bugs to http://bugs.gentoo.org
+++ /dev/null
-Karl Trygve Kalleberg <karltk@gentoo.org>
- * Initial version
-
+++ /dev/null
-# Copyright 2003 Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright 2003 Gentoo Technologies, Inc.
-# Distributed under the terms of the GNU General Public License v2
-#
-# $Header$
-
-include ../../makedefs.mak
-
-all:
- echo "YADDLETHORPE (vb.) (Of offended pooves.) To exit huffily from a boutique."
-
-dist:
- mkdir -p ../../$(distdir)/src/equery/
- cp Makefile AUTHORS README TODO equery equery.1 ../../$(distdir)/src/equery/
-
-install:
- install -m 0755 equery $(bindir)/
- install -d $(docdir)/equery
- install -m 0644 README AUTHORS $(docdir)/equery/
- install -m 0644 equery.1 $(mandir)/
+++ /dev/null
-- sqlite
- - regexp comparisons
- - check /var/log/emerge.log for database up-to-dateness
-
-
--------------------------
-- pkgquery language:
- Query ::= NewStyle | OldStyle | with OldStyle NewStyle
- NewStyle ::= NameVar in /RegExp/
- | VerVar in [ VerExpr ]
- | SetVar in [ SetExpr ]
- NameVar ::= PC | PN | DESCRIPTION | SRC_URI | HOMEPAGE
-
- SetVar ::= LICENSE | KEYWORDS | IUSE
- VerVar ::= SLOT | PV | DEPEND | RDEPEND
-
- BinaryOp ::= and | or
- UnaryOp ::= not
-
- VerExpr ::= SingleVer
- | VerExpr BinOp VerExpr
- | UnaryOp UnaryOp
-
- SetExpr ::= Element
- | Element BinOp Element
- | UnaryOp Element
-
- SingleVer ::= PrefixOp VersionBody ( VersionSuffix )? ( - Revision )?
- PrefixOp ::= ! | < | > | <= | >= | = | ~
- VersionBody ::= Number ( . Number )+ ( . * )?
- VersionSuffix ::= _ ( pre | beta | alpha | rc ) Number?
- | [a-z]
- Revision ::= r Number
-
-------
-
- PC in /dev-java/ and
- PN in /ant/ and
- PV in [ >=1.0 or <=2.3 and =2.0.* ] and
- IUSE in [ java or junit ]
-
-
---
- with >=dev-java/ant-1.0*
- IUSE in [ java or junit ] and
- SLOT in [ >=1.0 ]
-
-
-----------
-
-old cruft:
-
- SingleVer ::= ( Operator )? ( Category / ) PackageName ( - Version )?
- Operator ::= = | > | >= | < | <= | ~ | !
- Category ::= PackageName
- PackageName ::= NamePart ( - NamePart )+
- NamePart ::= [a-zA-Z+]+
- Version ::= VersionPart ( - VersionPart )+ ( _ VersionSuffix )? ( - Revision )?
- VersionSuffix ::= ( pre | rc | beta | alpha ) ( Number ) ?
-
- old style: >=dev-java/ant-1.0*
-
-
+++ /dev/null
-#!/usr/bin/python
-#
-# Copyright 2003-2004 Karl Trygve Kalleberg
-# Copyright 2003-2004 Gentoo Technologies, Inc.
-# Distributed under the terms of the GNU General Public License v2
-#
-# $Header$
-# Author: Karl Trygve Kalleberg <karltk@gentoo.org>
-
-__author__ = "Karl Trygve Kalleberg"
-__email__ = "karltk@gentoo.org"
-__version__ = "0.1.4"
-__productname__ = "equery"
-__description__ = "Gentoo Package Query Tool"
-
-import os
-import re
-import sys
-import time
-from glob import glob
-
-# portage (output module) and gentoolkit need special path modifications
-sys.path.insert(0, "/usr/lib/gentoolkit/pym")
-
-import gentoolkit
-try:
- import portage
-except ImportError:
- sys.path.insert(0, "/usr/lib/portage/pym")
- import portage
-
-try:
- import portage.checksum as checksum
- from portage.util import unique_array
-except ImportError:
- import portage_checksum as checksum
- from portage_util import unique_array
-
-import gentoolkit.pprinter as pp
-from gentoolkit.pprinter import print_info, print_error, print_warn, die
-
-# Auxiliary functions
-
-def fileAsStr(name, fdesc, showType=0, showMD5=0, showTimestamp=0):
- """
- Return file in fdesc as a filename
- @param name:
- @param fdesc:
- @param showType:
- @param showMD5:
- @param showTimestamp:
- @rtype: string
- """
- type = ""; fname = ""; stamp = ""; md5sum = ""
-
- if fdesc[0] == 'obj':
- type = "file"
- fname = name
- stamp = timestampAsStr(int(fdesc[1]))
- md5sum = fdesc[2]
- elif fdesc[0] == "dir":
- type = "dir"
- fname = pp.path(name)
- elif fdesc[0] == "sym":
- type = "symlink"
- stamp = timestampAsStr(int(fdesc[1].replace(")","")))
- tgt = fdesc[2].split()[0]
- if Config["piping"]:
- fname = name
- else:
- fname = pp.path_symlink(name + " -> " + tgt)
- elif fdesc[0] == "fif":
- type = "fifo"
- fname = name
- elif fdesc[0] == "dev":
- type = "device"
- fname = name
- else:
- raise Exception(name + " has unknown type: " + fdesc[0])
-
- s = ""
- if showType:
- s += "%6s " % type
- s += fname
- if showTimestamp:
- s += " " + stamp + " "
- if showMD5:
- s += " " + md5sum + " "
- return s
-
-def timestampAsStr(timestamp):
- return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp))
-
-
-class Command:
- """
- Abstract root class for all equery commands
- """
- def __init__(self):
- pass
- def shortHelp(self):
- """Return a help formatted to fit a single line, approx 70 characters.
- Must be overridden in the subclass."""
- return " - not implemented yet"
- def longHelp(self):
- """Return full, multiline, color-formatted help.
- Must be overridden in the subclass."""
- return "help for syntax and options"
- def perform(self, args):
- """Stub code for performing the command.
- Must be overridden in the subclass"""
- pass
- def parseArgs(self, args):
- """Stub code for parsing command line arguments for this command.
- Must be overridden in the subclass."""
- pass
-
-
-class CmdListFiles(Command):
- """List files owned by a particular package"""
- def __init__(self):
- self.default_options = {
- "showType": 0,
- "showTimestamp": 0,
- "showMD5": 0,
- "tree": 0,
- "filter": None
- }
-
- def parseArgs(self,args):
- query = ""
- need_help = 0
- opts = self.default_options
- for x in args:
- if x in ["-h", "--help"]:
- need_help = 1
- elif x in ["--md5sum"]:
- opts["showMD5"] = 1
- elif x in ["--timestamp"]:
- opts["showTimestamp"] = 1
- elif x in ["--type"]:
- opts["showType"] = 1
- elif x in ["--tree"]:
- opts["tree"] = 1
- elif x[:9] == "--filter=":
- opts["filter"] = x[9:].split(',')
- elif x[0] == "/":
- die(2, "The query '" + pp.pkgquery(x) + "' does not appear to be a valid package specification")
- elif x[0] == "-":
- print_warn("unknown local option %s, ignoring" % x)
- else:
- query = x
-
- if need_help or query == "":
- print_info(0, self.longHelp())
- sys.exit(-1)
-
- return (query, opts)
-
- def filterContents(self, cnt, filter):
- if filter in [None,[]]:
- return cnt
-
- mycnt = {}
-
- for mytype in filter:
- # Filter elements by type (as recorded in CONTENTS).
- if mytype in ["dir","obj","sym","dev","fif"]:
- for mykey in cnt.keys():
- if cnt[mykey][0] == mytype:
- mycnt[mykey] = cnt[mykey]
-
- if "cmd" in filter:
- # List files that are in $PATH.
- userpath = map(os.path.normpath,os.environ["PATH"].split(os.pathsep))
- for mykey in cnt.keys():
- if cnt[mykey][0] in ['obj','sym'] \
- and os.path.dirname(mykey) in userpath:
- mycnt[mykey] = cnt[mykey]
-
- if "path" in filter:
- # List only dirs where some files where actually installed,
- # and also skip their subdirs.
- mykeys = cnt.keys()
- mykeys.sort()
- while len(mykeys):
- mykey = mykeys.pop(0)
- if cnt[mykey][0] == 'dir':
- i = 0
- while i < len(mykeys) :
- if cnt[mykeys[i]][0] != "dir" \
- and os.path.dirname(mykeys[i]) == mykey:
- mycnt[mykey] = cnt[mykey]
- break
- i += 1
- if i < len(mykeys):
- while len(mykeys) \
- and len(mykey+"/") < len(mykeys[0]) \
- and mykey+"/" == mykeys[0][:len(mykey)+1]:
- mykeys.pop(0)
-
- if "conf" in filter:
- # List configuration files.
- conf_path = gentoolkit.settings["CONFIG_PROTECT"].split()
- conf_mask_path = gentoolkit.settings["CONFIG_PROTECT_MASK"].split()
- conf_path = map(os.path.normpath, conf_path)
- conf_mask_path = map(os.path.normpath, conf_mask_path)
- for mykey in cnt.keys():
- is_conffile = False
- if cnt[mykey][0] == 'obj':
- for conf_dir in conf_path:
- if conf_dir+"/" == mykey[:len(conf_dir)+1]:
- is_conffile = True
- for conf_mask_dir in conf_mask_path:
- if conf_mask_dir+"/" == mykey[:len(conf_mask_dir)+1]:
- is_conffile = False
- break
- break
- if is_conffile:
- mycnt[mykey] = cnt[mykey]
-
-
- for mydoctype in ["doc","man","info"]:
- # List only files from /usr/share/{doc,man,info}
- mydocpath = "/usr/share/"+mydoctype+"/"
- if mydoctype in filter:
- for mykey in cnt.keys():
- if cnt[mykey][0] == 'obj' \
- and mykey[:len(mydocpath)] == mydocpath :
- mycnt[mykey] = cnt[mykey]
-
- return mycnt
-
- def perform(self, args):
-
- (query, opts) = self.parseArgs(args)
-
- # Turn off filtering for tree output
- if opts["tree"]:
- opts["filter"] = None
-
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print_info(3, "[ Searching for packages matching " + pp.pkgquery(query) + "... ]")
-
- pkgs = gentoolkit.find_installed_packages(query, True)
- for x in pkgs:
- if not x.is_installed():
- continue
-
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print_info(1, pp.section("* ") + "Contents of " + pp.cpv(x.get_cpv()) + ":")
-
- cnt = self.filterContents(x.get_contents(),opts["filter"])
-
- filenames = cnt.keys()
- filenames.sort()
-
- last=[]
- for name in filenames:
- if not opts["tree"]:
- print_info(0, fileAsStr(name,
- cnt[name],
- showType=opts["showType"],
- showTimestamp=opts["showTimestamp"],
- showMD5=opts["showMD5"]))
- else:
- c = name.split( "/" )[1:]
- if cnt[name][0] == "dir":
- if len(last) == 0:
- last = c
- print pp.path(" /" + c[0])
- continue
- numol = 0
- for d in c:
- if d in last:
- numol = last.index(d) + 1
- continue
- last = c
- if len(last) == 1:
- print pp.path(" " + last[0])
- continue
- print pp.path(" " * ( numol * 3 ) + "> " + "/" + last[-1])
- elif cnt[name][0] == "sym":
- print pp.path(" " * ( bl * 3 ) + "+ ") + pp.path_symlink(c[-1] + " -> " + cnt[name][2])
- else:
- bl = len(last)
- print pp.path(" " * ( bl * 3 ) + "+ ") + c[-1]
-
- def longHelp(self):
- return "List files owned by a particular package\n" + \
- "\n" + \
- "Syntax:\n" + \
- " " + pp.command("files") + pp.localoption(" <local-opts> ") + pp.pkgquery("<cat/>packagename<-version>") + "\n" + \
- "\n" + \
- "Note: category and version parts are optional. \n" + \
- "\n" + \
- pp.localoption("<local-opts>") + " is either of: \n" + \
- " " + pp.localoption("--timestamp") + " - append timestamp\n" + \
- " " + pp.localoption("--md5sum") + " - append md5sum\n" + \
- " " + pp.localoption("--type") + " - prepend file type\n" + \
- " " + pp.localoption("--tree") + " - display results in a tree (turns off other options)\n" + \
- " " + pp.localoption("--filter=<rules>") + " - filter output\n" + \
- " " + pp.localoption("<rules>") + " is a comma separated list of elements you want to see:\n" + \
- " " + " " + pp.localoption("dir") + \
- ", " + pp.localoption("obj") + \
- ", " + pp.localoption("sym") + \
- ", " + pp.localoption("dev") + \
- ", " + pp.localoption("fifo") + \
- ", " + pp.localoption("path") + \
- ", " + pp.localoption("conf") + \
- ", " + pp.localoption("cmd") + \
- ", " + pp.localoption("doc") + \
- ", " + pp.localoption("man") + \
- ", " + pp.localoption("info")
-
- def shortHelp(self):
- return pp.localoption("<local-opts> ") + pp.pkgquery("pkgspec") + " - list files owned by " + pp.pkgquery("pkgspec")
-
-
-class CmdListBelongs(Command):
- """List all packages owning a particular file"""
- def __init__(self):
- self.default_opts = {
- "category": "*",
- "fullRegex": 0,
- "earlyOut": 0,
- "nameOnly": 0
- }
-
- def parseArgs(self, args):
-
- query = []
- need_help = 0
- opts = self.default_opts
- skip = 0
-
- for i in xrange(len(args)):
-
- if skip:
- skip -= 1
- continue
- x = args[i]
-
- if x in ["-h","--help"]:
- need_help = 1
- break
- elif x in ["-c", "--category"]:
- opts["category"] = args[i+1]
- skip = 1
- elif x in ["-e", "--earlyout"]:
- opts["earlyOut"] = 1
- elif x in ["-f", "--full-regex"]:
- opts["fullRegex"] = 1
- elif x in ["-n", "--name-only"]:
- opts["nameOnly"] = 1
- elif x[0] == "-":
- print_warn("unknown local option %s, ignoring" % x)
- else:
- query.append(x)
-
- if need_help or query == []:
- print_info(0, self.longHelp())
- sys.exit(-1)
-
- return (query, opts)
-
- def perform(self, args):
- (query, opts) = self.parseArgs(args)
-
- if opts["fullRegex"]:
- q = query
- else:
- # Trim trailing and multiple slashes from query
- for i in range(0, len(query)):
- query[i] = re.compile('/+').sub('/', query[i])
- query[i] = query[i].rstrip('/')
- q = map(lambda x: ((len(x) and x[0] == "/") and "^" or "/")
- + re.escape(x) + "$", query)
- try:
- q = "|".join(q)
- rx = re.compile(q)
- except:
- die(2, "The query '" + pp.regexpquery(q) + "' does not appear to be a valid regular expression")
-
- # Pick out only selected categories
- cat = opts["category"]
- filter_fn = None
- if cat != "*":
- filter_fn = lambda x: x.find(cat+"/")==0
-
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print_info(3, "[ Searching for file(s) " + pp.regexpquery(",".join(query)) + " in " + pp.cpv(cat) + "... ]")
-
- matches = portage.db["/"]["vartree"].dbapi.cpv_all()
- #matches = gentoolkit.find_all_installed_packages(filter_fn)
-
- found = 0
-
- def dumpToPipe(pkg):
- mysplit = pkg.split("/")
- cnt = portage.dblink(mysplit[0], mysplit[1], "/", gentoolkit.settings).getcontents()
- #cnt = pkg.get_contents()
- if not cnt: return
- for file in cnt.keys():
- if rx.search(file) and (opts["category"] == "*" or portage.catpkgsplit(pkg)[0] == opts["category"]):
- if opts["nameOnly"]:
- x = portage.catpkgsplit(pkg)
- print x[0]+"/"+x[1]
- else:
- print pkg
- return
-
- class DummyExp:
- pass
-
- def dumpToScreen(pkg):
- mysplit = pkg.split("/")
- cnt = portage.dblink(mysplit[0], mysplit[1], "/", gentoolkit.settings).getcontents()
- #cnt = pkg.get_contents()
- if not cnt: return
- for file in cnt.keys():
- if rx.search(file) and (opts["category"] == "*" or portage.catpkgsplit(pkg)[0] == opts["category"]):
- if opts["nameOnly"]:
- x = portage.catpkgsplit(pkg)
- s = x[0]+"/"+x[1]
- else:
- s = pkg
- s += " (" + pp.path(fileAsStr(file, cnt[file])) + ")"
- print_info(0, s)
- if opts["earlyOut"]:
- raise DummyExp
-
- try:
- if Config["piping"]:
- map(dumpToPipe, matches)
- else:
- map(dumpToScreen, matches)
- except DummyExp:
- pass
-
- def shortHelp(self):
- return pp.localoption("<local-opts> ") + pp.path("files...") + " - list all packages owning " + pp.path("files...")
- def longHelp(self):
- return "List all packages owning a particular set of files" + \
- "\n" + \
- "\n" + \
- pp.emph("Note: ") + "Normally, only one package will own a file. If multiple packages own the same file, it usually consitutes a problem, and should be reported.\n" + \
- "\n" + \
- "Syntax:\n" + \
- " " + pp.command("belongs") + pp.localoption(" <local-opts> ") + pp.path("filename") + \
- "\n" + \
- pp.localoption("<local-opts>") + " is either of: \n" + \
- " " + pp.localoption("-c, --category cat") + " - only search in category " + \
- pp.pkgquery("cat") + "\n" + \
- " " + pp.localoption("-f, --full-regex") + " - supplied query is a regex\n" + \
- " " + pp.localoption("-e, --earlyout") + " - stop when first match is found\n" + \
- " " + pp.localoption("-n, --name-only") + " - don't print the version."
-
-class CmdDisplayUSEs(Command):
- """Advanced report of a package's USE flags"""
- def __init__(self):
- self.default_opts = {
- "allPackages" : False
- }
- def parseArgs(self, args):
-
- query = ""
- need_help = 0
- opts = self.default_opts
- skip = 0
-
- for i in xrange(len(args)):
-
- if skip:
- skip -= 1
- continue
- x = args[i]
-
- if x in ["-h","--help"]:
- need_help = 1
- break
- elif x in ["-a", "--all"]:
- opts["allPackages"] = True
- elif x[0] == "-":
- print_warn("unknown local option %s, ignoring" % x)
- else:
- query = x
-
- if need_help or query == "":
- print_info(0, self.longHelp())
- sys.exit(-1)
-
- return (query, opts)
-
- def perform(self, args):
-
- (query, opts) = self.parseArgs(args)
-
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print_info(3, "[ Searching for packages matching " + pp.pkgquery(query) + "... ]")
-
- if not opts["allPackages"]:
- matches = gentoolkit.find_installed_packages(query, True)
- if not matches:
- matches = gentoolkit.find_packages(query, False)
- if matches:
- matches = gentoolkit.sort_package_list(matches)
- matches = matches[-1:]
- else:
- matches = gentoolkit.find_packages(query, True)
-
- if not matches:
- die(3, "No matching packages found for \"" + pp.pkgquery(query) + "\"")
-
-
- useflags = gentoolkit.settings["USE"].split()
- usedesc = {}
- uselocaldesc = {}
-
- # Load global USE flag descriptions
- try:
- fd = open(gentoolkit.settings["PORTDIR"]+"/profiles/use.desc")
- usedesc = {}
- for line in fd.readlines():
- if line[0] == "#":
- continue
- fields = line.split(" - ", 1)
- if len(fields) == 2:
- usedesc[fields[0].strip()] = fields[1].strip()
- except IOError:
- print_warn(5, "Could not load USE flag descriptions from " + ppath(gentoolkit.settings["PORTDIR"] + "/profiles/use.desc"))
-
- # TODO: Add USE_EXPANDED variables to usedesc hash -- Bug #238005
- # Pseudo-code:
- # for all files in gentoolkit.settings["PORTDIR"]+"/desc/*.desc
- # variable name = <filename>_<field1>
- # description = <field 2>
- for descfile in glob(gentoolkit.settings["PORTDIR"]+"/profiles/desc/*.desc"):
- try:
- fd = open(descfile)
- for line in fd.readlines():
- if line[0] == "#":
- continue
- fields = [field.strip() for field in line.split(" - ", 1)]
- if len(fields) == 2:
- usedesc["%s_%s" % (descfile.split("/")[-1][0:-5], fields[0],)] = fields[1]
- except IOError:
- print_warn(5, "Could not load USE flag descriptions from " + descfile)
-
- # Load local USE flag descriptions
- try:
- fd = open(gentoolkit.settings["PORTDIR"]+"/profiles/use.local.desc")
- for line in fd.readlines():
- if line[0] == "#":
- continue
- fields = line.split(" - ", 1)
- if len(fields) == 2:
- catpkguse = re.search("(.*):(.*)", fields[0])
- if catpkguse:
- if not uselocaldesc.has_key(catpkguse.group(1).strip()):
- uselocaldesc[catpkguse.group(1).strip()] = {catpkguse.group(2).strip() : fields[1].strip()}
- else:
- uselocaldesc[catpkguse.group(1).strip()][catpkguse.group(2).strip()] = fields[1].strip()
- except IOError:
- print_warn(5, "Could not load USE flag descriptions from " + path(gentoolkit.settings["PORTDIR"] + "/profiles/use.local.desc"))
-
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print_info(3, "[ Colour Code : " + pp.useflagon("set") + " " + pp.useflagoff("unset") + " ]")
- print_info(3, "[ Legend : Left column (U) - USE flags from make.conf ]")
- print_info(3, "[ : Right column (I) - USE flags packages was installed with ]")
-
- # Iterate through matches, printing a report for each package
- matches = gentoolkit.sort_package_list(matches)
- matches_found = 0
- for p in matches:
-
- matches_found += 1
-
- bestver = p.get_cpv()
- iuse = p.get_env_var("IUSE")
-
- if iuse:
- # Fix Bug #91623 by making sure the list of USE flags is unique
- # Added sort to make output prettier
- usevar = unique_array(iuse.split())
-
- # Remove prefixed +/- from flags in IUSE, Bug #232019
- for i in range(len(usevar)):
- if usevar[i][0] == "+" or usevar[i][0] == "-":
- usevar[i] = usevar[i][1:]
-
- usevar.sort()
- else:
- usevar = []
-
- inuse = []
- if p.is_installed():
- used = p.get_use_flags().split()
- else:
- # cosmetic issue here as noninstalled packages don't have "used" flags
- used = useflags
-
- # store (inuse, inused, flag, desc)
- output = []
-
- for u in usevar:
- inuse = 0
- inused = 0
- try:
- desc = usedesc[u]
- except KeyError:
- try:
- desc = uselocaldesc[p.get_category() + "/" + p.get_name()][u]
- except KeyError:
- desc = ""
-
- if u in p.get_settings("USE").split():
- inuse = 1
- if u in used:
- inused = 1
-
- output.append((inuse, inused, u, desc))
-
- # pretty print
- if output:
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print_info(0, "[ Found these USE variables for " + pp.cpv(bestver) + " ]")
- print_info(3, pp.emph(" U I"))
- maxflag_len = 0
- for inuse, inused, u, desc in output:
- if len(u) > maxflag_len:
- maxflag_len = len(u)
-
- for in_makeconf, in_installed, flag, desc in output:
- markers = ["-","+"]
- colour = [pp.useflagoff, pp.useflagon]
- if Config["piping"]:
- print_info(0, markers[in_makeconf] + flag)
- else:
- if in_makeconf != in_installed:
- print_info(0, pp.emph(" %s %s" % (markers[in_makeconf], markers[in_installed])), False)
- else:
- print_info(0, " %s %s" % (markers[in_makeconf], markers[in_installed]), False)
-
- print_info(0, " " + colour[in_makeconf](flag.ljust(maxflag_len)), False)
-
- # print description
- if desc:
- print_info(0, " : " + desc)
- else:
- print_info(0, " : <unknown>")
- else:
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print_info(1, "[ No USE flags found for " + pp.cpv(p.get_cpv()) + "]")
-
- if Config["verbosityLevel"] >= 2:
- if matches_found == 0:
- s = ""
- die(3, "No " + s + "packages found for " + pp.pkgquery(query))
-
-
- def shortHelp(self):
- return pp.localoption("<local-opts> ") + pp.pkgquery("pkgspec") + " - display USE flags for " + pp.pkgquery("pkgspec")
- def longHelp(self):
- return "Display USE flags for a given package\n" + \
- "\n" + \
- "Syntax:\n" + \
- " " + pp.command("uses") + pp.localoption(" <local-opts> ") + pp.pkgquery("pkgspec") + \
- "\n" + \
- pp.localoption("<local-opts>") + " is: \n" + \
- " " + pp.localoption("-a, --all") + " - include all package versions\n"
-
-
-class CmdDisplayDepGraph(Command):
- """Display tree graph of dependencies for a query"""
-
- def __init__(self):
- self.default_opts = {
- "displayUSEFlags": 1,
- "fancyFormatting": 1,
- "depth": 0
- }
-
- def parseArgs(self, args):
-
- query = ""
- need_help = 0
- opts = self.default_opts
- skip = 0
-
- for i in xrange(len(args)):
-
- if skip:
- skip -= 1
- continue
- x = args[i]
-
- if x in ["-h","--help"]:
- need_help = 1
- break
- elif x in ["-U","--no-useflags"]:
- opts["displayUSEFlags"] = 0
- elif x in ["-l","--linear"]:
- opts["fancyFormatting"] = 0
- elif x[:8] == "--depth=":
- opts["depth"] = int(x[8:])
- elif x[0] == "-":
- print_warn("unknown local option %s, ignoring" % x)
- else:
- query = x
-
- if need_help or query == "":
- print_info(0, self.longHelp())
- sys.exit(-1)
-
- return (query, opts)
-
- def perform(self, args):
- (query, opts) = self.parseArgs(args)
-
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print_info(3, "[ Searching for packages matching " + pp.pkgquery(query) + "... ]")
-
- matches = gentoolkit.find_packages(query, True)
-
- for pkg in matches:
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print_info(3, pp.section("* ") + "dependency graph for " + pp.cpv(pkg.get_cpv()))
- else:
- print_info(0, pkg.get_cpv() + ":")
-
- stats = { "maxdepth": 0, "packages": 0 }
- self._graph(pkg, opts, stats, 0, [], "")
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print_info(0, "[ " + pp.cpv(pkg.get_cpv()) + " stats: packages (" + pp.number(str(stats["packages"])) + \
- "), max depth (" + pp.number(str(stats["maxdepth"])) + ") ]")
-
- def _graph(self, pkg, opts, stats, level=0, pkgtbl=[], suffix=""):
-
- stats["packages"] += 1
- stats["maxdepth"] = max(stats["maxdepth"], level)
-
- cpv = pkg.get_cpv()
-
- pfx = ""
- if opts["fancyFormatting"]:
- pfx = level * " " + "`-- "
- print_info(0, pfx + cpv + suffix)
-
- pkgtbl.append(cpv)
-
- pkgdeps = pkg.get_runtime_deps() + pkg.get_compiletime_deps() + pkg.get_postmerge_deps()
- for x in pkgdeps:
- suffix = ""
- cpv = x[2]
- pkg = gentoolkit.find_best_match(x[0] + cpv)
- if not pkg:
- print pfx + x[0] + cpv + " (unable to resolve to a package / package masked or removed)"
- continue
- if pkg.get_cpv() in pkgtbl:
- continue
- if cpv.find("virtual") == 0:
- suffix += " (" + pp.cpv(cpv) + ")"
- if len(x[1]) and opts["displayUSEFlags"]:
- suffix += " [ " + pp.useflagon(' '.join(x[1])) + " ]"
- if (level < opts["depth"] or opts["depth"] <= 0):
- pkgtbl = self._graph(pkg, opts, stats, level+1, pkgtbl, suffix)
- return pkgtbl
-
- def shortHelp(self):
- return pp.localoption("<local-opts> ") + pp.pkgquery("pkgspec") + " - display a dependency tree for " + pp.pkgquery("pkgspec")
- def longHelp(self):
- return "Display a dependency tree for a given package\n" + \
- "\n" + \
- "Syntax:\n" + \
- " " + pp.command("depgraph") + pp.localoption(" <local-opts> ") + pp.pkgquery("pkgspec") + \
- "\n" + \
- pp.localoption("<local-opts>") + " is either of: \n" + \
- " " + pp.localoption("-U, --no-useflags") + " - do not show USE flags\n" + \
- " " + pp.localoption("-l, --linear") + " - do not use fancy formatting\n" + \
- " " + pp.localoption(" --depth=n") + " - limit dependency graph to specified depth"
-
-
-class CmdDisplaySize(Command):
- """Display disk size consumed by a package"""
- def __init__(self):
- self.default_opts = {
- "regex": 0,
- "exact": 0,
- "reportSizeInBytes": 0
- }
-
- def parseArgs(self, args):
-
- query = ""
- need_help = 0
- opts = self.default_opts
- skip = 0
-
- for i in xrange(len(args)):
-
- if skip:
- skip -= 1
- continue
- x = args[i]
-
- if x in ["-h","--help"]:
- need_help = 1
- break
- elif x in ["-b","--bytes"]:
- opts["reportSizeInBytes"] = 1
- elif x in ["-f", "--full-regex"]:
- opts["regex"] = 1
- elif x in ["-e", "--exact-name"]:
- opts["exact"] = 1
- elif x[0] == "-":
- print_warn("unknown local option %s, ignoring" % x)
- else:
- query = x
-
-# if need_help or query == "":
- if need_help:
- print_info(0, self.longHelp())
- sys.exit(-1)
-
- return (query, opts)
-
- def perform(self, args):
- (query, opts) = self.parseArgs(args)
-
- rev = ""
- name = ""
- ver = ""
- cat = ""
-
- if query != "":
- (cat, name, ver, rev) = gentoolkit.split_package_name(query)
- if rev == "r0": rev = ""
-
- # replace empty strings with .* and escape regular expression syntax
- if query != "":
- if not opts["regex"]:
- cat, name, ver, rev = [re.sub('^$', ".*", re.escape(x)) for x in cat, name, ver, rev]
- else:
- cat, name, ver, rev = [re.sub('^$', ".*", x) for x in cat, name, ver, rev]
-
- try:
- if opts["exact"]:
- filter_fn = lambda x: re.match(cat+"/"+name, x)
- else:
- filter_fn = lambda x: re.match(cat+"/.*"+name, x)
- matches = gentoolkit.find_all_installed_packages(filter_fn)
- except:
- die(2, "The query '" + pp.regexpquery(query) + "' does not appear to be a valid regular expression")
- else:
- cat, name, ver, rev = [re.sub('^$', ".*", x) for x in cat, name, ver, rev]
- matches = gentoolkit.find_all_installed_packages()
-
- matches = gentoolkit.sort_package_list(matches)
-
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print_info(3, "[ Searching for packages matching " + pp.pkgquery(query) + "... ]")
-
- # If no version supplied, fix regular expression
- if ver == ".*": ver = "[0-9]+[^-]*"
-
- if rev != ".*": # revision supplied
- ver = ver + "-" + rev
-
- if opts["exact"]:
- rx = re.compile(cat + "/" + name + "-" + ver)
- else:
- rx = re.compile(cat + "/.*" + name + ".*-" + ver)
-
- for pkg in matches:
- if rx.search(pkg.get_cpv()):
- (size, files, uncounted) = pkg.size()
-
- if Config["piping"]:
- print_info(0, pkg.get_cpv() + ": total(" + str(files) + "), inaccessible(" + str(uncounted) + \
- "), size(" + str(size) + ")")
- else:
- print_info(0, pp.section("* ") + "size of " + pp.cpv(pkg.get_cpv()))
- print_info(0, " Total files : ".rjust(25) + pp.number(str(files)))
-
- if uncounted:
- print_info(0, " Inaccessible files : ".rjust(25) + pp.number(str(uncounted)))
-
- sz = "%.2f KiB" % (size/1024.0)
- if opts["reportSizeInBytes"]:
- sz = pp.number(str(size)) + " bytes"
-
- print_info(0, "Total size : ".rjust(25) + pp.number(sz))
-
-
- def shortHelp(self):
- return pp.localoption("<local-opts> ") + pp.pkgquery("pkgspec") + " - print size of files contained in package " + pp.pkgquery("pkgspec")
- def longHelp(self):
- return "Print size total size of files contained in a given package" + \
- "\n" + \
- "Syntax:\n" + \
- " " + pp.command("size") + pp.localoption(" <local-opts> ") + pp.pkgquery("pkgspec") + \
- "\n" + \
- pp.localoption("<local-opts>") + " is: \n" + \
- " " + pp.localoption("-b, --bytes") + " - report size in bytes\n" \
- " " + pp.localoption("-f, --full-regex") + " - query is a regular expression\n" + \
- " " + pp.localoption("-e, --exact-name") + " - list only those packages that exactly match\n"
-
-class CmdDisplayChanges(Command):
- """Display changes for pkgQuery"""
- pass
-
-class CheckException:
- def __init__(self, s):
- self.s = s
-
-class CmdCheckIntegrity(Command):
- """Check timestamps and md5sums for files owned by pkgspec"""
- def __init__(self):
- self.default_opts = {
- "showSummary" : 1,
- "showGoodFiles" : 0,
- "showBadFiles" : 1,
- "checkTimestamp" : 1,
- "checkMD5sum": 1
- }
-
- def parseArgs(self, args):
-
- query = ""
- need_help = 0
- opts = self.default_opts
- skip = 0
-
- for i in xrange(len(args)):
- if skip:
- skip -= 1
- continue
- x = args[i]
-
- if x in ["-h","--help"]:
- need_help = 1
- break
- elif x[0] == "-":
- print_warn("unknown local option %s, ignoring" % x)
- else:
- query = x
-
- if need_help:
- print_info(0, self.longHelp())
- sys.exit(-1)
-
- return (query, opts)
-
- def getMD5sum(self, file):
- return checksum.perform_md5(file, calc_prelink=1)
-
- def perform(self, args):
- (query, opts) = self.parseArgs(args)
-
- if query == "":
- matches=gentoolkit.find_all_installed_packages()
- else:
- matches = gentoolkit.find_packages(query, True)
-
- matches = gentoolkit.sort_package_list(matches)
-
- for pkg in matches:
- if not pkg.is_installed():
- continue
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print_info(1, "[ Checking " + pp.cpv(pkg.get_cpv()) + " ]")
- else:
- print_info(0, pkg.get_cpv() + ":")
-
- files = pkg.get_contents()
- checked_files = 0
- good_files = 0
- for file in files.keys():
- type = files[file][0]
- try:
- st = os.lstat(file)
- if type == "dir":
- if not os.path.isdir(file):
- raise CheckException(file + " exists, but is not a directory")
- elif type == "obj":
- mtime = files[file][1]
- md5sum = files[file][2]
- if opts["checkMD5sum"]:
- try:
- actual_checksum = self.getMD5sum(file)
- except:
- raise CheckException("Failed to calculate MD5 sum for " + file)
-
- if self.getMD5sum(file) != md5sum:
- raise CheckException(file + " has incorrect md5sum")
- if opts["checkTimestamp"]:
- if int(st.st_mtime) != int(mtime):
- raise CheckException(file + (" has wrong mtime (is %d, should be %s)" % (st.st_mtime, mtime)))
- elif type == "sym":
- # FIXME: nastry strippery; portage should have this fixed!
- t = files[file][2]
- # target = os.path.normpath(t.strip())
- target = t.strip()
- if not os.path.islink(file):
- raise CheckException(file + " exists, but is not a symlink")
- tgt = os.readlink(file)
- if tgt != target:
- raise CheckException(file + " does not point to " + target)
- elif type == "fif":
- pass
- else:
- pp.print_error(file)
- pp.print_error(files[file])
- pp.print_error(type)
- raise CheckException(file + " has unknown type " + type)
- good_files += 1
- except CheckException, (e):
- print_error(e.s)
- except OSError:
- print_error(file + " does not exist")
- checked_files += 1
- print_info(0, pp.section(" * ") + pp.number(str(good_files)) + " out of " + pp.number(str(checked_files)) + " files good")
-
- def shortHelp(self):
- return pp.pkgquery("pkgspec") + " - check MD5sums and timestamps of " + pp.pkgquery("pkgspec") + "'s files"
- def longHelp(self):
- return "Check package's files against recorded MD5 sums and timestamps" + \
- "\n" + \
- "Syntax:\n" + \
- " " + pp.command("check") + pp.pkgquery(" pkgspec")
-
-class CmdDisplayStatistics(Command):
- """Display statistics about installed and uninstalled packages"""
- pass
-
-class CmdWhich(Command):
- """Display the filename of the ebuild for a given package
- that would be used by Portage with the current configuration."""
- def __init__(self):
- self.default_opts = {
- "includeMasked": False
- }
-
- def parseArgs(self, args):
-
- query = ""
- need_help = 0
- opts = self.default_opts
- skip = 0
-
- for i in xrange(len(args)):
-
- if skip:
- skip -= 1
- continue
- x = args[i]
-
- if x in ["-h","--help"]:
- need_help = 1
- break
- elif x in ["-m", "--include-masked"]:
- opts["includeMasked"] = True
- elif x[0] == "-":
- print_warn("unknown local option %s, ignoring" % x)
- else:
- query = x
-
- if need_help or query == "":
- print_info(0, self.longHelp())
- sys.exit(-1)
-
- return (query, opts)
-
- def perform(self, args):
- (query, opts) = self.parseArgs(args)
-
- matches = gentoolkit.find_packages(query, opts["includeMasked"])
- matches = gentoolkit.sort_package_list(matches)
-
- if matches:
- pkg = matches[-1]
- ebuild_path = pkg.get_ebuild_path()
- if ebuild_path:
- print_info(0, os.path.normpath(ebuild_path))
- else:
- print_warn("There are no ebuilds to satisfy %s" % pkg.get_name())
- else:
- print_error("No masked or unmasked packages found for " + pp.pkgquery(query))
-
- def shortHelp(self):
- return pp.pkgquery("pkgspec") + " - print full path to ebuild for package " + pp.pkgquery("pkgspec")
- def longHelp(self):
- # Not documenting --include-masked at this time, since I'm not sure that it is needed. - FuzzyRay
- return "Print full path to ebuild for a given package" + \
- "\n" + \
- "Syntax:\n" + \
- " " + pp.command("which ") + pp.pkgquery("pkgspec")
-
-class CmdListGLSAs(Command):
- """List outstanding GLSAs."""
- pass
-
-class CmdListDepends(Command):
- """List all packages directly or indirectly depending on pkgQuery"""
- def __init__(self):
- self.default_opts = {
- "onlyDirect": 1,
- "onlyInstalled": 1,
- "spacing": 0,
- "depth": -1
- }
- # Used to cache and detect looping
- self.pkgseen = []
- self.pkglist = []
- self.pkgdeps = {}
- self.deppkgs = {}
-
- def parseArgs(self, args):
-
- query = ""
- need_help = 0
- opts = self.default_opts
- skip = 0
-
- for i in xrange(len(args)):
- if skip:
- skip -= 1
- continue
- x = args[i]
-
- if x in ["-h","--help"]:
- need_help = 1
- break
- elif x in ["-d", "--direct"]:
- opts["onlyDirect"] = 1
- elif x in ["-D", "--indirect"]:
- opts["onlyDirect"] = 0
- elif x in ["-a", "--all-packages"]:
- opts["onlyInstalled"] = 0
- elif x[:10] == "--spacing=":
- opts["spacing"] = int(x[10:])
- elif x[:8] == "--depth=":
- opts["depth"] = int(x[8:])
- elif x[0] == "-":
- print_warn("unknown local option %s, ignoring" % x)
- else:
- query = x
-
- if need_help or query == "":
- print self.longHelp()
- sys.exit(-1)
- return (query, opts)
-
- def perform(self, args):
-
- (query, opts) = self.parseArgs(args)
-
- # We call ourself recursively if --indirect specified. spacing is used to control printing the tree.
- spacing = opts["spacing"]
-
- if not Config["piping"] and Config["verbosityLevel"] >= 3 and not spacing:
- print_info(3, "[ Searching for packages depending on " + pp.pkgquery(query) + "... ]")
-
- isdepend = gentoolkit.split_package_name(query)
- isdepends = map((lambda x: x.get_cpv()), gentoolkit.find_packages(query))
- if not isdepends:
- print_warn("Warning: No packages found matching %s" % query)
-
- # Cache the list of packages
- if not self.pkglist:
- if opts["onlyInstalled"]:
- packages = gentoolkit.find_all_installed_packages()
- else:
- packages = gentoolkit.find_all_packages()
-
- packages = gentoolkit.sort_package_list(packages)
- self.pkglist = packages
- else:
- packages = self.pkglist
-
- for pkg in packages:
- pkgcpv = pkg.get_cpv()
- if not pkgcpv in self.pkgdeps:
- try:
- deps = pkg.get_runtime_deps() + pkg.get_compiletime_deps() + pkg.get_postmerge_deps()
- except KeyError, e:
- # If the ebuild is not found...
- continue
- # Remove duplicate deps
- deps = unique_array(deps)
- self.pkgdeps[pkgcpv] = deps
- else:
- deps = self.pkgdeps[pkgcpv]
- isdep = 0
- for dependency in deps:
- # TODO determine if dependency is enabled by USE flag
- # Find all packages matching the dependency
- depstr = dependency[0]+dependency[2]
- if not depstr in self.deppkgs:
- try:
- depcpvs = map((lambda x: x.get_cpv()), gentoolkit.find_packages(depstr))
- self.deppkgs[depstr] = depcpvs
- except KeyError, e:
- print_warn("")
- print_warn("Package: " + pkgcpv + " contains invalid dependency specification.")
- print_warn("Portage error: " + str(e))
- print_warn("")
- continue
- else:
- depcpvs = self.deppkgs[depstr]
- for x in depcpvs:
- cpvs=gentoolkit.split_package_name(x)
- if x in isdepends:
- cat_match=1
- name_match=1
- ver_match=1
- else:
- cat_match=0
- name_match=0
- ver_match=0
- # Match Category
- if not isdepend[0] or cpvs[0] == isdepend[0]:
- cat_match=1
- # Match Name
- if cpvs[1] == isdepend[1]:
- name_match=1
- # Match Version
- if not isdepend[2] or ( cpvs[2] == isdepend[2] and (isdepend[3] \
- or isdepend[3] == "r0" or cpvs[3] == isdepend[3])):
- ver_match=1
-
- if cat_match and ver_match and name_match:
- if not isdep:
- if dependency[1]:
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print " " * (spacing * 2) + pp.cpv(pkg.get_cpv()),
- print "(" + \
- pp.useflag(" & ".join(dependency[1]) + "? ") + \
- pp.pkgquery(dependency[0]+dependency[2]) + ")"
- else:
- print " " * (spacing * 2) + pkg.get_cpv()
- else:
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print " " * (spacing * 2) + pp.cpv(pkg.get_cpv()),
- print "(" + pp.pkgquery(dependency[0]+dependency[2]) + ")"
- else:
- print " " * (spacing * 2) + pkg.get_cpv()
- isdep = 1
- elif not Config["piping"] and Config["verbosityLevel"] >= 3:
- if dependency[1]:
- print " "*len(pkg.get_cpv()) + " " * (spacing * 2) + \
- " (" + pp.useflag("&".join(dependency[1]) + "? ") + \
- pp.pkgquery(dependency[0]+dependency[2]) + ")"
- else:
- print " "*len(pkg.get_cpv()) + " " * (spacing * 2) + " (" + \
- pp.pkgquery(dependency[0]+dependency[2]) + ")"
-
- break
-
- # if --indirect specified, call ourselves again with the dependency
- # Do not call, if we have already called ourselves.
- if isdep and not opts["onlyDirect"] and pkg.get_cpv() not in self.pkgseen \
- and (spacing < opts["depth"] or opts["depth"] == -1):
- self.pkgseen.append(pkg.get_cpv())
- self.perform(['=' + pkg.get_cpv(), '--indirect', '--spacing=' + str(int(opts["spacing"]+1))])
- opts["spacing"] = spacing;
-
-
- def shortHelp(self):
- return pp.localoption("<local-opts> ") + pp.pkgquery("pkgspec") + " - list all direct dependencies matching " + \
- pp.pkgquery("pkgspec")
-
- def longHelp(self):
- return "List all direct dependencies matching a query pattern" + \
- "\n" + \
- "Syntax:\n" + \
- " " + pp.command("depends") + pp.localoption(" <local-opts> ") + pp.pkgquery("pkgspec") + \
- "\n" + \
- pp.localoption("<local-opts>") + " is either of: \n" + \
- " " + pp.localoption("-a, --all-packages") + " - search in all available packages (slow)\n" + \
- " " + pp.localoption("-d, --direct") + " - search direct dependencies only (default)\n" + \
- " " + pp.localoption("-D, --indirect") + " - search indirect dependencies (VERY slow)\n" + \
- " " + pp.localoption(" --depth=n") + " - limit indirect dependency tree to specified depth"
-
-
-class CmdListPackages(Command):
- """List packages satisfying pkgQuery"""
- def __init__(self):
- self.default_opts = {
- "category": "*",
- "includeInstalled": 1,
- "includePortTree": 0,
- "includeOverlayTree": 0,
- "includeMasked": 1,
- "regex": 0,
- "exact": 0,
- "duplicates": 0
- }
-
- def parseArgs(self, args):
-
- query = ""
- need_help = 0
- opts = self.default_opts
- skip = 0
-
- for i in xrange(len(args)):
-
- if skip:
- skip -= 1
- continue
- x = args[i]
-
- if x in ["-h","--help"]:
- need_help = 1
- break
- elif x in ["-i", "--installed"]:
- opts["includeInstalled"] = 1
- elif x in ["-I", "--exclude-installed"]:
- # If -I is the only option, warn
- # (warning located in perform())
- opts["includeInstalled"] = 0
- elif x in ["-p", "--portage-tree"]:
- opts["includePortTree"] = 1
- elif x in ["-o", "--overlay-tree"]:
- opts["includeOverlayTree"] = 1
- elif x in ["-m", "--exclude-masked"]:
- opts["includeMasked"] = 0
- elif x in ["-f", "--full-regex"]:
- opts["regex"] = 1
- elif x in ["-e", "--exact-name"]:
- opts["exact"] = 1
- elif x in ["-d", "--duplicates"]:
- opts["duplicates"] = 1
- elif x[0] == "-":
- print_warn("unknown local option %s, ignoring" % x)
- else:
- query = x
-
- # Only search installed packages when listing duplicated packages
- if opts["duplicates"]:
- opts["includeInstalled"] = 1
- opts["includePortTree"] = 0
- opts["includeOverlayTree"] = 0
-
- if need_help:
- print_info(0, self.longHelp())
- sys.exit(-1)
-
- return (query, opts)
-
- def perform(self, args):
- (query, opts) = self.parseArgs(args)
-
- rev = ""
- name = ""
- ver = ""
- cat = ""
-
- if query != "":
- try: (cat, name, ver, rev) = gentoolkit.split_package_name(query)
- except ValueError, e:
- if str(e) == 'too many values to unpack':
- print_error("A pattern to match against package names was expected, ")
- warn_msg = "but %s has too many slashes ('/') to match any package."
- die (1, warn_msg % query)
- else: raise ValueError(e)
- if rev == "r0": rev = ""
-
- package_finder = None
-
- if opts["includeInstalled"]:
- if opts["includePortTree"] or opts["includeOverlayTree"]:
- package_finder = gentoolkit.find_all_packages
- else:
- package_finder = gentoolkit.find_all_installed_packages
- elif opts["includePortTree"] or opts["includeOverlayTree"]:
- package_finder = gentoolkit.find_all_uninstalled_packages
- else:
- # -I was specified, and no selection of what packages to list was made
- print_warn("With -I you must specify one of -i, -p or -o. Assuming -p")
- opts["includePortTree"] = 1
- package_finder = gentoolkit.find_all_uninstalled_packages
-
- filter_fn = None
-
- if Config["verbosityLevel"] >= 3:
- scat = "'" + cat + "'"
- if not cat:
- scat = "all categories"
- sname = "package '" + name + "'"
- if not name:
- sname = "all packages"
- if not Config["piping"] and Config["verbosityLevel"] >= 3:
- print_info(1, "[ Searching for " + pp.cpv(sname) + " in " + pp.cpv(scat) + " among: ]")
-
- # replace empty strings with .* and escape regular expression syntax
- if query != "":
- if not opts["regex"]:
- cat, name, ver, rev = [re.sub('^$', ".*", re.escape(x)) for x in cat, name, ver, rev]
- else:
- cat, name, ver, rev = [re.sub('^$', ".*", x) for x in cat, name, ver, rev]
-
- try:
- if opts["exact"]:
- filter_fn = lambda x: re.match(cat+"/"+name, x)
- else:
- filter_fn = lambda x: re.match(cat+"/.*"+name, x)
- matches = package_finder(filter_fn)
- except:
- die(2, "The query '" + pp.regexpquery(query) + "' does not appear to be a valid regular expression")
- else:
- cat, name, ver, rev = [re.sub('^$', ".*", x) for x in cat, name, ver, rev]
- filter_fn = lambda x: True
- matches = package_finder(filter_fn)
-
- # Find duplicate packages
- if opts["duplicates"]:
- dups = {}
- newmatches = []
- for pkg in matches:
- mykey = pkg.get_category() + "/" + pkg.get_name()
- if dups.has_key(mykey):
- dups[mykey].append(pkg)
- else:
- dups[mykey] = [pkg]
-
- for mykey in dups.keys():
- if len(dups[mykey]) > 1:
- newmatches += dups[mykey]
-
- matches = newmatches
-
- matches = gentoolkit.sort_package_list(matches)
-
- # If no version supplied, fix regular expression
- if ver == ".*": ver = "[0-9]+[^-]*"
-
- if rev != ".*": # revision supplied
- ver = ver + "-" + rev
-
- if opts["exact"]:
- rx = re.compile(cat + "/" + name + "-" + ver)
- else:
- rx = re.compile(cat + "/.*" + name + ".*-" + ver)
-
- if opts["includeInstalled"]:
- self._print_installed(matches, rx)
-
- if opts["includePortTree"]:
- self._print_porttree(matches, rx)
-
- if opts["includeOverlayTree"]:
- self._print_overlay(matches, rx)
-
- def _get_mask_status(self, pkg):
- pkgmask = 0
- if pkg.is_masked():
- # Uncomment to only have package masked files show an 'M'
- # maskreasons = portage.getmaskingstatus(pkg.get_cpv())
- # if "package.mask" in maskreasons:
- pkgmask = pkgmask + 3
- keywords = pkg.get_env_var("KEYWORDS").split()
- if gentoolkit.settings["ARCH"] not in keywords:
- if "~" + gentoolkit.settings["ARCH"] in keywords:
- pkgmask = pkgmask + 1
- elif "-" + gentoolkit.settings["ARCH"] in keywords or "-*" in keywords:
- pkgmask = pkgmask + 2
- return pkgmask
-
- def _generic_print(self, header, exclude, matches, rx, status):
- if Config["verbosityLevel"] >= 3:
- print_info(1, header)
-
- pfxmodes = [ "---", "I--", "-P-", "--O" ]
- maskmodes = [ " ", " ~", " -", "M ", "M~", "M-" ]
-
- for pkg in matches:
- if exclude(pkg):
- continue
-
- pkgmask = self._get_mask_status(pkg)
-
- slot = pkg.get_env_var("SLOT")
-
- if rx.search(pkg.get_cpv()):
- if Config["piping"]:
- print_info(0, pkg.get_cpv())
- else:
- print_info(0, "[" + pp.installedflag(pfxmodes[status]) + "] [" + pp.maskflag(maskmodes[pkgmask]) + "] " + pp.cpv(pkg.get_cpv()) + " (" + pp.slot(slot) + ")")
-
- def _print_overlay(self, matches, rx):
- self._generic_print(
- pp.section(" *") + " overlay tree (" + pp.path(gentoolkit.settings["PORTDIR_OVERLAY"]) + ")",
- lambda x: not x.is_overlay(),
- matches, rx, 3)
-
- def _print_porttree(self, matches, rx):
- self._generic_print(
- pp.section(" *") + " Portage tree (" + pp.path(gentoolkit.settings["PORTDIR"]) + ")",
- lambda x: x.is_overlay() or x.is_installed(),
- matches, rx, 2)
-
- def _print_installed(self, matches, rx):
- self._generic_print(
- pp.section(" *") + " installed packages",
- lambda x: not x.is_installed(),
- matches, rx, 1)
-
- def shortHelp(self):
- return pp.localoption("<local-opts> ") + pp.pkgquery("pkgspec") + " - list all packages matching " + pp.pkgquery("pkgspec")
- def longHelp(self):
- return "List all packages matching a query pattern" + \
- "\n" + \
- "Syntax:\n" + \
- " " + pp.command("list") + pp.localoption(" <local-opts> ") + pp.pkgquery("pkgspec") + \
- "\n" + \
- pp.localoption("<local-opts>") + " is either of: \n" + \
- " " + pp.localoption("-i, --installed") + " - search installed packages (default)\n" + \
- " " + pp.localoption("-I, --exclude-installed") + " - do not search installed packages\n" + \
- " " + pp.localoption("-p, --portage-tree") + " - also search in portage tree (" + gentoolkit.settings["PORTDIR"] + ")\n" + \
- " " + pp.localoption("-o, --overlay-tree") + " - also search in overlay tree (" + gentoolkit.settings["PORTDIR_OVERLAY"] + ")\n" + \
- " " + pp.localoption("-f, --full-regex") + " - query is a regular expression\n" + \
- " " + pp.localoption("-e, --exact-name") + " - list only those packages that exactly match\n" + \
- " " + pp.localoption("-d, --duplicates") + " - list only installed duplicate packages\n"
-
-class CmdFindUSEs(Command):
- """Find all packages with a particular USE flag."""
- def __init__(self):
- self.default_opts = {
- "category": "*",
- "includeInstalled": 1,
- "includePortTree": 0,
- "includeOverlayTree": 0,
- "includeMasked": 1,
- "regex": 0
- }
-
- def parseArgs(self, args):
-
- query = ""
- need_help = 0
- opts = self.default_opts
- skip = 0
-
- for i in xrange(len(args)):
-
- if skip:
- skip -= 1
- continue
- x = args[i]
-
- if x in ["-h","--help"]:
- need_help = 1
- break
- elif x in ["-i", "--installed"]:
- opts["includeInstalled"] = 1
- elif x in ["-I", "--exclude-installed"]:
- opts["includeInstalled"] = 0
- elif x in ["-p", "--portage-tree"]:
- opts["includePortTree"] = 1
- elif x in ["-o", "--overlay-tree"]:
- opts["includeOverlayTree"] = 1
- elif x in ["-m", "--exclude-masked"]:
- opts["includeMasked"] = 0
- elif x[0] == "-":
- print_warn("unknown local option %s, ignoring" % x)
- else:
- query = x
-
- if need_help:
- print_info(0, self.longHelp())
- sys.exit(-1)
-
- return (query, opts)
-
- def perform(self, args):
- (query, opts) = self.parseArgs(args)
-
- rev = ".*"
- name = ".*"
- ver = ".*"
- cat = ".*"
-
- package_finder = None
-
- if opts["includeInstalled"] and (opts["includePortTree"] or opts["includeOverlayTree"]):
- package_finder = gentoolkit.find_all_packages
- elif opts["includeInstalled"]:
- package_finder = gentoolkit.find_all_installed_packages
- elif opts["includePortTree"] or opts["includeOverlayTree"]:
- package_finder = gentoolkit.find_all_uninstalled_packages
-
- if not package_finder:
- die(2,"You must specify one of -i, -p or -o")
-
- filter_fn = lambda x: True
-
- if Config["verbosityLevel"] >= 3:
- scat = "'" + cat + "'"
- if cat == ".*":
- scat = "all categories"
- if not Config["piping"]:
- print_info(2, "[ Searching for USE flag " + pp.useflag(query) + " in " + pp.cpv(scat) + " among: ]")
- if opts["includeInstalled"]:
- print_info(1, pp.section(" *") + " installed packages")
- if opts["includePortTree"]:
- print_info(1, pp.section(" *") + " Portage tree (" + pp.path(gentoolkit.settings["PORTDIR"]) + ")")
- if opts["includeOverlayTree"]:
- print_info(1, pp.section(" *") + " overlay tree (" + pp.path(gentoolkit.settings["PORTDIR_OVERLAY"]) + ")")
-
- matches = package_finder(filter_fn)
-
- rx = re.compile(cat + "/" + name + "-" + ver + "(-" + rev + ")?")
- pfxmodes = [ "---", "I--", "-P-", "--O" ]
- maskmodes = [ " ", " ~", " -", "M ", "M~", "M-" ]
- for pkg in matches:
- status = 0
- if pkg.is_installed():
- status = 1
- elif pkg.is_overlay():
- status = 3
- else:
- status = 2
-
- useflags = pkg.get_env_var("IUSE").split()
- useflags = [f.lstrip("+-") for f in useflags]
-
- if query not in useflags:
- continue
-
- # Determining mask status
- pkgmask = 0
- if pkg.is_masked():
- pkgmask = pkgmask + 3
- keywords = pkg.get_env_var("KEYWORDS").split()
- if "~"+gentoolkit.settings["ARCH"] in keywords:
- pkgmask = pkgmask + 1
- elif "-*" in keywords or "-"+gentoolkit.settings["ARCH"] in keywords:
- pkgmask = pkgmask + 2
-
- # Determining SLOT value
- slot = pkg.get_env_var("SLOT")
-
- if (status == 1 and opts["includeInstalled"]) or \
- (status == 2 and opts["includePortTree"]) or \
- (status == 3 and opts["includeOverlayTree"]):
- if Config["piping"]:
- print_info(0, pkg.get_cpv())
- else:
- print_info(0, "[" + pp.installedflag(pfxmodes[status]) + "] [" + pp.maskflag(maskmodes[pkgmask]) + "] " + pp.cpv(pkg.get_cpv()) + " (" + pp.slot(slot) + ")")
-
- def shortHelp(self):
- return pp.localoption("<local-opts> ") + pp.pkgquery("useflag") + " - list all packages with " + pp.pkgquery("useflag")
- def longHelp(self):
- return "List all packages with a particular USE flag" + \
- "\n" + \
- "Syntax:\n" + \
- " " + pp.command("list") + pp.localoption(" <local-opts> ") + pp.pkgquery("useflag") + \
- "\n" + \
- pp.localoption("<local-opts>") + " is either of: \n" + \
- " " + pp.localoption("-i, --installed") + " - search installed packages (default)\n" + \
- " " + pp.localoption("-I, --exclude-installed") + " - do not search installed packages\n" + \
- " " + pp.localoption("-p, --portage-tree") + " - also search in portage tree (" + gentoolkit.settings["PORTDIR"] + ")\n" + \
- " " + pp.localoption("-o, --overlay-tree") + " - also search in overlay tree (" + gentoolkit.settings["PORTDIR_OVERLAY"] + ")\n"
-
-#
-# Command line tokens to commands mapping
-#
-
-Known_commands = {
- "list" : CmdListPackages(),
- "files" : CmdListFiles(),
- "belongs" : CmdListBelongs(),
- "depends" : CmdListDepends(),
- "hasuse" : CmdFindUSEs(),
- "uses" : CmdDisplayUSEs(),
- "depgraph" : CmdDisplayDepGraph(),
- "changes" : CmdDisplayChanges(),
- "size" : CmdDisplaySize(),
- "check" : CmdCheckIntegrity(),
- "stats" : CmdDisplayStatistics(),
- "glsa" : CmdListGLSAs(),
- "which": CmdWhich()
- }
-
-# Short command line tokens
-
-Short_commands = {
- "a" : "glsa",
- "b" : "belongs",
- "c" : "changes",
- "d" : "depends",
- "f" : "files",
- "g" : "depgraph",
- "h" : "hasuse",
- "k" : "check",
- "l" : "list",
- "s" : "size",
- "t" : "stats",
- "u" : "uses",
- "w" : "which"
-}
-
-from gentoolkit import Config
-
-Config = {
- # Query will include packages installed on the system
- "installedPackages": 1,
- # Query will include packages available for installation
- "uninstalledPackages": 0,
- # Query will include overlay packages (iff uninstalledPackages==1)
- "overlayPackages": 1,
- # Query will include masked packages (iff uninstalledPackages==1)
- "maskedPackages": 0,
- # Query will only consider packages in the following categories, empty means all.
- "categoryFilter": [],
- # Enable color output (-1 = use Portage setting, 0 = force off, 1 = force on)
- "color": -1,
- # Level of detail on the output
- "verbosityLevel": 3,
- # Query will display info for multiple SLOTed versions
- "considerDuplicates": 1,
- # Are we writing to a pipe?
- "piping": 0
-}
-
-def printVersion():
- """Print the version of this tool to the console."""
- print_info(0, __productname__ + "(" + __version__ + ") - " + \
- __description__)
- print_info(0, "Author(s): " + __author__)
-
-def buildReverseMap(m):
- r = {}
- for x in m.keys():
- r[m[x]] = x
- return r
-
-def printUsage():
- """Print full usage information for this tool to the console."""
-
- short_cmds = buildReverseMap(Short_commands);
-
- print_info(0, pp.emph("Usage: ") + pp.productname(__productname__) + pp.globaloption(" <global-opts> ") + pp.command("command") + pp.localoption(" <local-opts>"))
- print_info(0, "where " + pp.globaloption("<global-opts>") + " is one of")
- print_info(0, pp.globaloption(" -q, --quiet") + " - minimal output")
- print_info(0, pp.globaloption(" -C, --nocolor") + " - turn off colours")
- print_info(0, pp.globaloption(" -h, --help") + " - this help screen")
- print_info(0, pp.globaloption(" -V, --version") + " - display version info")
- print_info(0, pp.globaloption(" -N, --no-pipe") + " - turn off pipe detection")
-
- print_info(0, "where " + pp.command("command") + "(" + pp.command("short") + ") is one of")
- keys = Known_commands.keys()
- keys.sort()
- for x in keys:
- print_info(0, " " + pp.command(x) + "(" + pp.command(short_cmds[x]) + ") " + \
- Known_commands[x].shortHelp())
- print
-
-def configure():
- """Set up default configuration.
- """
-
- # Guess colour output
- if (Config["color"] == -1 and \
- ((not sys.stdout.isatty()) or (gentoolkit.settings["NOCOLOR"] in ["yes","true"]))):
- pp.output.nocolor()
-
- # Guess piping output
- if not sys.stdout.isatty():
- Config["piping"] = True
- else:
- Config["piping"] = False
-
-
-def parseArgs(args):
- """Parse tool-specific arguments.
-
- Arguments are on the form equery <tool-specific> [command] <command-specific>
-
- This function will only parse the <tool-specific> bit.
- """
- command = None
- local_opts = []
- showhelp = 0
-
- def expand(x):
- if x in Short_commands.keys():
- return Short_commands[x]
- return x
-
- for i in xrange(len(args)):
- x = args[i]
- if 0:
- pass
- elif x in ["-h", "--help"]:
- showhelp = True
- elif x in ["-V", "--version"]:
- printVersion()
- sys.exit(0)
- elif x in ["-C", "--nocolor"]:
- Config["color"] = 0
- pp.output.nocolor()
- elif x in ["-N", "--no-pipe"]:
- Config["piping"] = False
- elif x in ["-q","--quiet"]:
- Config["verbosityLevel"] = 0
- elif expand(x) in Known_commands.keys():
- command = Known_commands[expand(x)]
- local_opts.extend(args[i+1:])
- if showhelp:
- local_opts.append("--help")
- break
- else:
- print_warn("unknown global option %s, reusing as local option" % x)
- local_opts.append(x)
-
- if not command and showhelp:
- printUsage()
- sys.exit(0)
-
- return (command, local_opts)
-
-if __name__ == "__main__":
- configure()
- (cmd, local_opts) = parseArgs(sys.argv[1:])
- if cmd:
- try:
- cmd.perform(local_opts)
- except KeyError, e:
- if e and e[0].find("Specific key requires an operator") >= 0:
- print_error("Invalid syntax: missing operator")
- print_error("If you want only specific versions please use one of")
- print_error("the following operators as prefix for the package name:")
- print_error(" > >= = <= <")
- print_error("Example to only match gcc versions greater or equal 3.2:")
- print_error(" >=sys-devel/gcc-3.2")
- print_error("")
- print_error("Note: The symbols > and < are used for redirection in the shell")
- print_error("and must be quoted if either one is used.")
-
- else:
- print_error("Internal portage error, terminating")
- if len(e[0]):
- print_error(str(e))
- sys.exit(2)
- except ValueError, e:
- if isinstance(e[0], list):
- print_error("Ambiguous package name " + pp.emph("\"" + local_opts[0] + "\""))
- print_error("Please use one of the following long names:")
- for p in e[0]:
- print_error(" " + str(p))
- else:
- print_error("Internal portage error, terminating")
- if len(e[0]):
- print_error(str(e[0]))
- sys.exit(2)
- except KeyboardInterrupt:
- print_info(0, "Interrupted by user, aborting.")
- else:
- print_error("No command or unknown command given")
- printUsage()
-
+++ /dev/null
-.TH "equery" "1" "Oct 2005" "gentoolkit" ""
-.SH "NAME"
-equery \- Gentoo: Package Query Tool
-.SH "SYNOPSIS"
-.B equery
-.I [global\-opts] command [local\-opts]
-.PP
-
-.SH "DESCRIPTION"
-equery is a flexible utility which may display various information about
-packages, such as the files they own, their USE flags, the md5sum
-of each file owned by a given package, and many other things.
-
-.SH "OPTIONS"
-The 'command' is the only mandatory option to equery. Most commands require
-a 'pkgspec' option, which is described by <cat/>packagename<\-version>;
-namely, the package name is mandatory, while the category and version are
-optional.
-
-[global\-opts] may be one of:
-
-.B \-q, \-\-quiet
-causes minimal output to be emitted
-.PP
-.B \-C, \-\-nocolor
-turns off colours
-.PP
-.B \-h, \-\-help
-displays a help summary
-.PP
-.B \-V, \-\-version
-displays the equery version
-.PP
-.B \-N, \-\-no\-pipe
-turns off pipe detection
-.PP
-
-Only one command will actually be run, at most. The possible commands are:
-.TP
-.B belongs <local\-opts> file
-This command lists all packages owning the specified file.
-.br
-Note: Normally, only one package will own a file. If multiple packages own the
-same file, it usually consitutes a problem, and should be reported (http://bugs.gentoo.org).
-.br
-.IP
-<local\-opts> is either or both of:
-.br
-.B \-c, \-\-category cat
-only search in category cat
-.br
-.B \-f, \-\-full\-regex
-supplied query is a regex
-.br
-.B \-e, \-\-earlyout
-stop when first match found
-
-.PP
-.B check pkgspec
-This command checks the files of the specified package against recorded MD5
-sums and timestamps.
-.PP
-.TP
-.B depends <local\-opts> pkgspec
-This command displays all dependencies matching pkgspec.
-.br
-<local\-opts> is either or both of:
-.br
-.B \-a, \-\-all\-packages
-search in all available packages (slow)
-.br
-.B \-d, \-\-direct
-search direct dependencies only (default)
-.br
-.B \-D, \-\-indirect
-search indirect dependencies (very slow)
-.br
-.B \-\-depth=n
-Limit depth of indirect dependency tree to n levels. Setting \-\-depth=0 is the same as not specifing \-\-indirect.
-.PP
-.TP
-.B depgraph <local\-opts> pkgspec
-This command display a dependency tree for pkgspec, by default indented to reflect
-how dependancies relate to each other.
-.br
-.IP
-<local\-opts> is either or both of:
-.br
-.B \-U, \-\-no\-useflags
-do not show USE flags.
-.br
-.B \-l, \-\-linear
-do not use fancy formatting
-.br
-.B \-\-depth=n
-Limit depth of dependency graph to n levels.
-.PP
-.TP
-.B files <local\-opts> pkgspec
-This lists files owned by a particular package, optionally with extra
-information specified by <local\-opts>
-.br
-
-<local\-opts> is any combination of:
-.br
-.B \-\-timestamp
-output the timestamp of each file
-.br
-.B \-\-md5sum
-output the md5sum of each file
-.br
-.B \-\-type
-output the type of each file
-.br
-.B \-\-tree
-display results in a tree (turns off all other options)
-.br
-.B \-\-filter=<rules>
-filter output based on files type or path
-.br
-.B \t<rules>
-is a comma separated list of filtering rules. Available rules are:
-.br
-.B \t\tdir\
-regular directories
-.br
-.B \t\tobj\
-regular files
-.br
-.B \t\tsym\
-symbolic links
-.br
-.B \t\tdev\
-device nodes
-.br
-.B \t\tfifo
-named pipes
-.br
-.B \t\tpath
-shortest paths where some files where installed
-.br
-.B \t\tconf
-configuration files (based on $CONFIG_PROTECT)
-.br
-.B \t\tcmd\
-user commands (based on $PATH)
-.br
-.B \t\tdoc\
-documentation files (from /usr/share/doc)
-.br
-.B \t\tman\
-manpages (from /usr/share/man)
-.br
-.B \t\tinfo
-info pages (from /usr/share/info)
-.PP
-.TP
-.B hasuse <local\-opts> useflag
-This command lists packages matching a particular USE flag in a user\-specified combination
-of installed packages, packages which are not installed, the portage tree, and
-the portage overlay tree.
-
-<local\-opts> must not include only \-I;
-if \-I is used, \-p and/or \-o must be also be present. By default, only installed
-packages are searched. \-o searches only the overlay tree [and possibly
-installed packages],
-.I not
-the main portage tree.
-
-.B \-i, \-\-installed
-search installed packages (default)
-.br
-.B \-I, \-\-exclude\-installed
-do not search installed packages
-.br
-.B \-p, \-\-portage\-tree
-also search in portage tree (/usr/portage)
-.br
-.B \-o, \-\-overlay\-tree
-also search in overlay tree (/usr/local/portage)
-.PP
-.TP
-.B list <local\-opts> pkgspec
-This command lists packages matching pkgspec in a user\-specified combination
-of installed packages, packages which are not installed, the portage tree, and
-the portage overlay tree. By default the list command searches for partial name matches.
-
-<local\-opts> \-I cannot be used by itself;
-if \-I is used, \-p and/or \-o must be also be present. By default, only installed
-packages are searched. \-o searches only the overlay tree [and possibly
-installed packages],
-\fInot\fR the main portage tree.
-
-.B \-i, \-\-installed
-search installed packages (default)
-.br
-.B \-I, \-\-exclude\-installed
-do not search installed packages
-.br
-.B \-p, \-\-portage\-tree
-also search in portage tree (/usr/portage)
-.br
-.B \-o, \-\-overlay\-tree
-also search in overlay tree (/usr/local/portage)
-.br
-.B \-f, \-\-full\-regex
-query is a regular expression
-.br
-.B \-e, \-\-exact\-name
-list only those packages that exactly match
-.br
-.B \-d, \-\-duplicates
-only list installed duplicate packages
-.br
-
-\fBOutput:\fR
-
-.br
-The list command searches packages for the name given. If found, the following info will be displayed: the package location between the first square brackets (I for Installed packages, P for Portage, O for Overlay), the possible masks between the second (~ by keyword, - by arch or M hard masked), then the category and complete name and last of all, the slot in which the package is stored.
-
-\fBExamples:\fR
-
-equery list zilla \- list all installed versions of packages containing the string 'zilla'
-
-equery list \-\-exact\-name x11\-libs/gtk+ \- list all installed versions of x11\-libs/gtk+
-
-equery list \-\-full\-regex '(mozilla\-firefox|mozilla\-thunderbird)' \- list all installed versions of mozilla\-firefox and mozilla\-thunderbird
-
-equery list \-\-duplicates \- list all installed slotted packages
-.PP
-.TP
-.B size <local\-opts> pkgspec
-This command outputs the number of files in the specified package, as well as
-their total size in an appropriate unit.
-
-The possible values for <local\-opts>, if specified, are:
-.br
-.B \-b, \-\-bytes
-report size in bytes
-.br
-.B \-f, \-\-full\-regex
-query is a regular expression
-.br
-.B \-e, \-\-exact\-name
-list only those packages that exactly match
-.PP
-.TP
-.B uses <local\-opts> pkgspec
-display USE flags for pkgspec.
-
-The only possible value for <local\-opts>, if specified, is:
-.br
-.B \-a, \-\-all
-include all package versions
-.PP
-.B which pkgspec
-print full path to ebuild for package pkgspec
-.PP
-
-.SH "Unimplemented Options"
-.PP
-.B changes
-.PP
-.B glsa \fR \- use glsa\-check for the time being.
-.PP
-.B stats
-
-
-
-.SH "BUGS"
-Many options aren't implemented. Command\-line parsing could use some work.
-.br
-Submit bug reports to http://bugs.gentoo.org
-.SH "AUTHORS"
-equery, original man page: Karl Trygve Kalleberg <karltk@gentoo.org>, 2003.
-.br
-Massive man page updates: Katerina Barone\-Adesi <katerinab@gmail.com>, 2004.
-
+++ /dev/null
-#! /bin/bash
-#
-# Copyright (c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright (c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-
-function tempfilename() {
- fn=$(date "+%s")
- if [ ! -f ${fn}.tmp ] ; then
- echo ${fn}.tmp
- fi
-}
-
-function report_pass() {
- printf "%-40s - passed\n" ${1}
-}
-
-function report_failure() {
- printf "%-40s - FAILED!\n" ${1}
-}
-
-function assert_samefile() {
- diff $2 $3 && report_pass $1 || report_failure $1
-}
-
-function assert_eq() {
- if [ $2 -eq $3 ] ; then
- report_pass $1
- else
- printf "FAIL: $2 ! -eq $3\n"
- report_failure $1
- fi
-}
-
-function assert_ge() {
- if [ $2 -ge $3 ] ; then
- report_pass $1
- else
- printf "FAIL: $2 ! -ge $3\n"
- report_failure $1
- fi
-}
-
-function assert_exists() {
- if [ -f $2 ] ; then
- report_pass $1
- else
- printf "FAIL: $2 does not exist\n"
- report_failure $1
- fi
-}
\ No newline at end of file
+++ /dev/null
-#! /bin/bash
-#
-# Copyright (c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright (c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-
-. common-functions.sh
-
-for x in belongs check depends depgraph files help list size uses which ; do
- ./test-${x}.sh
-done
+++ /dev/null
-List all packages owning a particular set of files
-
-Note: Normally, only one package will own a file. If multiple packages own the same file, it usually consitutes a problem, and should be reported.
-
-Syntax:
- belongs <local-opts> filename
-<local-opts> is either of:
- -c, --category cat - only search in category cat
- -f, --full-regex - supplied query is a regex
- -e, --earlyout - stop when first match is found
-
+++ /dev/null
-#! /bin/bash
-#
-# Copyright (c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright (c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-
-. common-functions.sh
-
-tmpfile=$(tempfilename)
-
-test_belongs() {
- equery belongs $(which gcc) > ${tmpfile}
-
- x=$(grep "gcc-config" ${tmpfile} | wc -l)
-
- assert_eq ${FUNCNAME} ${x} 1
-}
-
-# Run tests
-
-test_belongs
-
-rm -f ${tmpfile}
\ No newline at end of file
+++ /dev/null
-Check package's files against recorded MD5 sums and timestamps
-Syntax:
- size pkgspec
+++ /dev/null
-#! /bin/bash
-#
-# Copyright (c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright (c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-
-. common-functions.sh
-
-tmpfile=$(tempfilename)
-
-test_check() {
- equery check gcc > ${tmpfile}
-
- x=$(grep "sys-devel/gcc" ${tmpfile} | wc -l)
-
- assert_ge ${FUNCNAME} ${x} 1
-
- x=$(egrep "[0-9]+ out of [0-9]+" ${tmpfile} | wc -l)
- assert_ge ${FUNCNAME} ${x} 1
-}
-
-test_check_permissions() {
- equery check sudo > ${tmpfile}
-
- x=$(grep "app-admin/sudo" ${tmpfile} | wc -l)
-
- assert_ge ${FUNCNAME} ${x} 1
-
- x=$(egrep "[0-9]+ out of [0-9]+" ${tmpfile} | wc -l)
- assert_ge ${FUNCNAME} ${x} 1
-}
-
-# Run tests
-
-test_check
-test_check_permissions
-
-rm -f ${tmpfile}
+++ /dev/null
-List all direct dependencies matching a query pattern
-Syntax:
- depends <local-opts> pkgspec
-<local-opts> is either of:
- -d, --direct - search direct dependencies only (default)
- -D, --indirect - search indirect dependencies (VERY slow)
- -i, --only-installed - search installed in installed packages only
-
+++ /dev/null
-#! /bin/bash
-#
-# Copyright (c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright (c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-
-. common-functions.sh
-
-tmpfile=$(tempfilename)
-
-test_depends() {
-# equery skel gcc > ${tmpfile}
-
-# x=$(grep "app-shells/bash" ${tmpfile} | wc -l)
- true
-# assert_eq ${FUNCNAME} ${x} 1
-
-# x=$(grep "virtual/libc" ${tmpfile} | wc -l)
-# assert_eq ${FUNCNAME} ${x} 1
-}
-
-# Run tests
-
-#test_skel
-
-rm -f ${tmpfile}
\ No newline at end of file
+++ /dev/null
-Display a dependency tree for a given package
-
-Syntax:
- depgraph <local-opts> pkgspec
-<local-opts> is either of:
- -U, --no-useflags - do not show USE flags
- -l, --linear - do not use fancy formatting
+++ /dev/null
-#! /bin/bash
-#
-# Copyright (c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright (c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-
-. common-functions.sh
-
-tmpfile=$(tempfilename)
-
-test_depgraph() {
- equery depgraph gcc > ${tmpfile}
-
- x=$(grep "app-shells/bash" ${tmpfile} | wc -l)
-
- assert_eq ${FUNCNAME} ${x} 1
-
- x=$(grep "virtual/libc" ${tmpfile} | wc -l)
- assert_eq ${FUNCNAME} ${x} 1
-}
-
-# Run tests
-
-test_depgraph
-
-rm -f ${tmpfile}
\ No newline at end of file
+++ /dev/null
-List files owned by a particular package
-
-Syntax:
- files <local-opts> <cat/>packagename<-version>
-
-Note: category and version parts are optional.
-
-<local-opts> is either of:
- --timestamp - append timestamp
- --md5sum - append md5sum
- --type - prepend file type
+++ /dev/null
-#! /bin/bash
-#
-# Copyright (c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright (c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-
-. common-functions.sh
-
-tmpfile=$(tempfilename)
-
-strip_versioned_files() {
- grep -v "/usr/share/doc"
-}
-
-test_files() {
- equery files bash > ${tmpfile}
-
- x=$(grep man ${tmpfile} | wc -l)
- assert_ge ${FUNCNAME} $x 5
-
- x=$(cat ${tmpfile} | wc -l)
- assert_ge ${FUNCNAME} $x 25
-}
-
-test_files_timestamp() {
- equery files --timestamp bash > ${tmpfile}
-
- x=$(grep "/bin/bash .*....-..-.. ..:..:.." ${tmpfile} | wc -l)
- assert_eq ${FUNCNAME} $x 1
-}
-
-test_files_md5sum() {
- equery files --md5sum bash > ${tmpfile}
-
- x=$(egrep "/bin/bash .*[0-9a-z]{30}" ${tmpfile} | wc -l)
- assert_eq ${FUNCNAME} $x 1
-}
-
-test_files_type() {
-
- equery files --type bash > ${tmpfile}
-
- x=$(grep "file.*/bin/bash$" ${tmpfile} | wc -l)
- assert_eq ${FUNCNAME} $x 1
-
- x=$(grep "symlink.*/bin/rbash" ${tmpfile} | wc -l)
- assert_eq ${FUNCNAME} $x 1
-
- x=$(grep "dir.*/usr/share/man" ${tmpfile} | wc -l)
- assert_ge ${FUNCNAME} $x 1
-}
-
-# Run tests
-
-test_files
-test_files_timestamp
-test_files_md5sum
-test_files_type
-
-rm ${tmpfile}
\ No newline at end of file
+++ /dev/null
-List all packages with a particular USE flag
-Syntax:
- list <local-opts> useflag
-<local-opts> is either of:
- -i, --installed - search installed packages (default)
- -I, --exclude-installed - do not search installed packages
- -p, --portage-tree - also search in portage tree (/usr/portage)
- -o, --overlay-tree - also search in overlay tree (/usr/local/portage /usr/local/overlays/gentoo-boblycat)
-
+++ /dev/null
-Usage: equery <global-opts> command <local-opts>
-where <global-opts> is one of
- -q, --quiet - minimal output
- -C, --nocolor - turn off colours
- -h, --help - this help screen
- -V, --version - display version info
-where command(short) is one of
- belongs(b) <local-opts> files... - list all packages owning files...
- changes(c) - not implemented yet
- check(k) pkgspec - check MD5sums and timestamps of pkgspec's files
- depends(d) <local-opts> pkgspec - list all direct dependencies matching pkgspec
- depgraph(g) <local-opts> pkgspec - display a dependency tree for pkgspec
- files(f) <local-opts> pkgspec - list files owned by pkgspec
- glsa(a) - not implemented yet
- hasuses(h) <local-opts> pkgspec - list all packages with useflag
- list(l) <local-opts> pkgspec - list all packages matching pkgspec
- size(s) <local-opts> pkgspec - print size of files contained in package pkgspec
- stats(t) - not implemented yet
- uses(u) <local-opts> pkgspec - display USE flags for pkgspec
- which(w) pkgspec - print full path to ebuild for package pkgspec
-
+++ /dev/null
-#! /bin/sh
-#
-# Copyright (c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright (c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-
-. common-functions.sh
-
-tmpfile=$(tempfilename)
-
-test_equery_help() {
- equery --help > ${tmpfile}
- assert_samefile ${FUNCNAME} ${tmpfile} test-help.out
-
-}
-
-test_belongs_help() {
- equery belongs --help > ${tmpfile}
- assert_samefile ${FUNCNAME} ${tmpfile} test-belongs-help.out
-}
-
-test_changes_help() {
- equery changes --help > ${tmpfile}
- assert_samefile ${FUNCNAME} ${tmpfile} test-changes-help.out
-}
-
-test_check_help() {
- equery check --help > ${tmpfile}
- assert_samefile ${FUNCNAME} ${tmpfile} test-check-help.out
-}
-
-test_depends_help() {
- equery depends --help > ${tmpfile}
- assert_samefile ${FUNCNAME} ${tmpfile} test-depends-help.out
-}
-
-test_depgraph_help() {
- equery depgraph --help > ${tmpfile}
- assert_samefile ${FUNCNAME} ${tmpfile} test-depgraph-help.out
-}
-
-test_files_help() {
- equery files --help > ${tmpfile}
- assert_samefile ${FUNCNAME} ${tmpfile} test-files-help.out
-}
-
-test_glsa_help() {
- equery glsa --help > ${tmpfile}
- assert_samefile ${FUNCNAME} ${tmpfile} test-glsa-help.out
-}
-
-test_hasuses_help() {
- equery hasuses --help > ${tmpfile}
- assert_samefile ${FUNCNAME} ${tmpfile} test-hasuses-help.out
-}
-
-test_list_help() {
- equery list --help > ${tmpfile}
- assert_samefile ${FUNCNAME} ${tmpfile} test-list-help.out
-}
-
-test_size_help() {
- equery size --help > ${tmpfile}
- assert_samefile ${FUNCNAME} ${tmpfile} test-size-help.out
-}
-
-test_stats_help() {
- equery stats --help > ${tmpfile}
- assert_samefile ${FUNCNAME} ${tmpfile} test-stats-help.out
-}
-
-test_uses_help() {
- equery uses --help > ${tmpfile}
- assert_samefile ${FUNCNAME} ${tmpfile} test-uses-help.out
-}
-
-test_which_help() {
- equery which --help > ${tmpfile}
- assert_samefile ${FUNCNAME} ${tmpfile} test-which-help.out
-}
-
-
-# run tests
-
-if [ "`hostname`" != "sky" ] ; then
- echo "Testing framework is beta and machine dependent; some tests will fail!"
-fi
-
-test_equery_help
-test_belongs_help
-test_check_help
-test_changes_help
-test_depends_help
-test_depgraph_help
-test_files_help
-test_glsa_help
-test_hasuses_help
-test_list_help
-test_size_help
-test_stats_help
-test_uses_help
-test_which_help
-
-rm -f *.tmp
\ No newline at end of file
+++ /dev/null
-List all packages matching a query pattern
-Syntax:
- list <local-opts> pkgspec
-<local-opts> is either of:
- -i, --installed - search installed packages (default)
- -I, --exclude-installed - do not search installed packages
- -p, --portage-tree - also search in portage tree (/usr/portage)
- -o, --overlay-tree - also search in overlay tree (/usr/local/portage /usr/local/overlays/gentoo-boblycat)
-
+++ /dev/null
-#! /bin/bash
-#
-# Copyright (c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright (c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-
-. common-functions.sh
-
-tmpfile=$(tempfilename)
-
-test_list() {
- equery list > ${tmpfile}
-
-# should test tty output as well
-# pkgs=$(cat ${tmpfile} | wc -l)
-# x=$(grep "[I--]" ${tmpfile} | wc -l)
-# assert_eq ${FUNCNAME} ${pkgs} ${x}
-
- x=$(grep "app-shells/bash" ${tmpfile} | wc -l)
- assert_ge ${FUNCNAME} $x 1
-}
-
-test_list_installed() {
- test_list
-}
-
-test_list_portage_tree() {
- equery list -I -p > ${tmpfile}
-}
-
-test_list_overlay_tree() {
- equery list -I -o > ${tmpfile}
-}
-
-# Run tests
-
-test_list
-
-rm -f ${tmpfile}
\ No newline at end of file
+++ /dev/null
-Print size total size of files contained in a given package
-Syntax:
- size <local-opts> pkgspec
-<local-opts> is either of:
- -b, --bytes - report size in bytes
-
+++ /dev/null
-#! /bin/bash
-#
-# Copyright (c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright (c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-
-. common-functions.sh
-
-tmpfile=$(tempfilename)
-
-test_size() {
- equery size gcc > ${tmpfile}
-
- x=$(grep "sys-devel/gcc" ${tmpfile} | wc -l)
-
- assert_ge ${FUNCNAME} ${x} 1
-
- x=$(egrep "size\([0-9]+\)" ${tmpfile} | wc -l)
- assert_ge ${FUNCNAME} ${x} 1
-}
-
-# Run tests
-
-test_size
-
-rm -f ${tmpfile}
\ No newline at end of file
+++ /dev/null
-Display USE flags for a given package
-
-Syntax:
- uses <local-opts> pkgspec
-<local-opts> is either of:
- -a, --all - include non-installed packages
-
+++ /dev/null
-#! /bin/bash
-#
-# Copyright (c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright (c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-
-. common-functions.sh
-
-tmpfile=$(tempfilename)
-
-test_uses() {
- equery uses gcc > ${tmpfile}
-
- x=$(grep "static" ${tmpfile} | wc -l)
-
- assert_eq ${FUNCNAME} ${x} 1
-
- x=$(cat ${tmpfile} | wc -l)
- assert_ge ${FUNCNAME} $x 7
-}
-
-test_uses_all() {
- equery uses -a uclibc > ${tmpfile}
-
- x=$(grep "static" ${tmpfile} | wc -l)
- assert_ge ${FUNCNAME} ${x} 1
-
- x=$(cat ${tmpfile} | wc -l)
- assert_ge ${FUNCNAME} $x 5
-
-}
-
-# Run tests
-
-test_uses
-test_uses_all
-
-rm -f ${tmpfile}
\ No newline at end of file
+++ /dev/null
-Print full path to ebuild for a given package
-Syntax:
- size pkgspec
+++ /dev/null
-#! /bin/bash
-#
-# Copyright (c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright (c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-
-. common-functions.sh
-
-tmpfile=$(tempfilename)
-
-test_which() {
- file=$(equery which gcc)
-
- assert_exists ${FUNCNAME} ${file}
-}
-
-# Run tests
-
-test_which
-
-rm -f ${tmpfile}
\ No newline at end of file
+++ /dev/null
-Author: Donnie Berkholz <dberkholz@gentoo.org>
-Updated by: Uwe Klosa <uwe.klosa@gmail.com>
+++ /dev/null
-# Copyright 2006 Gentoo Technologies, Inc.
-# Distributed under the terms of the GNU General Public License v2
-#
-# $Header$
-
-include ../../makedefs.mak
-
-all:
- echo "ELY (n.) The first, tiniest inkling you get that something, somewhere, has gone terribly wrong."
-
-dist:
- mkdir -p ../../$(distdir)/src/eread
- cp AUTHORS Makefile eread eread.1 ../../$(distdir)/src/eread/
-
-install:
-
- install -m 0755 eread $(bindir)/
- install -d $(docdir)/eread
- install -m 0644 AUTHORS $(docdir)/eread/
- install -m 0644 eread.1 $(mandir)/
+++ /dev/null
-#!/bin/bash
-
-# This is a script to read portage log items from einfo, ewarn etc, new in the
-# portage-2.1 series.
-#
-# Author: Donnie Berkholz <spyderous@gentoo.org>
-# Updated by: Uwe Klosa <uwe.klosa@gmail.com>
-
-# set decent PATH for bug 172969
-
-PATH=/usr/bin:/bin:${PATH}
-
-# Set ELOGDIR
-PORT_LOGDIR="$(portageq envvar PORT_LOGDIR)"
-[ "$PORT_LOGDIR" = "" ] && PORT_LOGDIR="/var/log/portage"
-ELOGDIR="$PORT_LOGDIR/elog"
-
-# Verify that ELOGDIR exists
-if [ ! -d "$ELOGDIR" ]; then
- echo "ELOG directory: $ELOGDIR does not exist!"
- exit 1
-fi
-
-# Use the pager from the users environment
-[ -z "$PAGER" ] && PAGER="less"
-
-# Set up select prompt
-PS3="Choice? "
-
-select_loop() {
- ANY_FILES=$(find . -type f)
- ANY_FILES=$(echo ${ANY_FILES} | sed -e "s:\./::g")
-
- if [[ -z ${ANY_FILES} ]]; then
- echo "No log items to read"
- break
- fi
-
- echo
- echo "This is a list of portage log items. Choose a number to view that file or type q to quit."
- echo
-
- # Pick which file to read
- select FILE in ${ANY_FILES}; do
- case ${REPLY} in
- q)
- echo "Quitting"
- QUIT="yes"
- break
- ;;
- *)
- if [ -f "$FILE" ]; then
- ${PAGER} ${FILE}
- read -p "Delete file? [y/N] " DELETE
- case ${DELETE} in
- q)
- echo "Quitting"
- QUIT="yes"
- break
- ;;
- y|Y)
- rm -f ${FILE}
- SUCCESS=$?
- if [[ ${SUCCESS} = 0 ]]; then
- echo "Deleted ${FILE}"
- else
- echo "Unable to delete ${FILE}"
- fi
- ;;
- # Empty string defaults to N (save file)
- n|N|"")
- echo "Saving ${FILE}"
- ;;
- *)
- echo "Invalid response. Saving ${FILE}"
- ;;
- esac
- else
- echo
- echo "Invalid response."
- fi
- ;;
- esac
- break
- done
-}
-
-pushd ${ELOGDIR} > /dev/null
-
-until [[ -n ${QUIT} ]]; do
- select_loop
-done
-
-popd > /dev/null
+++ /dev/null
-.TH "eread" "1" "1.0" "Donnie Berkholz" "gentoolkit"
-.SH "NAME"
-.LP
-eread \- Gentoo: Tool to display and manage ELOG files from portage
-.SH "SYNTAX"
-.LP
-eread
-.SH "DESCRIPTION"
-.LP
-This tool is used to display and manage ELOG files produced by portage version 2.1 and higher.
-.SH "ENVIRONMENT VARIABLES"
-The eread utility uses the PAGER environment variable to display the ELOG files. If the variable is not set, it defaults to /usr/bin/less.
+++ /dev/null
-* original perl version: Arun Bhanu <codebear@gentoo.org>
-* new bash version: Marius Mauch <genone@gentoo.org>
+++ /dev/null
-
-2004-01-07 Karl Trygve Kalleberg <karltk@gentoo.org>
- * Added Makefile
- * Updated from app-portage/gentoolkit
- * Reformatted ChangeLog
-
-2003-05-09 Arun Bhanu <codebear@gentoo.org>
- * Initial commit to gentoolkit.
-
+++ /dev/null
-# Copyright 2004 Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright 2004 Gentoo Technologies, Inc.
-# Distributed under the terms of the GNU General Public License v2
-#
-# $Header$
-
-include ../../makedefs.mak
-
-all:
- echo "PIMPERNE (n.) One of those rubber nodules found on the underneath side of a lavatory seat."
-
-dist:
- mkdir -p ../../$(distdir)/src/euse/
- cp Makefile AUTHORS ChangeLog euse euse.1 ../../$(distdir)/src/euse/
-
-install:
- install -m 0755 euse $(bindir)/
- install -d $(docdir)/euse
- install -m 0644 AUTHORS ChangeLog $(docdir)/euse/
- install -m 0644 euse.1 $(mandir)/
+++ /dev/null
-#!/bin/bash
-
-# $Header$
-
-# bash replacement for the original euse by Arun Bhanu
-# Author: Marius Mauch <genone@gentoo.org>
-# Version: 0.2
-# Licensed under the GPL v2
-
-PROGRAM_NAME=euse
-PROGRAM_VERSION=0.1
-
-MAKE_CONF_PATH=/etc/make.conf
-MAKE_GLOBALS_PATH=/etc/make.globals
-MAKE_PROFILE_PATH=/etc/make.profile
-MAKE_CONF_BACKUP_PATH=/etc/make.conf.euse_backup
-
-[ -z "${MODE}" ] && MODE="showhelp" # available operation modes: showhelp, showversion, showdesc, showflags, modify
-
-parse_arguments() {
- if [ -z "${1}" ]; then
- return
- fi
- while [ -n "${1}" ]; do
- case "${1}" in
- -h | --help) MODE="showhelp";;
- -v | --version) MODE="showversion";;
- -i | --info) MODE="showdesc";;
- -I | --info-installed) MODE="showinstdesc";;
- -l | --local) SCOPE="local";;
- -g | --global) SCOPE="global";;
- -a | --active) MODE="showflags";;
- -E | --enable) MODE="modify"; ACTION="add";;
- -D | --disable) MODE="modify"; ACTION="remove";;
- -P | --prune) MODE="modify"; ACTION="prune";;
- -*)
- echo "ERROR: unknown option ${1} specified."
- echo
- MODE="showhelp"
- ;;
- "%active")
- get_useflags
- ARGUMENTS="${ARGUMENTS} ${ACTIVE_FLAGS[9]}"
- ;;
- *)
- ARGUMENTS="${ARGUMENTS} ${1}"
- ;;
- esac
- shift
- done
-}
-
-error() {
- echo "ERROR: ${1}"
- set +f
- exit 1
-}
-
-get_real_path() {
- set -P
- cd "$1"
- pwd
- cd "$OLDPWD"
- set +P
-}
-
-check_sanity() {
- # file permission tests
- local descdir
- local make_defaults
-
- descdir="$(get_portdir)/profiles"
-
- [ ! -r "${MAKE_CONF_PATH}" ] && error "${MAKE_CONF_PATH} is not readable"
- [ ! -r "${MAKE_GLOBALS_PATH}" ] && error "${MAKE_GLOBALS_PATH} is not readable"
- [ ! -h "${MAKE_PROFILE_PATH}" ] && error "${MAKE_PROFILE_PATH} is not a symlink"
- [ -z "$(get_portdir)" ] && error "\$PORTDIR couldn't be determined"
- [ ! -d "${descdir}" ] && error "${descdir} does not exist or is not a directory"
- [ ! -r "${descdir}/use.desc" ] && error "${descdir}/use.desc is not readable"
- [ ! -r "${descdir}/use.local.desc" ] && error "${descdir}/use.local.desc is not readable"
- for make_defaults in $(get_all_make_defaults); do
- [ ! -r "$make_defaults" ] && error "$_make_defaults is not readable"
- done
-# [ ! -r "$(get_make_defaults)" ] && error "$(get_make_defaults) is not readable"
- [ "${MODE}" == "modify" -a ! -w "${MAKE_CONF_PATH}" ] && error ""${MAKE_CONF_PATH}" is not writable"
-}
-
-showhelp() {
-cat << HELP
-${PROGRAM_NAME} v${PROGRAM_VERSION}
-
-Syntax: ${PROGRAM_NAME} <option> [suboptions] [useflaglist]
-
-Options: -h, --help - show this message
- -v, --version - show version information
- -i, --info - show descriptions for the given useflags
- -I, --info-installed - show descriptions for the given useflags and
- their current impact on the installed system
- -g, --global - show only global use flags (suboption)
- -l, --local - show only local use flags (suboption)
- -a, --active - show currently active useflags and their origin
- -E, --enable - enable the given useflags
- -D, --disable - disable the given useflags
- -P, --prune - remove all references to the given flags from
- make.conf to revert to default settings
-
-Notes: ${PROGRAM_NAME} currently only works for global flags defined
- in make.globals, make.defaults or make.conf, it doesn't handle
- use.defaults, use.mask or package.use yet (see portage(5) for details on
- these files). It also might have issues with cascaded profiles.
- If multiple options are specified only the last one will be used.
-HELP
-}
-
-showversion() {
-cat << VER
-${PROGRAM_NAME} v${PROGRAM_VERSION}
-Written by Marius Mauch
-
-Copyright (C) 2004-2008 Gentoo Foundation, Inc.
-This is free software; see the source for copying conditions.
-VER
-}
-
-# remove duplicate flags from the given list in both positive and negative forms
-# (but unlike portage always keep the last value even if it's negative)
-# Otherwise the status flags could be incorrect if a flag appers multiple times in
-# one location (like make.conf).
-# Using python here as bash sucks for list handling.
-# NOTE: bash isn't actually that bad at handling lists -- sh is. This may be
-# worth another look to avoid calling python unnecessariy. Or we could
-# just write the whole thing in python. ;)
-reduce_incrementals() {
- echo $@ | python -c "import sys
-r=[]
-for x in sys.stdin.read().split():
- if x[0] == '-' and x[1:] in r:
- r.remove(x[1:])
- r.append(x)
- elif x[0] != '-' and '-'+x in r:
- r.remove('-'+x)
- r.append(x)
- elif x == '-*':
- r = []
- r.append(x)
- elif x not in r:
- r.append(x)
-print ' '.join(r)"
-}
-
-# the following function creates a bash array ACTIVE_FLAGS that contains the
-# global use flags, indexed by origin: 0: environment, 1: make.conf,
-# 2: make.defaults, 3: make.globals
-get_useflags() {
- # only calculate once as calling emerge is painfully slow
- [ -n "${USE_FLAGS_CALCULATED}" ] && return
-
- # backup portdir so get_portdir() doesn't give false results later
- portdir_backup="${PORTDIR}"
-
- ACTIVE_FLAGS[0]="$(reduce_incrementals ${USE})"
- USE=""
- source "${MAKE_CONF_PATH}"
- ACTIVE_FLAGS[1]="$(reduce_incrementals ${USE})"
- USE=""
- for x in $(get_all_make_defaults); do
- source "${x}"
- ACTIVE_FLAGS[2]="$(reduce_incrementals ${ACTIVE_FLAGS[2]} ${USE})"
- done
- USE=""
- source "${MAKE_GLOBALS_PATH}"
- ACTIVE_FLAGS[3]="$(reduce_incrementals ${USE})"
-
- # restore saved env variables
- USE="${ACTIVE_FLAGS[0]}"
- PORTDIR="${portdir_backup}"
-
- # get the currently active USE flags as seen by portage, this has to be after
- # restoring USE or portage won't see the original environment
- ACTIVE_FLAGS[9]="$(emerge --info | grep 'USE=' | cut -b 5- | sed -e 's:"::g')" #'
- USE_FLAGS_CALCULATED=1
-}
-
-# get the list of all known USE flags by reading use.desc and/or use.local.desc
-# (depending on the value of $SCOPE)
-get_useflaglist() {
- local descdir
-
- descdir="$(get_portdir)/profiles"
-
- if [ -z "${SCOPE}" -o "${SCOPE}" == "global" ]; then
- egrep "^[^# ]+ +-" "${descdir}/use.desc" | cut -d\ -f 1
- fi
- if [ -z "${SCOPE}" -o "${SCOPE}" == "local" ]; then
- egrep "^[^# :]+:[^ ]+ +-" "${descdir}/use.local.desc" | cut -d: -f 2 | cut -d\ -f 1
- fi
-}
-
-# get all make.defaults by traversing the cascaded profile directories
-get_all_make_defaults() {
- local curdir
- local parent
- local rvalue
-
- curdir="${1:-$(get_real_path ${MAKE_PROFILE_PATH})}"
-
- [ -f "${curdir}/make.defaults" ] && rvalue="${curdir}/make.defaults ${rvalue}"
- if [ -f "${curdir}/parent" ]; then
- for parent in $(egrep -v '(^#|^ *$)' ${curdir}/parent); do
- pdir="$(get_real_path ${curdir}/${parent})"
- rvalue="$(get_all_make_defaults ${pdir}) ${rvalue}"
- done
- fi
-
- echo "${rvalue}"
-}
-
-# get the path to make.defaults by traversing the cascaded profile directories
-get_make_defaults() {
- local curdir
- local parent
-
- curdir="${1:-$(get_real_path ${MAKE_PROFILE_PATH})}"
-
- if [ ! -f "${curdir}/make.defaults" -a -f "${curdir}/parent" ]; then
- for parent in $(egrep -v '(^#|^ *$)' ${curdir}/parent); do
- if [ -f "$(get_make_defaults ${curdir}/${parent})" ]; then
- curdir="${curdir}/${parent}"
- break
- fi
- done
- fi
-
- echo "${curdir}/make.defaults"
-}
-
-# little helper function to get the status of a given flag in one of the
-# ACTIVE_FLAGS elements. Arguments are 1: flag to test, 2: index of ACTIVE_FLAGS,
-# 3: echo value for positive (and as lowercase for negative) test result,
-# 4 (optional): echo value for "missing" test result, defaults to blank
-get_flagstatus_helper() {
- if echo " ${ACTIVE_FLAGS[${2}]} " | grep " ${1} " > /dev/null; then
- echo -n "${3}"
- elif echo " ${ACTIVE_FLAGS[${2}]} " | grep " -${1} " > /dev/null; then
- echo -n "$(echo ${3} | tr [[:upper:]] [[:lower:]])"
- else
- echo -n "${4:- }"
- fi
-}
-
-# prints a status string for the given flag, each column indicating the presence
-# for portage, in the environment, in make.conf, in make.defaults and in make.globals.
-# full positive value would be "[+ECDG]", full negative value would be [-ecdg],
-# full missing value would be "[- ]" (portage only sees present or not present)
-get_flagstatus() {
- get_useflags
-
- echo -n '['
- get_flagstatus_helper "${1}" 9 "+" "-"
- get_flagstatus_helper "${1}" 0 "E"
- get_flagstatus_helper "${1}" 1 "C"
- get_flagstatus_helper "${1}" 2 "D"
- get_flagstatus_helper "${1}" 3 "G"
- echo -n '] '
-}
-
-# faster replacement to `portageq portdir`
-get_portdir() {
- if [ -z "${PORTDIR}" ]; then
- use_backup="${USE}"
- source "${MAKE_GLOBALS_PATH}"
- for x in $(get_all_make_defaults); do
- source "${x}"
- done
- source "${MAKE_CONF_PATH}"
- USE="${use_backup}"
- fi
- echo "${PORTDIR}"
-}
-
-# This function takes a list of use flags and shows the status and
-# the description for each one, honoring $SCOPE
-showdesc() {
- local descdir
- local current_desc
- local found_one
- local args
-
- args="${*:-*}"
-
- if [ -z "${SCOPE}" ]; then
- SCOPE="global" showdesc ${args}
- echo
- SCOPE="local" showdesc ${args}
- return
- fi
-
- descdir="$(get_portdir)/profiles"
-
- [ "${SCOPE}" == "global" ] && echo "global use flags (searching: ${args})"
- [ "${SCOPE}" == "local" ] && echo "local use flags (searching: ${args})"
- echo "************************************************************"
-
- if [ "${args}" == "*" ]; then
- args="$(get_useflaglist | sort -u)"
- fi
-
- set ${args}
-
- foundone=0
- while [ -n "${1}" ]; do
- if [ "${SCOPE}" == "global" ]; then
- if grep "^${1} *-" "${descdir}/use.desc" > /dev/null; then
- get_flagstatus "${1}"
- foundone=1
- fi
- grep "^${1} *-" "${descdir}/use.desc"
- fi
- # local flags are a bit more complicated as there can be multiple
- # entries per flag and we can't pipe into printf
- if [ "${SCOPE}" == "local" ]; then
- if grep ":${1} *-" "${descdir}/use.local.desc" > /dev/null; then
- foundone=1
- fi
- grep ":${1} *-" "${descdir}/use.local.desc" \
- | sed -e "s/^\([^:]\+\):\(${1}\) *- *\(.\+\)/\1|\2|\3/g" \
- | while read line; do
- pkg="$(echo $line | cut -d\| -f 1)"
- flag="$(echo $line | cut -d\| -f 2)"
- desc="$(echo $line | cut -d\| -f 3)"
- get_flagstatus "${flag}"
- printf "%s (%s):\n%s\n\n" "${flag}" "${pkg}" "${desc}"
- done
- fi
- shift
- done
-
- if [ ${foundone} == 0 ]; then
- echo "no matching entries found"
- fi
-}
-
-# Works like showdesc() but displays only descriptions of which the appropriate
-# ebuild is installed and prints the name of those packages.
-showinstdesc() {
- local descdir
- local current_desc
- local args
- local -i foundone=0
- local OIFS="$IFS"
-
- args=("${@:-*}")
-
- case "${SCOPE}" in
- "global") echo "global use flags (searching: ${args})";;
- "local") echo "local use flags (searching: ${args})";;
- *) SCOPE="global" showinstdesc "${args[@]}"
- echo
- SCOPE="local" showinstdesc "${args[@]}"
- return;;
- esac
-
- descdir="$(get_portdir)/profiles"
- echo "************************************************************"
-
- if [ "${args}" = "*" ]; then
- args="$(get_useflaglist | sort -u)"
- fi
-
- set "${args[@]}"
-
- while [ -n "${1}" ]; do
- case "${SCOPE}" in
- "global")
- if desc=$(grep "^${1} *-" "${descdir}/use.desc"); then
- get_flagstatus "${1}"
- echo "$desc"
- # get list of installed packages matching this USE flag.
- IFS=$'\n'
- packages=($(equery -q -C hasuse -i "${1}" | awk '{ print $(NF-1) }' | sort))
- foundone+=${#packages[@]}
- printf "\nInstalled packages matching this USE flag: "
- if [ ${foundone} -gt 0 ]; then
- echo $'\n'"${packages[*]}"
- else
- echo "none"
- fi
- fi
- ;;
- "local")
- # local flags are a bit more complicated as there can be multiple
- # entries per flag and we can't pipe into printf
- IFS=': ' # Use a space instead of a dash because dashes occur in cat/pkg
- while read pkg flag desc; do
- # print name only if package is installed
- # NOTE: If we implement bug #114086 's enhancement we can just use the
- # exit status of equery instead of a subshell and pipe to wc -l
- if [ $(equery -q -C list -i -e "${pkg}" | wc -l) -gt 0 ]; then
- foundone=1
- IFS="$OIFS"
- get_flagstatus "${flag}"
- IFS=': '
- printf "%s (%s):\n%s\n\n" "${flag}" "${pkg}" "${desc#- }"
- fi
- done < <(grep ":${1} *-" "${descdir}/use.local.desc")
- ;;
- esac
- shift
- done
-
- if [ ${foundone} -lt 1 ]; then
- echo "no matching entries found"
- fi
- IFS="$OIFS"
-}
-
-# show a list of all currently active flags and where they are activated
-showflags() {
- local args
-
- get_useflags
-
- args="${*:-*}"
-
- if [ "${args}" == "*" ]; then
- args="$(get_useflaglist | sort -u)"
- fi
-
- set ${args}
-
- while [ -n "${1}" ]; do
- if echo " ${ACTIVE_FLAGS[9]} " | grep " ${1} " > /dev/null; then
- printf "%-20s" ${1}
- get_flagstatus ${1}
- echo
- fi
- shift
- done
-}
-
-# two small helpers to add or remove a flag from a USE string
-add_flag() {
- NEW_MAKE_CONF_USE="${NEW_MAKE_CONF_USE} ${1}"
-}
-
-remove_flag() {
- NEW_MAKE_CONF_USE="${NEW_MAKE_CONF_USE// ${1} / }"
-}
-
-# USE flag modification function. Mainly a loop with calls to add_flag and
-# remove_flag to create a new USE string which is then inserted into make.conf.
-modify() {
- if [ -z "${*}" ]; then
- if [ "${ACTION}" != "prune" ]; then
- echo "WARNING: no USE flags listed for modification, do you really"
- echo " want to ${ACTION} *all* known USE flags?"
- echo " If you don't please press Ctrl-C NOW!!!"
- sleep 5
- set $(get_useflaglist | sort -u)
- fi
- fi
-
- get_useflags
-
- NEW_MAKE_CONF_USE=" ${ACTIVE_FLAGS[1]} "
-
- while [ -n "${1}" ]; do
- if [ "${ACTION}" == "add" ]; then
- if echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
- shift
- elif echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
- remove_flag "-${1}"
- else
- add_flag "${1}"
- shift
- fi
- elif [ "${ACTION}" == "remove" ]; then
- if echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
- shift
- elif echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
- remove_flag "${1}"
- else
- add_flag "-${1}"
- shift
- fi
- elif [ "${ACTION}" == "prune" ]; then
- if echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
- remove_flag "${1}"
- elif echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
- remove_flag "-${1}"
- fi
- shift
- fi
- done
-
- #echo "old flags:"
- #echo ${ACTIVE_FLAGS[1]}
- #echo
- #echo "new flags:"
- #echo ${NEW_MAKE_CONF_USE}
-
- # a little loop to add linebreaks so we don't end with one ultra-long line
- NEW_MAKE_CONF_USE_2=""
- for x in ${NEW_MAKE_CONF_USE}; do
- if [ $(((${#NEW_MAKE_CONF_USE_2}%70)+${#x}+2)) -gt 70 ]; then
- NEW_MAKE_CONF_USE_2="${NEW_MAKE_CONF_USE_2}\\ \\n $x "
- else
- NEW_MAKE_CONF_USE_2="${NEW_MAKE_CONF_USE_2}${x} "
- fi
- done
-
- # make a backup just in case the user doesn't like the new make.conf
- cp -p "${MAKE_CONF_PATH}" "${MAKE_CONF_BACKUP_PATH}"
-
- # as sed doesn't really work with multi-line patterns we have to replace USE
- # on our own here. Basically just skip everything between USE=" and the
- # closing ", printing our new USE line there instead.
- inuse=0
- had_use=0
- x=0
- (while [ "$x" -eq "0" ]; do
- read -r line
- x="$?"
- [ "${line:0:4}" == "USE=" ] && inuse=1
- [ "${inuse}" == "0" ] && echo -E "${line}"
- if [ "${inuse}" == "1" ] && echo "${line}" | egrep '" *(#.*)?$' > /dev/null; then
- echo -n 'USE="'
- echo -ne "${NEW_MAKE_CONF_USE_2%% }"
- echo '"'
- inuse=0
- had_use=1
- fi
- done
- if [ ${had_use} -eq 0 ]; then
- echo -n 'USE="'
- echo -ne "${NEW_MAKE_CONF_USE_2%% }"
- echo '"'
- fi ) < "${MAKE_CONF_BACKUP_PATH}" | sed -e 's:\\ $:\\:' > "${MAKE_CONF_PATH}"
-
- echo "${MAKE_CONF_PATH} was modified, a backup copy has been placed at ${MAKE_CONF_BACKUP_PATH}"
-}
-
-##### main program comes now #####
-
-# disable globbing as it fucks up with args=*
-set -f
-parse_arguments "$@"
-check_sanity
-
-eval ${MODE} ${ARGUMENTS}
-set +f
+++ /dev/null
-.TH "EUSE" "1" "2004-10-17" "Gentoo Linux" "Gentoo Toolkit"
-.SH "NAME"
-euse \- Gentoo: command line USE flag editor
-.SH "SYNOPSIS"
-.B euse
-\fI<option> [suboption] [useflaglist]\fB
-.SH "DESCRIPTION"
-.PP
-.I euse
-is used to set(disable/enable) USE flags in /etc/make.conf without having to edit
-the file directly. It is also used to get detail information about use flags
-like description, status of flags(enabled/disabled), type of flag(global/local)
-etc.
-.SH "OPTIONS "
-.TP
-\fB\-E, \-\-enable\fI
-Enables USE flag(s) in make.conf. It accepts one or more space seperated
-USE flags as parameters.
-.TP
-\fB\-D, \-\-disable\fI
-Disables USE flag(s) in make.conf. Puts a '\-' sign in front of the USE flag
-and appends it to the USE setting in make.conf. It accepts one or more
-space seperated USE flags as parameters.
-.TP
-\fB\-P, \-\-prune\fI
-Removes USE flag(s) in make.conf. Removes all positive and negative references to
-the given USE flags from make.conf.
-.TP
-\fB\-i, \-\-info\fI
-Prints detail information about the USE flag(s). If no arguments are given then
-it assumes you want information for all USE flags. If one or more
-arguments are given (space separated) then only information for those flags is
-printed.
-.TP
-\fB\-I, \-\-info\-installed\fI
-Same as \-\-info, except that it will also list the currently installed packages that are utilizing the flag.
-.sp
-.RS
-The output is in the following format:
-.br
-\fB[\- cD ]\fI alpha \- indicates that architecture ...
-.br
-\fB[\- ]\fI moznocompose (net\-www/mozilla):
-.br
-Disable building of mozilla's web page composer
-.br
-The indicators in the first column are:
-.IP is_active
-+ if the flag is seen as active by portage, \- if not
-.IP is_in_env
-E if the flag is enabled in the environment, e if it is
-disabled in the environment, nothing if it's not affected
-by the environment
-.IP is_in_make_conf
-C if the flag is enabled in make.conf, c if it is
-disabled in make.conf, nothing if it's not affected
-by make.conf
-.IP is_in_make_defaults
-D if the flag is enabled in make.defaults, d if it is
-disabled in make.defaults, nothing if it's not affected
-by make.defaults
-.IP is_in_make_globals
-G if the flag is enabled in make.globals, g if it is
-disabled in make.globals, nothing if it's not affected
-by make.globals
-.br
-Then follows the name of the flag, for local flags the
-package name and then the description (on a new line for
-local flags).
-.TP
-\fB\-a, \-\-active\fI
-Shows all currently active USE flags and where they are activated (see
-description for \fB\-\-info\fI).
-.TP
-\fB\-h, \-\-help\fI
-Show the help message listing all the available flags and a short description
-.TP
-\fB\-v, \-\-version\fI
-Show the version information
-.SH "FILES"
-/etc/make.conf
-.br
-/etc/make.profile/make.defaults
-.br
-/etc/make.globals
-.br
-$PORTDIR/profiles/use.desc
-.br
-$PORTDIR/profiles/use.local.desc
-.br
-
-.SH "AUTHOR"
-Original version by Arun Bhanu <codebear@gentoo.org>
-.br
-Updated for rewritten euse by Marius Mauch <genone@gentoo.org>
-.SH "BUGS"
-euse doesn't handle USE flags enabled or disabled by use.defaults, use.mask
-or package.use yet. It also doesn't completely understand the \-* flag.
-.SH "SEE ALSO"
-.BR ufed(8),
-.TP
-The \fI/usr/bin/euse\fR script.
+++ /dev/null
-Original author:
-Karl Trygve Kalleberg <karltk@gentoo.org>
\ No newline at end of file
+++ /dev/null
-# Copyright 2004 Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright 2004 Gentoo Technologies, Inc.
-# Distributed under the terms of the GNU General Public License v2
-#
-# $Header$
-
-include ../../makedefs.mak
-
-all:
- echo "LISTOWEL (n.) The small mat on the bar designed to be more absorbent than the bar, but not as absorbent as your elbows."
-
-dist:
- mkdir -p ../../${distdir}/src/gentoolkit
- cp Makefile AUTHORS README TODO errors.py package.py helpers.py pprinter.py __init__.py ../../${distdir}/src/gentoolkit/
-
-install:
- install -d $(docdir)/gentoolkit
- install -m 0644 AUTHORS README TODO $(docdir)/gentoolkit/
- install -d $(DESTDIR)/usr/lib/gentoolkit/pym/gentoolkit
- install -m 0644 package.py pprinter.py helpers.py errors.py $(DESTDIR)/usr/lib/gentoolkit/pym/gentoolkit/
- install -m 0644 __init__.py $(DESTDIR)/usr/lib/gentoolkit/pym/gentoolkit/
-
+++ /dev/null
-
-Package : gentoolkit
-Version : see __init__.py
-Author : See AUTHORS
-
-MOTIVATION
-
-This is the Python API for Gentoolkit. It contains common functionality shared
-by the Gentoolkit tools written in Python.
-
-MECHANICS
-
-N/A
-
-IMPROVEMENTS
-
-N/A
+++ /dev/null
-#!/usr/bin/python
-#
-# Copyright 2003-2004 Karl Trygve Kalleberg
-# Copyright 2003-2004 Gentoo Technologies, Inc.
-# Distributed under the terms of the GNU General Public License v2
-#
-# $Header$
-# Author: Karl Trygve Kalleberg <karltk@gentoo.org>
-#
-# Portions written ripped from
-# - etcat, by Alistair Tse <liquidx@gentoo.org>
-#
-
-__author__ = "Karl Trygve Kalleberg"
-__email__ = "karltk@gentoo.org"
-__version__ = "0.1.1"
-__productname__ = "gentoolkit"
-__description__ = "Gentoolkit Common Library"
-
-import os
-import sys
-try:
- import portage
-except ImportError:
- sys.path.insert(0, "/usr/lib/portage/pym")
- import portage
-import re
-try:
- from threading import Lock
-except ImportError:
- # If we don't have thread support, we don't need to worry about
- # locking the global settings object. So we define a "null" Lock.
- class Lock:
- def acquire(self):
- pass
- def release(self):
- pass
-
-try:
- import portage.exception as portage_exception
-except ImportError:
- import portage_exception
-
-try:
- settingslock = Lock()
- settings = portage.config(clone=portage.settings)
- porttree = portage.db[portage.root]["porttree"]
- vartree = portage.db[portage.root]["vartree"]
- virtuals = portage.db[portage.root]["virtuals"]
-except portage_exception.PermissionDenied, e:
- sys.stderr.write("Permission denied: '%s'\n" % str(e))
- sys.exit(e.errno)
-
-Config = {
- "verbosityLevel": 3
-}
-
-from helpers import *
-from package import *
+++ /dev/null
-#! /usr/bin/python2
-#
-# Copyright(c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright(c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-#
-# $Header$
-
-class FatalError:
- def __init__(self, s):
- self._message = s
- def get_message(self):
- return self._message
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/python2
-#
-# Copyright(c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright(c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-#
-# $Header$
-
-import portage
-from gentoolkit import *
-from package import *
-from pprinter import print_warn
-try:
- from portage.util import unique_array
-except ImportError:
- from portage_util import unique_array
-
-def find_packages(search_key, masked=False):
- """Returns a list of Package objects that matched the search key."""
- try:
- if masked:
- t = portage.db["/"]["porttree"].dbapi.xmatch("match-all", search_key)
- t += portage.db["/"]["vartree"].dbapi.match(search_key)
- else:
- t = portage.db["/"]["porttree"].dbapi.match(search_key)
- t += portage.db["/"]["vartree"].dbapi.match(search_key)
- # catch the "amgigous package" Exception
- except ValueError, e:
- if isinstance(e[0],list):
- t = []
- for cp in e[0]:
- if masked:
- t += portage.db["/"]["porttree"].dbapi.xmatch("match-all", cp)
- t += portage.db["/"]["vartree"].dbapi.match(cp)
- else:
- t += portage.db["/"]["porttree"].dbapi.match(cp)
- t += portage.db["/"]["vartree"].dbapi.match(cp)
- else:
- raise ValueError(e)
- except portage_exception.InvalidAtom, e:
- print_warn("Invalid Atom: '%s'" % str(e))
- return []
- # Make the list of packages unique
- t = unique_array(t)
- t.sort()
- return [Package(x) for x in t]
-
-def find_installed_packages(search_key, masked=False):
- """Returns a list of Package objects that matched the search key."""
- try:
- t = portage.db["/"]["vartree"].dbapi.match(search_key)
- # catch the "amgigous package" Exception
- except ValueError, e:
- if isinstance(e[0],list):
- t = []
- for cp in e[0]:
- t += portage.db["/"]["vartree"].dbapi.match(cp)
- else:
- raise ValueError(e)
- except portage_exception.InvalidAtom, e:
- print_warn("Invalid Atom: '%s'" % str(e))
- return []
- return [Package(x) for x in t]
-
-def find_best_match(search_key):
- """Returns a Package object for the best available candidate that
- matched the search key."""
- t = portage.db["/"]["porttree"].dep_bestmatch(search_key)
- if t:
- return Package(t)
- return None
-
-def find_system_packages(prefilter=None):
- """Returns a tuple of lists, first list is resolved system packages,
- second is a list of unresolved packages."""
- pkglist = settings.packages
- resolved = []
- unresolved = []
- for x in pkglist:
- cpv = x.strip()
- if len(cpv) and cpv[0] == "*":
- pkg = find_best_match(cpv)
- if pkg:
- resolved.append(pkg)
- else:
- unresolved.append(cpv)
- return (resolved, unresolved)
-
-def find_world_packages(prefilter=None):
- """Returns a tuple of lists, first list is resolved world packages,
- seond is unresolved package names."""
- f = open(portage.root+portage.WORLD_FILE)
- pkglist = f.readlines()
- resolved = []
- unresolved = []
- for x in pkglist:
- cpv = x.strip()
- if len(cpv) and cpv[0] != "#":
- pkg = find_best_match(cpv)
- if pkg:
- resolved.append(pkg)
- else:
- unresolved.append(cpv)
- return (resolved,unresolved)
-
-def find_all_installed_packages(prefilter=None):
- """Returns a list of all installed packages, after applying the prefilter
- function"""
- t = vartree.dbapi.cpv_all()
- if prefilter:
- t = filter(prefilter,t)
- return [Package(x) for x in t]
-
-def find_all_uninstalled_packages(prefilter=None):
- """Returns a list of all uninstalled packages, after applying the prefilter
- function"""
- alist = find_all_packages(prefilter)
- return [x for x in alist if not x.is_installed()]
-
-def find_all_packages(prefilter=None):
- """Returns a list of all known packages, installed or not, after applying
- the prefilter function"""
- t = porttree.dbapi.cp_all()
- t += vartree.dbapi.cp_all()
- if prefilter:
- t = filter(prefilter,t)
- t = unique_array(t)
- t2 = []
- for x in t:
- t2 += porttree.dbapi.cp_list(x)
- t2 += vartree.dbapi.cp_list(x)
- t2 = unique_array(t2)
- return [Package(x) for x in t2]
-
-def split_package_name(name):
- """Returns a list on the form [category, name, version, revision]. Revision will
- be 'r0' if none can be inferred. Category and version will be empty, if none can
- be inferred."""
- r = portage.catpkgsplit(name)
- if not r:
- r = name.split("/")
- if len(r) == 1:
- return ["", name, "", "r0"]
- else:
- return r + ["", "r0"]
- else:
- r = list(r)
- if r[0] == 'null':
- r[0] = ''
- return r
-
-def sort_package_list(pkglist):
- """Returns the list ordered in the same way portage would do with lowest version
- at the head of the list."""
- pkglist.sort(Package.compare_version)
- return pkglist
-
-if __name__ == "__main__":
- print "This module is for import only"
-
-
+++ /dev/null
-#! /usr/bin/python2
-#
-# Copyright(c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright(c) 2004, Gentoo Foundation
-#
-# Licensed under the GNU General Public License, v2
-#
-# $Header$
-
-import os
-from errors import FatalError
-import portage
-from gentoolkit import *
-
-class Package:
- """Package descriptor. Contains convenience functions for querying the
- state of a package, its contents, name manipulation, ebuild info and
- similar."""
-
- def __init__(self,cpv):
- self._cpv = cpv
- self._scpv = portage.catpkgsplit(self._cpv)
-
- if not self._scpv:
- raise FatalError("invalid cpv: %s" % cpv)
- self._db = None
- self._settings = settings
- self._settingslock = settingslock
- self._portdir_path = os.path.realpath(settings["PORTDIR"])
-
- def get_name(self):
- """Returns base name of package, no category nor version"""
- return self._scpv[1]
-
- def get_version(self):
- """Returns version of package, with revision number"""
- v = self._scpv[2]
- if self._scpv[3] != "r0":
- v += "-" + self._scpv[3]
- return v
-
- def get_category(self):
- """Returns category of package"""
- return self._scpv[0]
-
- def get_settings(self, key):
- """Returns the value of the given key for this package (useful
- for package.* files."""
- self._settingslock.acquire()
- self._settings.setcpv(self._cpv)
- v = self._settings[key]
- self._settingslock.release()
- return v
-
- def get_cpv(self):
- """Returns full Category/Package-Version string"""
- return self._cpv
-
- def get_provide(self):
- """Return a list of provides, if any"""
- if not self.is_installed():
- try:
- x = [self.get_env_var('PROVIDE')]
- except KeyError:
- x = []
- return x
- else:
- return vartree.get_provide(self._cpv)
-
- def get_dependants(self):
- """Retrieves a list of CPVs for all packages depending on this one"""
- raise NotImplementedError("Not implemented yet!")
-
- def get_runtime_deps(self):
- """Returns a linearised list of first-level run time dependencies for this package, on
- the form [(comparator, [use flags], cpv), ...]"""
- # Try to use the portage tree first, since emerge only uses the tree when calculating dependencies
- try:
- cd = self.get_env_var("RDEPEND", porttree).split()
- except KeyError:
- cd = self.get_env_var("RDEPEND", vartree).split()
- r,i = self._parse_deps(cd)
- return r
-
- def get_compiletime_deps(self):
- """Returns a linearised list of first-level compile time dependencies for this package, on
- the form [(comparator, [use flags], cpv), ...]"""
- # Try to use the portage tree first, since emerge only uses the tree when calculating dependencies
- try:
- rd = self.get_env_var("DEPEND", porttree).split()
- except KeyError:
- rd = self.get_env_var("DEPEND", vartree).split()
- r,i = self._parse_deps(rd)
- return r
-
- def get_postmerge_deps(self):
- """Returns a linearised list of first-level post merge dependencies for this package, on
- the form [(comparator, [use flags], cpv), ...]"""
- # Try to use the portage tree first, since emerge only uses the tree when calculating dependencies
- try:
- pd = self.get_env_var("PDEPEND", porttree).split()
- except KeyError:
- pd = self.get_env_var("PDEPEND", vartree).split()
- r,i = self._parse_deps(pd)
- return r
-
- def _parse_deps(self,deps,curuse=[],level=0):
- # store (comparator, [use predicates], cpv)
- r = []
- comparators = ["~","<",">","=","<=",">="]
- end = len(deps)
- i = 0
- while i < end:
- tok = deps[i]
- if tok == ')':
- return r,i
- if tok[-1] == "?":
- tok = tok.replace("?","")
- sr,l = self._parse_deps(deps[i+2:],curuse=curuse+[tok],level=level+1)
- r += sr
- i += l + 3
- continue
- if tok == "||":
- sr,l = self._parse_deps(deps[i+2:],curuse,level=level+1)
- r += sr
- i += l + 3
- continue
- # conjonction, like in "|| ( ( foo bar ) baz )" => recurse
- if tok == "(":
- sr,l = self._parse_deps(deps[i+1:],curuse,level=level+1)
- r += sr
- i += l + 2
- continue
- # pkg block "!foo/bar" => ignore it
- if tok[0] == "!":
- i += 1
- continue
- # pick out comparator, if any
- cmp = ""
- for c in comparators:
- if tok.find(c) == 0:
- cmp = c
- tok = tok[len(cmp):]
- r.append((cmp,curuse,tok))
- i += 1
- return r,i
-
- def is_installed(self):
- """Returns true if this package is installed (merged)"""
- self._initdb()
- return os.path.exists(self._db.getpath())
-
- def is_overlay(self):
- """Returns true if the package is in an overlay."""
- dir,ovl = portage.portdb.findname2(self._cpv)
- return ovl != self._portdir_path
-
- def is_masked(self):
- """Returns true if this package is masked against installation. Note: We blindly assume that
- the package actually exists on disk somewhere."""
- unmasked = portage.portdb.xmatch("match-visible", "=" + self._cpv)
- return self._cpv not in unmasked
-
- def get_ebuild_path(self,in_vartree=0):
- """Returns the complete path to the .ebuild file"""
- if in_vartree:
- return vartree.getebuildpath(self._cpv)
- else:
- return portage.portdb.findname(self._cpv)
-
- def get_package_path(self):
- """Returns the path to where the ChangeLog, Manifest, .ebuild files reside"""
- p = self.get_ebuild_path()
- sp = p.split("/")
- if len(sp):
- return "/".join(sp[:-1])
-
- def get_env_var(self, var, tree=""):
- """Returns one of the predefined env vars DEPEND, RDEPEND, SRC_URI,...."""
- if tree == "":
- mytree = vartree
- if not self.is_installed():
- mytree = porttree
- else:
- mytree = tree
- r = mytree.dbapi.aux_get(self._cpv,[var])
- if not r:
- raise FatalError("Could not find the package tree")
- if len(r) != 1:
- raise FatalError("Should only get one element!")
- return r[0]
-
- def get_use_flags(self):
- """Returns the USE flags active at time of installation"""
- self._initdb()
- if self.is_installed():
- return self._db.getfile("USE")
- return ""
-
- def get_contents(self):
- """Returns the full contents, as a dictionary, on the form
- [ '/bin/foo' : [ 'obj', '1052505381', '45ca8b8975d5094cd75bdc61e9933691' ], ... ]"""
- self._initdb()
- if self.is_installed():
- return self._db.getcontents()
- return {}
-
- def compare_version(self,other):
- """Compares this package's version to another's CPV; returns -1, 0, 1"""
- v1 = self._scpv
- v2 = portage.catpkgsplit(other.get_cpv())
- # if category is different
- if v1[0] != v2[0]:
- return cmp(v1[0],v2[0])
- # if name is different
- elif v1[1] != v2[1]:
- return cmp(v1[1],v2[1])
- # Compare versions
- else:
- return portage.pkgcmp(v1[1:],v2[1:])
-
- def size(self):
- """Estimates the installed size of the contents of this package, if possible.
- Returns [size, number of files in total, number of uncounted files]"""
- contents = self.get_contents()
- size = 0
- uncounted = 0
- files = 0
- for x in contents:
- try:
- size += os.lstat(x).st_size
- files += 1
- except OSError:
- uncounted += 1
- return [size, files, uncounted]
-
- def _initdb(self):
- """Internal helper function; loads package information from disk,
- when necessary"""
- if not self._db:
- cat = self.get_category()
- pnv = self.get_name()+"-"+self.get_version()
- self._db = portage.dblink(cat,pnv,settings["ROOT"],settings)
+++ /dev/null
-#!/usr/bin/python
-#
-# Copyright 2004 Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright 2004 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-#
-# $Header$
-
-import sys
-import gentoolkit
-
-try:
- import portage.output as output
-except ImportError:
- import output
-
-
-def print_error(s):
- """Prints an error string to stderr."""
- sys.stderr.write(output.red("!!! ") + s + "\n")
-
-def print_info(lv, s, line_break = True):
- """Prints an informational string to stdout."""
- if gentoolkit.Config["verbosityLevel"] >= lv:
- sys.stdout.write(s)
- if line_break:
- sys.stdout.write("\n")
-
-def print_warn(s):
- """Print a warning string to stderr."""
- sys.stderr.write("!!! " + s + "\n")
-
-def die(err, s):
- """Print an error string and die with an error code."""
- print_error(s)
- sys.exit(err)
-
-# Colour settings
-
-def cpv(s):
- """Print a category/package-<version> string."""
- return output.green(s)
-
-def slot(s):
- """Print a slot string"""
- return output.bold(s)
-
-def useflag(s):
- """Print a USE flag strign"""
- return output.blue(s)
-
-def useflagon(s):
- """Print an enabled USE flag string"""
- # FIXME: Collapse into useflag with parameter
- return output.red(s)
-
-def useflagoff(s):
- """Print a disabled USE flag string"""
- # FIXME: Collapse into useflag with parameter
- return output.blue(s)
-
-def maskflag(s):
- """Print a masking flag string"""
- return output.red(s)
-
-def installedflag(s):
- """Print an installed flag string"""
- return output.bold(s)
-
-def number(s):
- """Print a number string"""
- return output.turquoise(s)
-
-def pkgquery(s):
- """Print a package query string."""
- return output.bold(s)
-
-def regexpquery(s):
- """Print a regular expression string"""
- return output.bold(s)
-
-def path(s):
- """Print a file or directory path string"""
- return output.bold(s)
-
-def path_symlink(s):
- """Print a symlink string."""
- return output.turquoise(s)
-
-def productname(s):
- """Print a product name string, i.e. the program name."""
- return output.turquoise(s)
-
-def globaloption(s):
- """Print a global option string, i.e. the program global options."""
- return output.yellow(s)
-
-def localoption(s):
- """Print a local option string, i.e. the program local options."""
- return output.green(s)
-
-def command(s):
- """Print a program command string."""
- return output.green(s)
-
-def section(s):
- """Print a string as a section header."""
- return output.turquoise(s)
-
-def subsection(s):
- """Print a string as a subsection header."""
- return output.turquoise(s)
-
-def emph(s):
- """Print a string as emphasized."""
- return output.bold(s)
+++ /dev/null
-# Copyright 2003 Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright 2003 Gentoo Technologies, Inc.
-# Distributed under the terms of the GNU General Public License v2
-#
-# $Header$
-
-include ../../makedefs.mak
-
-all:
- echo "YADDLETHORPE (vb.) (Of offended pooves.) To exit huffily from a boutique."
-
-dist:
- mkdir -p ../../$(distdir)/src/glsa-check/
- cp Makefile glsa.py glsa-check glsa-check.1 ../../$(distdir)/src/glsa-check/
-
-install:
- install -d $(DESTDIR)/usr/lib/gentoolkit/pym/
- install -m 0755 glsa-check $(bindir)/
- install -m 0644 glsa.py $(DESTDIR)/usr/lib/gentoolkit/pym/
- install -m 0644 glsa-check.1 $(mandir)/
+++ /dev/null
-#!/usr/bin/python
-
-# $Header: $
-# This program is licensed under the GPL, version 2
-
-import os
-import sys
-sys.path.insert(0, "/usr/lib/gentoolkit/pym")
-try:
- import portage
-except ImportError:
- sys.path.insert(0, "/usr/lib/portage/pym")
- import portage
-
-try:
- from portage.output import *
-except ImportError:
- from output import *
-
-from getopt import getopt, GetoptError
-
-__program__ = "glsa-check"
-__author__ = "Marius Mauch <genone@gentoo.org>"
-__version__ = "0.9"
-
-optionmap = [
-["-l", "--list", "list all unapplied GLSA"],
-["-d", "--dump", "--print", "show all information about the given GLSA"],
-["-t", "--test", "test if this system is affected by the given GLSA"],
-["-p", "--pretend", "show the necessary commands to apply this GLSA"],
-["-f", "--fix", "try to auto-apply this GLSA (experimental)"],
-["-i", "--inject", "inject the given GLSA into the checkfile"],
-["-n", "--nocolor", "disable colors (option)"],
-["-e", "--emergelike", "do not use a least-change algorithm (option)"],
-["-h", "--help", "show this help message"],
-["-V", "--version", "some information about this tool"],
-["-v", "--verbose", "print more information (option)"],
-["-c", "--cve", "show CAN ids in listing mode (option)"],
-["-m", "--mail", "send a mail with the given GLSAs to the administrator"]
-]
-
-# print a warning as this is beta code (but proven by now, so no more warning)
-#sys.stderr.write("WARNING: This tool is completely new and not very tested, so it should not be\n")
-#sys.stderr.write("used on production systems. It's mainly a test tool for the new GLSA release\n")
-#sys.stderr.write("and distribution system, it's functionality will later be merged into emerge\n")
-#sys.stderr.write("and equery.\n")
-#sys.stderr.write("Please read http://www.gentoo.org/proj/en/portage/glsa-integration.xml\n")
-#sys.stderr.write("before using this tool AND before reporting a bug.\n\n")
-
-# option parsing
-args = []
-params = []
-try:
- args, params = getopt(sys.argv[1:], "".join([o[0][1] for o in optionmap]), \
- [x[2:] for x in reduce(lambda x,y: x+y, [z[1:-1] for z in optionmap])])
-# ["dump", "print", "list", "pretend", "fix", "inject", "help", "verbose", "version", "test", "nocolor", "cve", "mail"])
- args = [a for a,b in args]
-
- for option in ["--nocolor", "-n"]:
- if option in args:
- nocolor()
- args.remove(option)
-
- verbose = False
- for option in ["--verbose", "-v"]:
- if option in args:
- verbose = True
- args.remove(option)
-
- list_cve = False
- for option in ["--cve", "-c"]:
- if option in args:
- list_cve = True
- args.remove(option)
-
- least_change = True
- for option in ["--emergelike", "-e"]:
- if option in args:
- least_change = False
- args.remove(option)
-
- # sanity checking
- if len(args) <= 0:
- sys.stderr.write("no option given: what should I do ?\n")
- mode = "HELP"
- elif len(args) > 1:
- sys.stderr.write("please use only one command per call\n")
- mode = "HELP"
- else:
- # in what mode are we ?
- args = args[0]
- for m in optionmap:
- if args in [o for o in m[:-1]]:
- mode = m[1][2:]
-
-except GetoptError, e:
- sys.stderr.write("unknown option given: ")
- sys.stderr.write(str(e)+"\n")
- mode = "HELP"
-
-# we need a set of glsa for most operation modes
-if len(params) <= 0 and mode in ["fix", "test", "pretend", "dump", "inject", "mail"]:
- sys.stderr.write("\nno GLSA given, so we'll do nothing for now. \n")
- sys.stderr.write("If you want to run on all GLSA please tell me so \n")
- sys.stderr.write("(specify \"all\" as parameter)\n\n")
- mode = "HELP"
-elif len(params) <= 0 and mode == "list":
- params.append("new")
-
-# show help message
-if mode == "help" or mode == "HELP":
- msg = "Syntax: glsa-check <option> [glsa-list]\n\n"
- for m in optionmap:
- msg += m[0] + "\t" + m[1] + " \t: " + m[-1] + "\n"
- for o in m[2:-1]:
- msg += "\t" + o + "\n"
- msg += "\nglsa-list can contain an arbitrary number of GLSA ids, \n"
- msg += "filenames containing GLSAs or the special identifiers \n"
- msg += "'all', 'new' and 'affected'\n"
- if mode == "help":
- sys.stdout.write(msg)
- sys.exit(0)
- else:
- sys.stderr.write("\n" + msg)
- sys.exit(1)
-
-# we need root priviledges for write access
-if mode in ["fix", "inject"] and os.geteuid() != 0:
- sys.stderr.write(__program__ + ": root access is needed for \""+mode+"\" mode\n")
- sys.exit(2)
-
-# show version and copyright information
-if mode == "version":
- sys.stderr.write("\n"+ __program__ + ", version " + __version__ + "\n")
- sys.stderr.write("Author: " + __author__ + "\n")
- sys.stderr.write("This program is licensed under the GPL, version 2\n\n")
- sys.exit(0)
-
-# delay this for speed increase
-from glsa import *
-
-glsaconfig = checkconfig(portage.config(clone=portage.settings))
-
-vardb = portage.db["/"]["vartree"].dbapi
-portdb = portage.db["/"]["porttree"].dbapi
-
-# Check that we really have a glsa dir to work on
-if not (os.path.exists(glsaconfig["GLSA_DIR"]) and os.path.isdir(glsaconfig["GLSA_DIR"])):
- sys.stderr.write(red("ERROR")+": GLSA_DIR %s doesn't exist. Please fix this.\n" % glsaconfig["GLSA_DIR"])
- sys.exit(1)
-
-# build glsa lists
-completelist = get_glsa_list(glsaconfig["GLSA_DIR"], glsaconfig)
-
-if os.access(glsaconfig["CHECKFILE"], os.R_OK):
- checklist = [line.strip() for line in open(glsaconfig["CHECKFILE"], "r").readlines()]
-else:
- checklist = []
-todolist = [e for e in completelist if e not in checklist]
-
-glsalist = []
-if "new" in params:
- glsalist = todolist
- params.remove("new")
-
-if "all" in params:
- glsalist = completelist
- params.remove("all")
-if "affected" in params:
- # replaced completelist with todolist on request of wschlich
- for x in todolist:
- try:
- myglsa = Glsa(x, glsaconfig)
- except (GlsaTypeException, GlsaFormatException), e:
- if verbose:
- sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (x, e)))
- continue
- if myglsa.isVulnerable():
- glsalist.append(x)
- params.remove("affected")
-
-# remove invalid parameters
-for p in params[:]:
- if not (p in completelist or os.path.exists(p)):
- sys.stderr.write(("(removing %s from parameter list as it isn't a valid GLSA specification)\n" % p))
- params.remove(p)
-
-glsalist.extend([g for g in params if g not in glsalist])
-
-def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr):
- fd2.write(white("[A]")+" means this GLSA was already applied,\n")
- fd2.write(green("[U]")+" means the system is not affected and\n")
- fd2.write(red("[N]")+" indicates that the system might be affected.\n\n")
-
- for myid in myglsalist:
- try:
- myglsa = Glsa(myid, glsaconfig)
- except (GlsaTypeException, GlsaFormatException), e:
- if verbose:
- fd2.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
- continue
- if myglsa.isApplied():
- status = "[A]"
- color = white
- elif myglsa.isVulnerable():
- status = "[N]"
- color = red
- else:
- status = "[U]"
- color = green
-
- if verbose:
- access = ("[%-8s] " % myglsa.access)
- else:
- access=""
-
- fd1.write(color(myglsa.nr) + " " + color(status) + " " + color(access) + myglsa.title + " (")
- if not verbose:
- for pkg in myglsa.packages.keys()[:3]:
- fd1.write(" " + pkg + " ")
- if len(myglsa.packages) > 3:
- fd1.write("... ")
- else:
- for pkg in myglsa.packages.keys():
- mylist = vardb.match(portage.dep_getkey(str(pkg)))
- if len(mylist) > 0:
- pkg = color(" ".join(mylist))
- fd1.write(" " + pkg + " ")
-
- fd1.write(")")
- if list_cve:
- fd1.write(" "+(",".join([r[:13] for r in myglsa.references if r[:4] in ["CAN-", "CVE-"]])))
- fd1.write("\n")
- return 0
-
-if mode == "list":
- sys.exit(summarylist(glsalist))
-
-# dump, fix, inject and fix are nearly the same code, only the glsa method call differs
-if mode in ["dump", "fix", "inject", "pretend"]:
- for myid in glsalist:
- try:
- myglsa = Glsa(myid, glsaconfig)
- except (GlsaTypeException, GlsaFormatException), e:
- if verbose:
- sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
- continue
- if mode == "dump":
- myglsa.dump()
- elif mode == "fix":
- sys.stdout.write("fixing "+myid+"\n")
- mergelist = myglsa.getMergeList(least_change=least_change)
- for pkg in mergelist:
- sys.stdout.write(">>> merging "+pkg+"\n")
- # using emerge for the actual merging as it contains the dependency
- # code and we want to be consistent in behaviour. Also this functionality
- # will be integrated in emerge later, so it shouldn't hurt much.
- emergecmd = "emerge --oneshot " + glsaconfig["EMERGE_OPTS"] + " =" + pkg
- if verbose:
- sys.stderr.write(emergecmd+"\n")
- exitcode = os.system(emergecmd)
- # system() returns the exitcode in the high byte of a 16bit integer
- if exitcode >= 1<<8:
- exitcode >>= 8
- if exitcode:
- sys.exit(exitcode)
- if len(mergelist):
- sys.stdout.write("\n")
- myglsa.inject()
- elif mode == "pretend":
- sys.stdout.write("Checking GLSA "+myid+"\n")
- mergelist = myglsa.getMergeList(least_change=least_change)
- if mergelist:
- sys.stdout.write("The following updates will be performed for this GLSA:\n")
- for pkg in mergelist:
- oldver = None
- for x in vardb.match(portage.dep_getkey(pkg)):
- if vardb.aux_get(x, ["SLOT"]) == portdb.aux_get(pkg, ["SLOT"]):
- oldver = x
- if oldver == None:
- raise ValueError("could not find old version for package %s" % pkg)
- oldver = oldver[len(portage.dep_getkey(oldver))+1:]
- sys.stdout.write(" " + pkg + " (" + oldver + ")\n")
- else:
- sys.stdout.write("Nothing to do for this GLSA\n")
- sys.stdout.write("\n")
- elif mode == "inject":
- sys.stdout.write("injecting " + myid + "\n")
- myglsa.inject()
- sys.exit(0)
-
-# test is a bit different as Glsa.test() produces no output
-if mode == "test":
- outputlist = []
- for myid in glsalist:
- try:
- myglsa = Glsa(myid, glsaconfig)
- except (GlsaTypeException, GlsaFormatException), e:
- if verbose:
- sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
- continue
- if myglsa.isVulnerable():
- if verbose:
- outputlist.append(str(myglsa.nr)+" ( "+myglsa.title+" ) ")
- else:
- outputlist.append(str(myglsa.nr))
- if len(outputlist) > 0:
- sys.stderr.write("This system is affected by the following GLSAs:\n")
- sys.stdout.write("\n".join(outputlist)+"\n")
- else:
- sys.stderr.write("This system is not affected by any of the listed GLSAs\n")
- sys.exit(0)
-
-# mail mode as requested by solar
-if mode == "mail":
- try:
- import portage.mail as portage_mail
- except ImportError:
- import portage_mail
-
- import socket
- from StringIO import StringIO
- try:
- from email.mime.text import MIMEText
- except ImportError:
- from email.MIMEText import MIMEText
-
- # color doesn't make any sense for mail
- nocolor()
-
- if "PORTAGE_ELOG_MAILURI" in glsaconfig:
- myrecipient = glsaconfig["PORTAGE_ELOG_MAILURI"].split()[0]
- else:
- myrecipient = "root@localhost"
-
- if "PORTAGE_ELOG_MAILFROM" in glsaconfig:
- myfrom = glsaconfig["PORTAGE_ELOG_MAILFROM"]
- else:
- myfrom = "glsa-check"
-
- mysubject = "[glsa-check] Summary for %s" % socket.getfqdn()
-
- # need a file object for summarylist()
- myfd = StringIO()
- myfd.write("GLSA Summary report for host %s\n" % socket.getfqdn())
- myfd.write("(Command was: %s)\n\n" % " ".join(sys.argv))
- summarylist(glsalist, fd1=myfd, fd2=myfd)
- summary = str(myfd.getvalue())
- myfd.close()
-
- myattachments = []
- for myid in glsalist:
- try:
- myglsa = Glsa(myid, glsaconfig)
- except (GlsaTypeException, GlsaFormatException), e:
- if verbose:
- sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
- continue
- myfd = StringIO()
- myglsa.dump(outstream=myfd)
- myattachments.append(MIMEText(str(myfd.getvalue()), _charset="utf8"))
- myfd.close()
-
- mymessage = portage_mail.create_message(myfrom, myrecipient, mysubject, summary, myattachments)
- portage_mail.send_mail(glsaconfig, mymessage)
-
- sys.exit(0)
-
-# something wrong here, all valid paths are covered with sys.exit()
-sys.stderr.write("nothing more to do\n")
-sys.exit(2)
+++ /dev/null
-.TH "glsa-check" "1" "0.6" "Marius Mauch" "gentoolkit"
-.SH "NAME"
-.LP
-glsa\-check \- Gentoo: Tool to locally monitor and manage GLSA's
-.SH "SYNTAX"
-.LP
-glsa\-check <\fIoption\fP> [\fIglsa\-list\fP]
-
-[\fIglsa\-list\fR] can contain an arbitrary number of GLSA ids, filenames containing GLSAs or the special identifiers 'all', 'new' and 'affected'
-.SH "DESCRIPTION"
-.LP
-This tool is used to locally monitor and manage Gentoo Linux Security Advisories.
-Please read:
-.br
-http://www.gentoo.org/security
-.br
-before reporting a bug.
-.LP
-Note: In order for this tool to be effective, you must regularly sync your local portage tree.
-.SH "OPTIONS"
-.LP
-.TP
-.B \-l, \-\-list
-list all unapplied GLSA
-.TP
-.B \-d, \-\-dump, \-\-print
-show all information about the given GLSA
-.TP
-.B \-t, \-\-test
-test if this system is affected by the given GLSA
-.TP
-.B \-p, \-\-pretend
-show the necessary commands to apply this GLSA
-.TP
-.B \-f, \-\-fix
-try to auto\-apply this GLSA (experimental)
-.TP
-.B \-i, \-\-inject
-inject the given GLSA into the checkfile
-.TP
-.B \-n, \-\-nocolor
-disable colors (option)
-.TP
-.B \-h, \-\-help
-show this help message
-.TP
-.B \-V, \-\-version
-some information about this tool
-.TP
-.B \-v, \-\-verbose
-print more messages (option)
-.TP
-.B \-c, \-\-cve
-show CAN ids in listing mode (option)
-.TP
-.B \-m, \-\-mail
-send a mail with the given GLSAs to the administrator
+++ /dev/null
-# $Header$
-
-# This program is licensed under the GPL, version 2
-
-# WARNING: this code is only tested by a few people and should NOT be used
-# on production systems at this stage. There are possible security holes and probably
-# bugs in this code. If you test it please report ANY success or failure to
-# me (genone@gentoo.org).
-
-# The following planned features are currently on hold:
-# - getting GLSAs from http/ftp servers (not really useful without the fixed ebuilds)
-# - GPG signing/verification (until key policy is clear)
-
-__author__ = "Marius Mauch <genone@gentoo.org>"
-
-import os
-import sys
-import urllib
-import time
-import codecs
-import re
-import xml.dom.minidom
-
-if sys.version_info[0:2] < (2, 3):
- raise NotImplementedError("Python versions below 2.3 have broken XML code " \
- +"and are not supported")
-
-try:
- import portage
-except ImportError:
- sys.path.insert(0, "/usr/lib/portage/pym")
- import portage
-
-# Note: the space for rgt and rlt is important !!
-opMapping = {"le": "<=", "lt": "<", "eq": "=", "gt": ">", "ge": ">=",
- "rge": ">=~", "rle": "<=~", "rgt": " >~", "rlt": " <~"}
-NEWLINE_ESCAPE = "!;\\n" # some random string to mark newlines that should be preserved
-SPACE_ESCAPE = "!;_" # some random string to mark spaces that should be preserved
-
-def center(text, width):
- """
- Returns a string containing I{text} that is padded with spaces on both
- sides. If C{len(text) >= width} I{text} is returned unchanged.
-
- @type text: String
- @param text: the text to be embedded
- @type width: Integer
- @param width: the minimum length of the returned string
- @rtype: String
- @return: the expanded string or I{text}
- """
- if len(text) >= width:
- return text
- margin = (width-len(text))/2
- rValue = " "*margin
- rValue += text
- if 2*margin + len(text) == width:
- rValue += " "*margin
- elif 2*margin + len(text) + 1 == width:
- rValue += " "*(margin+1)
- return rValue
-
-
-def wrap(text, width, caption=""):
- """
- Wraps the given text at column I{width}, optionally indenting
- it so that no text is under I{caption}. It's possible to encode
- hard linebreaks in I{text} with L{NEWLINE_ESCAPE}.
-
- @type text: String
- @param text: the text to be wrapped
- @type width: Integer
- @param width: the column at which the text should be wrapped
- @type caption: String
- @param caption: this string is inserted at the beginning of the
- return value and the paragraph is indented up to
- C{len(caption)}.
- @rtype: String
- @return: the wrapped and indented paragraph
- """
- rValue = ""
- line = caption
- text = text.replace(2*NEWLINE_ESCAPE, NEWLINE_ESCAPE+" "+NEWLINE_ESCAPE)
- words = text.split()
- indentLevel = len(caption)+1
-
- for w in words:
- if line[-1] == "\n":
- rValue += line
- line = " "*indentLevel
- if len(line)+len(w.replace(NEWLINE_ESCAPE, ""))+1 > width:
- rValue += line+"\n"
- line = " "*indentLevel+w.replace(NEWLINE_ESCAPE, "\n")
- elif w.find(NEWLINE_ESCAPE) >= 0:
- if len(line.strip()) > 0:
- rValue += line+" "+w.replace(NEWLINE_ESCAPE, "\n")
- else:
- rValue += line+w.replace(NEWLINE_ESCAPE, "\n")
- line = " "*indentLevel
- else:
- if len(line.strip()) > 0:
- line += " "+w
- else:
- line += w
- if len(line) > 0:
- rValue += line.replace(NEWLINE_ESCAPE, "\n")
- rValue = rValue.replace(SPACE_ESCAPE, " ")
- return rValue
-
-def checkconfig(myconfig):
- """
- takes a portage.config instance and adds GLSA specific keys if
- they are not present. TO-BE-REMOVED (should end up in make.*)
- """
- mysettings = {
- "GLSA_DIR": portage.settings["PORTDIR"]+"/metadata/glsa/",
- "GLSA_PREFIX": "glsa-",
- "GLSA_SUFFIX": ".xml",
- "CHECKFILE": "/var/cache/edb/glsa",
- "GLSA_SERVER": "www.gentoo.org/security/en/glsa/", # not completely implemented yet
- "CHECKMODE": "local", # not completely implemented yet
- "PRINTWIDTH": "76"
- }
- for k in mysettings.keys():
- if k not in myconfig:
- myconfig[k] = mysettings[k]
- return myconfig
-
-def get_glsa_list(repository, myconfig):
- """
- Returns a list of all available GLSAs in the given repository
- by comparing the filelist there with the pattern described in
- the config.
-
- @type repository: String
- @param repository: The directory or an URL that contains GLSA files
- (Note: not implemented yet)
- @type myconfig: portage.config
- @param myconfig: a GLSA aware config instance (see L{checkconfig})
-
- @rtype: List of Strings
- @return: a list of GLSA IDs in this repository
- """
- # TODO: remote fetch code for listing
-
- rValue = []
-
- if not os.access(repository, os.R_OK):
- return []
- dirlist = os.listdir(repository)
- prefix = myconfig["GLSA_PREFIX"]
- suffix = myconfig["GLSA_SUFFIX"]
-
- for f in dirlist:
- try:
- if f[:len(prefix)] == prefix:
- rValue.append(f[len(prefix):-1*len(suffix)])
- except IndexError:
- pass
- return rValue
-
-def getListElements(listnode):
- """
- Get all <li> elements for a given <ol> or <ul> node.
-
- @type listnode: xml.dom.Node
- @param listnode: <ul> or <ol> list to get the elements for
- @rtype: List of Strings
- @return: a list that contains the value of the <li> elements
- """
- rValue = []
- if not listnode.nodeName in ["ul", "ol"]:
- raise GlsaFormatException("Invalid function call: listnode is not <ul> or <ol>")
- for li in listnode.childNodes:
- if li.nodeType != xml.dom.Node.ELEMENT_NODE:
- continue
- rValue.append(getText(li, format="strip"))
- return rValue
-
-def getText(node, format):
- """
- This is the main parser function. It takes a node and traverses
- recursive over the subnodes, getting the text of each (and the
- I{link} attribute for <uri> and <mail>). Depending on the I{format}
- parameter the text might be formatted by adding/removing newlines,
- tabs and spaces. This function is only useful for the GLSA DTD,
- it's not applicable for other DTDs.
-
- @type node: xml.dom.Node
- @param node: the root node to start with the parsing
- @type format: String
- @param format: this should be either I{strip}, I{keep} or I{xml}
- I{keep} just gets the text and does no formatting.
- I{strip} replaces newlines and tabs with spaces and
- replaces multiple spaces with one space.
- I{xml} does some more formatting, depending on the
- type of the encountered nodes.
- @rtype: String
- @return: the (formatted) content of the node and its subnodes
- """
- rValue = ""
- if format in ["strip", "keep"]:
- if node.nodeName in ["uri", "mail"]:
- rValue += node.childNodes[0].data+": "+node.getAttribute("link")
- else:
- for subnode in node.childNodes:
- if subnode.nodeName == "#text":
- rValue += subnode.data
- else:
- rValue += getText(subnode, format)
- else:
- for subnode in node.childNodes:
- if subnode.nodeName == "p":
- for p_subnode in subnode.childNodes:
- if p_subnode.nodeName == "#text":
- rValue += p_subnode.data.strip()
- elif p_subnode.nodeName in ["uri", "mail"]:
- rValue += p_subnode.childNodes[0].data
- rValue += " ( "+p_subnode.getAttribute("link")+" )"
- rValue += NEWLINE_ESCAPE
- elif subnode.nodeName == "ul":
- for li in getListElements(subnode):
- rValue += "-"+SPACE_ESCAPE+li+NEWLINE_ESCAPE+" "
- elif subnode.nodeName == "ol":
- i = 0
- for li in getListElements(subnode):
- i = i+1
- rValue += str(i)+"."+SPACE_ESCAPE+li+NEWLINE_ESCAPE+" "
- elif subnode.nodeName == "code":
- rValue += getText(subnode, format="keep").replace("\n", NEWLINE_ESCAPE)
- if rValue[-1*len(NEWLINE_ESCAPE):] != NEWLINE_ESCAPE:
- rValue += NEWLINE_ESCAPE
- elif subnode.nodeName == "#text":
- rValue += subnode.data
- else:
- raise GlsaFormatException("Invalid Tag found: ", subnode.nodeName)
- if format == "strip":
- rValue = rValue.strip(" \n\t")
- rValue = re.sub("[\s]{2,}", " ", rValue)
- # Hope that the utf conversion doesn't break anything else
- return rValue.encode("utf_8")
-
-def getMultiTagsText(rootnode, tagname, format):
- """
- Returns a list with the text of all subnodes of type I{tagname}
- under I{rootnode} (which itself is not parsed) using the given I{format}.
-
- @type rootnode: xml.dom.Node
- @param rootnode: the node to search for I{tagname}
- @type tagname: String
- @param tagname: the name of the tags to search for
- @type format: String
- @param format: see L{getText}
- @rtype: List of Strings
- @return: a list containing the text of all I{tagname} childnodes
- """
- rValue = []
- for e in rootnode.getElementsByTagName(tagname):
- rValue.append(getText(e, format))
- return rValue
-
-def makeAtom(pkgname, versionNode):
- """
- creates from the given package name and information in the
- I{versionNode} a (syntactical) valid portage atom.
-
- @type pkgname: String
- @param pkgname: the name of the package for this atom
- @type versionNode: xml.dom.Node
- @param versionNode: a <vulnerable> or <unaffected> Node that
- contains the version information for this atom
- @rtype: String
- @return: the portage atom
- """
- rValue = opMapping[versionNode.getAttribute("range")] \
- + pkgname \
- + "-" + getText(versionNode, format="strip")
- return str(rValue)
-
-def makeVersion(versionNode):
- """
- creates from the information in the I{versionNode} a
- version string (format <op><version>).
-
- @type versionNode: xml.dom.Node
- @param versionNode: a <vulnerable> or <unaffected> Node that
- contains the version information for this atom
- @rtype: String
- @return: the version string
- """
- return opMapping[versionNode.getAttribute("range")] \
- +getText(versionNode, format="strip")
-
-def match(atom, portdbname, match_type="default"):
- """
- wrapper that calls revisionMatch() or portage.dbapi.match() depending on
- the given atom.
-
- @type atom: string
- @param atom: a <~ or >~ atom or a normal portage atom that contains the atom to match against
- @type portdb: portage.dbapi
- @param portdb: one of the portage databases to use as information source
- @type match_type: string
- @param match_type: if != "default" passed as first argument to dbapi.xmatch
- to apply the wanted visibility filters
-
- @rtype: list of strings
- @return: a list with the matching versions
- """
- db = portage.db["/"][portdbname].dbapi
- if atom[2] == "~":
- return revisionMatch(atom, db, match_type=match_type)
- elif match_type == "default" or not hasattr(db, "xmatch"):
- return db.match(atom)
- else:
- return db.xmatch(match_type, atom)
-
-def revisionMatch(revisionAtom, portdb, match_type="default"):
- """
- handler for the special >~, >=~, <=~ and <~ atoms that are supposed to behave
- as > and < except that they are limited to the same version, the range only
- applies to the revision part.
-
- @type revisionAtom: string
- @param revisionAtom: a <~ or >~ atom that contains the atom to match against
- @type portdb: portage.dbapi
- @param portdb: one of the portage databases to use as information source
- @type match_type: string
- @param match_type: if != "default" passed as first argument to portdb.xmatch
- to apply the wanted visibility filters
-
- @rtype: list of strings
- @return: a list with the matching versions
- """
- if match_type == "default" or not hasattr(portdb, "xmatch"):
- mylist = portdb.match(re.sub("-r[0-9]+$", "", revisionAtom[2:]))
- else:
- mylist = portdb.xmatch(match_type, re.sub("-r[0-9]+$", "", revisionAtom[2:]))
- rValue = []
- for v in mylist:
- r1 = portage.pkgsplit(v)[-1][1:]
- r2 = portage.pkgsplit(revisionAtom[3:])[-1][1:]
- if eval(r1+" "+revisionAtom[0:2]+" "+r2):
- rValue.append(v)
- return rValue
-
-
-def getMinUpgrade(vulnerableList, unaffectedList, minimize=True):
- """
- Checks if the systemstate is matching an atom in
- I{vulnerableList} and returns string describing
- the lowest version for the package that matches an atom in
- I{unaffectedList} and is greater than the currently installed
- version or None if the system is not affected. Both
- I{vulnerableList} and I{unaffectedList} should have the
- same base package.
-
- @type vulnerableList: List of Strings
- @param vulnerableList: atoms matching vulnerable package versions
- @type unaffectedList: List of Strings
- @param unaffectedList: atoms matching unaffected package versions
- @type minimize: Boolean
- @param minimize: True for a least-change upgrade, False for emerge-like algorithm
-
- @rtype: String | None
- @return: the lowest unaffected version that is greater than
- the installed version.
- """
- rValue = None
- v_installed = []
- u_installed = []
- for v in vulnerableList:
- v_installed += match(v, "vartree")
-
- for u in unaffectedList:
- u_installed += match(u, "vartree")
-
- install_unaffected = True
- for i in v_installed:
- if i not in u_installed:
- install_unaffected = False
-
- if install_unaffected:
- return rValue
-
- for u in unaffectedList:
- mylist = match(u, "porttree", match_type="match-all")
- for c in mylist:
- c_pv = portage.catpkgsplit(c)
- i_pv = portage.catpkgsplit(portage.best(v_installed))
- if portage.pkgcmp(c_pv[1:], i_pv[1:]) > 0 \
- and (rValue == None \
- or not match("="+rValue, "porttree") \
- or (minimize ^ (portage.pkgcmp(c_pv[1:], portage.catpkgsplit(rValue)[1:]) > 0)) \
- and match("="+c, "porttree")) \
- and portage.db["/"]["porttree"].dbapi.aux_get(c, ["SLOT"]) == portage.db["/"]["vartree"].dbapi.aux_get(portage.best(v_installed), ["SLOT"]):
- rValue = c_pv[0]+"/"+c_pv[1]+"-"+c_pv[2]
- if c_pv[3] != "r0": # we don't like -r0 for display
- rValue += "-"+c_pv[3]
- return rValue
-
-
-# simple Exception classes to catch specific errors
-class GlsaTypeException(Exception):
- def __init__(self, doctype):
- Exception.__init__(self, "wrong DOCTYPE: %s" % doctype)
-
-class GlsaFormatException(Exception):
- pass
-
-class GlsaArgumentException(Exception):
- pass
-
-# GLSA xml data wrapper class
-class Glsa:
- """
- This class is a wrapper for the XML data and provides methods to access
- and display the contained data.
- """
- def __init__(self, myid, myconfig):
- """
- Simple constructor to set the ID, store the config and gets the
- XML data by calling C{self.read()}.
-
- @type myid: String
- @param myid: String describing the id for the GLSA object (standard
- GLSAs have an ID of the form YYYYMM-nn) or an existing
- filename containing a GLSA.
- @type myconfig: portage.config
- @param myconfig: the config that should be used for this object.
- """
- if re.match(r'\d{6}-\d{2}', myid):
- self.type = "id"
- elif os.path.exists(myid):
- self.type = "file"
- else:
- raise GlsaArgumentException("Given ID "+myid+" isn't a valid GLSA ID or filename.")
- self.nr = myid
- self.config = myconfig
- self.read()
-
- def read(self):
- """
- Here we build the filename from the config and the ID and pass
- it to urllib to fetch it from the filesystem or a remote server.
-
- @rtype: None
- @return: None
- """
- if self.config["CHECKMODE"] == "local":
- repository = "file://" + self.config["GLSA_DIR"]
- else:
- repository = self.config["GLSA_SERVER"]
- if self.type == "file":
- myurl = "file://"+self.nr
- else:
- myurl = repository + self.config["GLSA_PREFIX"] + str(self.nr) + self.config["GLSA_SUFFIX"]
- self.parse(urllib.urlopen(myurl))
- return None
-
- def parse(self, myfile):
- """
- This method parses the XML file and sets up the internal data
- structures by calling the different helper functions in this
- module.
-
- @type myfile: String
- @param myfile: Filename to grab the XML data from
- @rtype: None
- @returns: None
- """
- self.DOM = xml.dom.minidom.parse(myfile)
- if not self.DOM.doctype:
- raise GlsaTypeException(None)
- elif self.DOM.doctype.systemId != "http://www.gentoo.org/dtd/glsa.dtd":
- raise GlsaTypeException(self.DOM.doctype.systemId)
- myroot = self.DOM.getElementsByTagName("glsa")[0]
- if self.type == "id" and myroot.getAttribute("id") != self.nr:
- raise GlsaFormatException("filename and internal id don't match:" + myroot.getAttribute("id") + " != " + self.nr)
-
- # the simple (single, required, top-level, #PCDATA) tags first
- self.title = getText(myroot.getElementsByTagName("title")[0], format="strip")
- self.synopsis = getText(myroot.getElementsByTagName("synopsis")[0], format="strip")
- self.announced = getText(myroot.getElementsByTagName("announced")[0], format="strip")
- self.revised = getText(myroot.getElementsByTagName("revised")[0], format="strip")
-
- # now the optional and 0-n toplevel, #PCDATA tags and references
- try:
- self.access = getText(myroot.getElementsByTagName("access")[0], format="strip")
- except IndexError:
- self.access = ""
- self.bugs = getMultiTagsText(myroot, "bug", format="strip")
- self.references = getMultiTagsText(myroot.getElementsByTagName("references")[0], "uri", format="keep")
-
- # and now the formatted text elements
- self.description = getText(myroot.getElementsByTagName("description")[0], format="xml")
- self.workaround = getText(myroot.getElementsByTagName("workaround")[0], format="xml")
- self.resolution = getText(myroot.getElementsByTagName("resolution")[0], format="xml")
- self.impact_text = getText(myroot.getElementsByTagName("impact")[0], format="xml")
- self.impact_type = myroot.getElementsByTagName("impact")[0].getAttribute("type")
- try:
- self.background = getText(myroot.getElementsByTagName("background")[0], format="xml")
- except IndexError:
- self.background = ""
-
- # finally the interesting tags (product, affected, package)
- self.glsatype = myroot.getElementsByTagName("product")[0].getAttribute("type")
- self.product = getText(myroot.getElementsByTagName("product")[0], format="strip")
- self.affected = myroot.getElementsByTagName("affected")[0]
- self.packages = {}
- for p in self.affected.getElementsByTagName("package"):
- name = p.getAttribute("name")
- if not name in self.packages:
- self.packages[name] = []
- tmp = {}
- tmp["arch"] = p.getAttribute("arch")
- tmp["auto"] = (p.getAttribute("auto") == "yes")
- tmp["vul_vers"] = [makeVersion(v) for v in p.getElementsByTagName("vulnerable")]
- tmp["unaff_vers"] = [makeVersion(v) for v in p.getElementsByTagName("unaffected")]
- tmp["vul_atoms"] = [makeAtom(name, v) for v in p.getElementsByTagName("vulnerable")]
- tmp["unaff_atoms"] = [makeAtom(name, v) for v in p.getElementsByTagName("unaffected")]
- self.packages[name].append(tmp)
- # TODO: services aren't really used yet
- self.services = self.affected.getElementsByTagName("service")
- return None
-
- def dump(self, outstream=sys.stdout):
- """
- Dumps a plaintext representation of this GLSA to I{outfile} or
- B{stdout} if it is ommitted. You can specify an alternate
- I{encoding} if needed (default is latin1).
-
- @type outstream: File
- @param outfile: Stream that should be used for writing
- (defaults to sys.stdout)
- """
- width = int(self.config["PRINTWIDTH"])
- outstream.write(center("GLSA %s: \n%s" % (self.nr, self.title), width)+"\n")
- outstream.write((width*"=")+"\n")
- outstream.write(wrap(self.synopsis, width, caption="Synopsis: ")+"\n")
- outstream.write("Announced on: %s\n" % self.announced)
- outstream.write("Last revised on: %s\n\n" % self.revised)
- if self.glsatype == "ebuild":
- for k in self.packages.keys():
- pkg = self.packages[k]
- for path in pkg:
- vul_vers = "".join(path["vul_vers"])
- unaff_vers = "".join(path["unaff_vers"])
- outstream.write("Affected package: %s\n" % k)
- outstream.write("Affected archs: ")
- if path["arch"] == "*":
- outstream.write("All\n")
- else:
- outstream.write("%s\n" % path["arch"])
- outstream.write("Vulnerable: %s\n" % vul_vers)
- outstream.write("Unaffected: %s\n\n" % unaff_vers)
- elif self.glsatype == "infrastructure":
- pass
- if len(self.bugs) > 0:
- outstream.write("\nRelated bugs: ")
- for i in range(0, len(self.bugs)):
- outstream.write(self.bugs[i])
- if i < len(self.bugs)-1:
- outstream.write(", ")
- else:
- outstream.write("\n")
- if self.background:
- outstream.write("\n"+wrap(self.background, width, caption="Background: "))
- outstream.write("\n"+wrap(self.description, width, caption="Description: "))
- outstream.write("\n"+wrap(self.impact_text, width, caption="Impact: "))
- outstream.write("\n"+wrap(self.workaround, width, caption="Workaround: "))
- outstream.write("\n"+wrap(self.resolution, width, caption="Resolution: "))
- myreferences = ""
- for r in self.references:
- myreferences += (r.replace(" ", SPACE_ESCAPE)+NEWLINE_ESCAPE+" ")
- outstream.write("\n"+wrap(myreferences, width, caption="References: "))
- outstream.write("\n")
-
- def isVulnerable(self):
- """
- Tests if the system is affected by this GLSA by checking if any
- vulnerable package versions are installed. Also checks for affected
- architectures.
-
- @rtype: Boolean
- @returns: True if the system is affected, False if not
- """
- vList = []
- rValue = False
- for k in self.packages.keys():
- pkg = self.packages[k]
- for path in pkg:
- if path["arch"] == "*" or self.config["ARCH"] in path["arch"].split():
- for v in path["vul_atoms"]:
- rValue = rValue \
- or (len(match(v, "vartree")) > 0 \
- and getMinUpgrade(path["vul_atoms"], path["unaff_atoms"]))
- return rValue
-
- def isApplied(self):
- """
- Looks if the GLSA IDis in the GLSA checkfile to check if this
- GLSA was already applied.
-
- @rtype: Boolean
- @returns: True if the GLSA was applied, False if not
- """
- aList = portage.grabfile(self.config["CHECKFILE"])
- return (self.nr in aList)
-
- def inject(self):
- """
- Puts the ID of this GLSA into the GLSA checkfile, so it won't
- show up on future checks. Should be called after a GLSA is
- applied or on explicit user request.
-
- @rtype: None
- @returns: None
- """
- if not self.isApplied():
- checkfile = open(self.config["CHECKFILE"], "a+")
- checkfile.write(self.nr+"\n")
- checkfile.close()
- return None
-
- def getMergeList(self, least_change=True):
- """
- Returns the list of package-versions that have to be merged to
- apply this GLSA properly. The versions are as low as possible
- while avoiding downgrades (see L{getMinUpgrade}).
-
- @type least_change: Boolean
- @param least_change: True if the smallest possible upgrade should be selected,
- False for an emerge-like algorithm
- @rtype: List of Strings
- @return: list of package-versions that have to be merged
- """
- rValue = []
- for pkg in self.packages.keys():
- for path in self.packages[pkg]:
- update = getMinUpgrade(path["vul_atoms"], path["unaff_atoms"], minimize=least_change)
- if update:
- rValue.append(update)
- return rValue
+++ /dev/null
-# Default revdep-rebuild configuration file
-#
-# revdep-rebuild no longer uses hardcoded paths. To change the default
-# behavior the following variables can be changed:
-#
-# LD_LIBRARY_MASK - Mask of specially evaluated libraries
-#
-# SEARCH_DIRS - List of directories to search for executables and libraries
-# Use this for directories that are not included in PATH or ld.so.conf.
-# An application should normally not have to set this variable
-#
-# SEARCH_DIRS_MASK - List of directories to not search
-# Use this for directories that should not be searched by revdep-rebuild
-# This is normally used by binary packages such as openoffice-bin
-#
-# Note: This file is sourced using bash by the revdep-rebuild script
-
-LD_LIBRARY_MASK="libodbcinst.so libodbc.so libjava.so libjvm.so"
-SEARCH_DIRS="/bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
-SEARCH_DIRS_MASK="/lib*/modules"
-
+++ /dev/null
-Stanislav Brabec (original author)
-Paul Varner <fuzzyray@gentoo.org>
+++ /dev/null
-2005-06-05 Paul Varner <fuzzyray@gentoo.org>
-
- * ChangeLog moved to main gentoolkit ChangeLog
-
-2004-01-07 Karl Trygve Kalleberg <karltk@gentoo.org>
-
- * Added Makefile
- * Copied revdep-rebuild script from app-portage/gentoolkit
-
+++ /dev/null
-# Copyright 2004 Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright 2004 Gentoo Technologies, Inc.
-# Distributed under the terms of the GNU General Public License v2
-#
-# $Header$
-
-include ../../makedefs.mak
-
-all:
- echo "AIGBURTH (AYG-berth n.) Any piece of readily identifiable anatomy found among cooked meat."
-
-dist:
- mkdir -p ../../$(distdir)/src/revdep-rebuild
- cp Makefile AUTHORS README TODO ChangeLog revdep-rebuild revdep-rebuild.1 99revdep-rebuild ../../$(distdir)/src/revdep-rebuild/
-
-install:
-
- install -m 0755 revdep-rebuild $(bindir)/
- install -d $(docdir)/revdep-rebuild
- install -m 0644 AUTHORS README TODO $(docdir)/revdep-rebuild/
- install -m 0644 revdep-rebuild.1 $(mandir)/
- install -d $(sysconfdir)/revdep-rebuild
- install -m 0644 99revdep-rebuild $(sysconfdir)/revdep-rebuild/
+++ /dev/null
-This tool scans libraries and binaries for broken shared lib dependencies
-and fixes them by re-emerging those broken binaries and shared libraries.
-
-- Alastair Tse <liquidx@gentoo.org>
+++ /dev/null
-- revdep cache in /var/cache
- - list all .so files this package depends on
- - use timestamps of files to know when to rebuild
- - if ts of cache is older than any of the package's contained
- files, we must rebuild
-- update to use equery/gentoolkit
-- rewrite in python and/or eclectic module
+++ /dev/null
-#!/usr/bin/python
-# Copyright 1999-2005 Gentoo Foundation
-# $Header$
-
-# Temporary script to find package versions and slot for revdep-rebuild
-
-import sys
-
-sys.path.insert(0, "/usr/lib/gentoolkit/pym")
-import gentoolkit
-
-for pkgname in sys.argv[1:]:
- matches = gentoolkit.find_packages(pkgname)
- for pkg in matches:
- (cat, name, ver, rev) = gentoolkit.split_package_name(pkg.get_cpv())
- slot = pkg.get_env_var("SLOT")
- if rev == "r0":
- fullversion = ver
- else:
- fullversion = ver + "-" + rev
-
- print name + " " + fullversion + " (" + slot + ")"
+++ /dev/null
-#!/bin/bash
-# Copyright 1999-2008 Gentoo Foundation
-
-# revdep-rebuild: Reverse dependency rebuilder.
-# Original Author: Stanislav Brabec
-# Rewrite Author: Michael A. Smith
-# Current Maintainer: Paul Varner <fuzzyray@gentoo.org>
-
-# TODO:
-# - Use more /etc/init.d/functions.sh
-# - Try to reduce the number of global vars
-
-##
-# Global Variables:
-
-# Must-be-blank:
-unset GREP_OPTIONS
-
-# Readonly variables:
-declare -r APP_NAME="${0##*/}" # The name of this application
-declare -r OIFS="$IFS" # Save the IFS
-declare -r ENV_FILE=0_env.rr # Contains environment variables
-declare -r FILES_FILE=1_files.rr # Contains a list of files to search
-declare -r LDPATH_FILE=2_ldpath.rr # Contains the LDPATH
-declare -r BROKEN_FILE=3_broken.rr # Contains the list of broken files
-declare -r ERRORS_FILE=3_errors.rr # Contains the ldd error output
-declare -r RAW_FILE=4_raw.rr # Contains the raw list of packages
-declare -r OWNERS_FILE=4_owners.rr # Contains the file owners
-declare -r PKGS_FILE=4_pkgs.rr # Contains the unsorted bare package names
-declare -r EBUILDS_FILE=4_ebuilds.rr # Contains the unsorted atoms
- # (Appropriately slotted or versioned)
-declare -r ORDER_FILE=5_order.rr # Contains the sorted atoms
-declare -r STATUS_FILE=6_status.rr # Contains the ldd error output
-declare -ra FILES=(
- "$ENV_FILE"
- "$FILES_FILE"
- "$LDPATH_FILE"
- "$BROKEN_FILE"
- "$ERRORS_FILE"
- "$RAW_FILE"
- "$OWNERS_FILE"
- "$PKGS_FILE"
- "$EBUILDS_FILE"
- "$ORDER_FILE"
- "$STATUS_FILE"
-)
-
-# "Boolean" variables: Considered "true" if it has any value at all
-# "True" indicates we should...
-declare FULL_LD_PATH # ...search across the COMPLETE_LD_LIBRARY_PATH
-declare KEEP_TEMP # ...not delete tempfiles from the current run
-declare ORDER_PKGS # ...sort the atoms in deep dependency order
-declare PACKAGE_NAMES # ...emerge by slot, not by versionated atom
-declare RM_OLD_TEMPFILES # ...remove tempfiles from prior runs
-declare SEARCH_BROKEN # ...search for broken libraries and binaries
-declare VERBOSE # ...give verbose output
-
-# Globals that impact portage directly:
-declare EMERGE_DEFAULT_OPTS # String of options portage assumes to be set
-declare EMERGE_OPTIONS # Array of options to pass to portage
-declare PORTAGE_NICENESS # Renice to this value
-declare PORTAGE_ROOT # The root path for portage
-
-# Customizable incremental variables:
-# These variables can be prepended to either by setting the variable in
-# your environment prior to execution, or by placing an entry in
-# /etc/make.conf.
-#
-# An entry of "-*" means to clear the variable from that point forward.
-# Example: env SEARCH_DIRS="/usr/bin -*" revdep-rebuild will set SEARCH_DIRS
-# to contain only /usr/bin
-declare LD_LIBRARY_MASK # Mask of specially evaluated libraries
-declare SEARCH_DIRS # List of dirs to search for executables and libraries
-declare SEARCH_DIRS_MASK # List of dirs not to search
-
-# Other globals:
-declare OLDPROG # Previous pass through the progress meter
-declare EXACT_PKG # Versionated atom to emerge
-declare HEAD_TEXT # Feedback string about the search
-declare NOCOLOR # Set to "true" not to output term colors
-declare OK_TEXT # Feedback about a search which found no errors
-declare RC_NOCOLOR # Hack to insure we respect NOCOLOR
-declare REBUILD_LIST # Array of atoms to emerge
-declare SKIP_LIST # Array of atoms that cannot be emerged (masked?)
-declare SONAME # Soname/soname path pattern given on commandline
-declare SONAME_SEARCH # Value of SONAME modified to match ldd's output
-declare WORKING_TEXT # Feedback about the search
-declare WORKING_DIR # Working directory where cache files are kept
-
-main() {
- # preliminary setup
- get_opts "$@"
- setup_portage
- setup_search_paths_and_masks
- get_search_env
- echo
-
- # Search for broken binaries
- get_files
- get_ldpath
- main_checks
-
- # Associate broken binaries with packages to rebuild
- if [[ $PACKAGE_NAMES ]]; then
- get_packages
- clean_packages
- assign_packages_to_ebuilds
- else
- get_exact_ebuilds
- fi
-
- # Rebuild packages owning broken binaries
- get_build_order
- rebuild
-
- # All done
- cleanup
-}
-##
-# Refuse to delete anything before we cd to our tmpdir
-# (See mkdir_and_cd_to_tmpdir()
-rm() {
- eerror "I was instructed to rm '$@'"
- die 1 "Refusing to delete anything before changing to temporary directory."
-}
-: <<'EW'
-##
-# GNU find has -executable, but if our users' finds do not have that flag
-# we emulate it with this function. Also emulates -writable and -readable.
-# Usage: find PATH ARGS -- use find like normal, except use -executable instead
-# of various versions of -perm /+ blah blah and hacks
-find() {
- hash find || { die 1 'find not found!'; }
- # We can be pretty sure find itself should be executable.
- local testsubject="$(type -P find)"
- if [[ $(command find "$testsubject" -executable 2> /dev/null) ]]; then
- unset -f find # We can just use the command find
- elif [[ $(command find "$testsubject" -perm /u+x 2> /dev/null) ]]; then
- find() {
- a=(${@//-executable/-perm \/u+x})
- a=(${a[@]//-writable/-perm \/u+w})
- a=(${a[@]//-readable/-perm \/r+w})
- command find "${a[@]}"
- }
- elif [[ $(command find "$testsubject" -perm +u+x 2> /dev/null) ]]; then
- find() {
- a=(${@//-executable/-perm +u+x})
- a=(${a[@]//-writable/-perm +u+w})
- a=(${a[@]//-readable/-perm +r+w})
- command find "${a[@]}"
- }
- else # Last resort
- find() {
- a=(${@//-executable/-exec test -x '{}' \; -print})
- a=(${a[@]//-writable/-exec test -w '{}' \; -print})
- a=(${a[@]//-readable/-exec test -r '{}' \; -print})
- command find "${a[@]}"
- }
- fi
- find "$@"
-}
-EW
-
-print_usage() {
-cat << EOF
-Usage: $APP_NAME [OPTIONS] [--] [EMERGE_OPTIONS]
-
-Broken reverse dependency rebuilder.
-
- -C, --nocolor Turn off colored output
- -d, --debug Print way too much information (uses bash's set -xv)
- -e, --exact Emerge based on exact package version
- -h, --help Print this usage
- -i, --ignore Ignore temporary files from previous runs
- -k, --keep-temp Do not delete temporary files on exit
- -L, --library NAME Emerge existing packages that use the library with NAME
- --library=NAME NAME can be a full path to the library or a basic
- regular expression (man grep)
- -l, --no-ld-path Do not set LD_LIBRARY_PATH
- -o, --no-order Do not check the build order
- (Saves time, but may cause breakage.)
- -p, --pretend Do a trial run without actually emerging anything
- (also passed to emerge command)
- -P, --no-progress Turn off the progress meter
- -q, --quiet Be less verbose (also passed to emerge command)
- -v, --verbose Be more verbose (also passed to emerge command)
-
-Calls emerge, options after -- are ignored by $APP_NAME
-and passed directly to emerge.
-
-Report bugs to <http://bugs.gentoo.org>
-EOF
-}
-##
-# Usage: progress i n
-# i: current item
-# n: total number of items to process
-progress() {
- if [[ -t 1 ]]; then
- progress() {
- local curProg=$(( $1 * 100 / $2 ))
- (( curProg == OLDPROG )) && return # no change, output nothing
- OLDPROG="$curProg" # must be a global variable
- (( $1 == $2 )) && local lb=$'\n'
- echo -ne '\r \r'"[ $curProg% ] $lb"
- }
- progress $@
- else # STDOUT is not a tty. Disable progress meter.
- progress() { :; }
- fi
-}
-##
-# Usage: countdown n
-# n: number of seconds to count
-countdown() {
- local i
- for ((i=1; i<$1; i++)); do
- echo -ne '\a.'
- ((i<$1)) && sleep 1
- done
- echo -e '\a.'
-}
-##
-# Replace whitespace with linebreaks, normalize repeated '/' chars, and sort -u
-# (If any libs have whitespace in their filenames, someone needs punishment.)
-clean_var() {
- gawk 'BEGIN {RS="[[:space:]]"}
- /-\*/ {exit}
- /[^[:space:]]/ {gsub(/\/\/+/, "/"); print}' | sort -u
-}
-##
-# Exit and optionally output to sterr
-die() {
- local status=$1
- shift
- eerror "$@"
- exit $status
-}
-##
-# What to do when dynamic linking is consistent
-clean_exit() {
- if [[ ! $KEEP_TEMP ]]; then
- rm -f "${FILES[@]}"
- if [[ "$WORKING_DIR" != "/var/cache/${APP_NAME}" ]]; then
- # Remove the working directory
- builtin cd; rmdir "$WORKING_DIR"
- fi
- fi
- echo
- einfo "$OK_TEXT... All done. "
- exit 0
-}
-##
-# Get the name of the package that owns a file or list of files given as args.
-get_file_owner() {
- local IFS=$'\n'
- # ${*/%/ } adds a space to the end of each object name to prevent false
- # matches, for example /usr/bin/dia matching /usr/bin/dialog (bug #196460).
- find -L /var/db/pkg -name CONTENTS -print0 |
- xargs -0 grep -Fl "${*/%/ }" |
- sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:'
-}
-##
-# Normalize some EMERGE_OPTIONS
-normalize_emerge_opts() {
- # Normalize some EMERGE_OPTIONS
- EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-p/--pretend})
- EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--fetchonly})
- EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-v/--verbose})
-}
-##
-# Use the color preference from portage
-setup_color() {
- # This should still work if NOCOLOR is set by the -C flag or in the user's
- # environment.
- export NOCOLOR=$(portageq envvar NOCOLOR)
- [[ $NOCOLOR = yes || $NOCOLOR = true ]] && export RC_NOCOLOR=yes # HACK! (grr)
- . /etc/init.d/functions.sh
-}
-##
-# Die if an argument is missing.
-die_if_missing_arg() {
- [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1"
-}
-##
-# Die because an option is not recognized.
-die_invalid_option() {
- # Can't use eerror and einfo because this gets called before function.sh
- # is sourced
- echo
- echo "Encountered unrecognized option $1." >&2
- echo
- echo "$APP_NAME no longer automatically passes unrecognized options to portage."
- echo "Separate emerge-only options from revdep-rebuild options with the -- flag."
- echo
- echo "For example, $APP_NAME -v -- --ask"
- echo
- echo "See the man page or $APP_NAME -h for more detail."
- echo
- exit 1
-}
-##
-# Warn about deprecated options.
-warn_deprecated_opt() {
- # Can't use eerror and einfo because this gets called before function.sh
- # is sourced
- echo
- echo "Encountered deprecated option $1." >&2
- [[ $2 ]] && echo "Please use $2 instead." >&2
-}
-##
-# Get whole-word commandline options preceded by two dashes.
-get_longopts() {
- case $1 in
- --nocolor) export NOCOLOR="yes";;
- --no-color) warn_deprecated_opt "$1" "--nocolor"
- export NOCOLOR="yes";;
- --debug) set -xv;;
- --exact) unset PACKAGE_NAMES;;
- --help) print_usage
- exit 0;;
- --ignore) RM_OLD_TEMPFILES=1;;
- --keep-temp) KEEP_TEMP=1;;
- --library=*) # TODO: check for invalid values
- SONAME="${1#*=}"
- unset SEARCH_BROKEN;;
- --soname=*|--soname-regexp=*) # TODO: check for invalid values
- warn_deprecated_opt "${1%=*}" "--library"
- SONAME="${1#*=}"
- unset SEARCH_BROKEN;;
- --library) # TODO: check for invalid values
- die_if_missing_arg $1 $2
- shift
- SONAME="$1"
- unset SEARCH_BROKEN;;
- --soname|--soname-regexp) # TODO: check for invalid values
- warn_deprecated_opt "$1" "--library"
- die_if_missing_arg $1 $2
- shift
- SONAME="$1"
- unset SEARCH_BROKEN;;
- --no-ld-path) unset FULL_LD_PATH;;
- --no-order) unset ORDER_PKGS;;
- --no-progress) progress() { :; };;
- --pretend) EMERGE_OPTIONS+=("--pretend");;
- --quiet) echo_v() { :; }
- progress() { :; }
- quiet=1
- EMERGE_OPTIONS+=($1);;
- --verbose) VERBOSE=1
- EMERGE_OPTIONS+=("--verbose");;
- --extra-verbose) warn_deprecated_opt "$1" "--verbose"
- VERBOSE=1
- EMERGE_OPTIONS+=("--verbose");;
- --package-names) # No longer used, since it is the
- # default. We accept it for
- # backwards compatibility.
- warn_deprecated_opt "$1"
- PACKAGE_NAMES=1;;
- *) die_invalid_option $1;;
- esac
-}
-
-##
-# Get single-letter commandline options preceded by a single dash.
-get_shortopts() {
- local OPT OPTSTRING OPTARG OPTIND
- while getopts ":CdehikL:loPpqu:vX" OPT; do
- case "$OPT" in
- C) # TODO: Match syntax with the rest of gentoolkit
- export NOCOLOR="yes";;
- d) set -xv;;
- e) unset PACKAGE_NAMES;;
- h) print_usage
- exit 0;;
- i) RM_OLD_TEMPFILES=1;;
- k) KEEP_TEMP=1;;
- L) # TODO: Check for invalid values
- SONAME="${OPTARG#*=}"
- unset SEARCH_BROKEN;;
- l) unset FULL_LD_PATH;;
- o) unset ORDER_PKGS;;
- P) progress() { :; };;
- p) EMERGE_OPTIONS+=("--pretend");;
- q) echo_v() { :; }
- progress() { :; }
- quiet=1
- EMERGE_OPTIONS+=("--quiet");;
- v) VERBOSE=1
- EMERGE_OPTIONS+=("--verbose");;
- X) # No longer used, since it is the default.
- # We accept it for backwards compatibility.
- warn_deprecated_opt "-X"
- PACKAGE_NAMES=1;;
- *) die_invalid_option "-$OPTARG";;
- esac
- done
-}
-##
-# Get command-line options.
-get_opts() {
- local avoid_utils
- local -a args
- echo_v() { ewarn "$@"; }
- unset VERBOSE KEEP_TEMP EMERGE_OPTIONS RM_OLD_TEMPFILES
- ORDER_PKGS=1
- PACKAGE_NAMES=1
- SONAME="not found"
- SEARCH_BROKEN=1
- FULL_LD_PATH=1
- while [[ $1 ]]; do
- case $1 in
- --) shift
- EMERGE_OPTIONS+=("$@")
- break;;
- -*) while true; do
- args+=("$1")
- shift
- [[ ${1:--} = -* ]] && break
- done
- if [[ ${args[0]} = --* ]]; then
- get_longopts "${args[@]}"
- else
- get_shortopts "${args[@]}"
- fi;;
- *) die_invalid_option "$1";;
- esac
- unset args
- done
-
- setup_color
- normalize_emerge_opts
-
- # If the user is not super, add --pretend to EMERGE_OPTIONS
- if [[ ${EMERGE_OPTIONS[@]} != *--pretend* && $UID -ne 0 ]]; then
- ewarn "You are not superuser. Adding --pretend to emerge options."
- EMERGE_OPTIONS+=(--pretend)
- fi
-}
-##
-# Is there a --pretend or --fetchonly flag in the EMERGE_OPTIONS array?
-is_real_merge() {
- [[ ${EMERGE_OPTIONS[@]} != *--pretend* &&
- ${EMERGE_OPTIONS[@]} != *--fetchonly* ]]
-}
-##
-# Clean up temporary files and exit
-cleanup_and_die() {
- rm -f "$@"
- die 1 " ...terminated. Removing incomplete $@."
-}
-##
-# Clean trap
-clean_trap() {
- trap "cleanup_and_die $*" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
- rm -f "$@"
-}
-##
-# Returns 0 if the first arg is found in the remaining args, 1 otherwise
-# (Returns 2 if given fewer than 2 arguments)
-has() {
- (( $# > 1 )) || return 2
- local IFS=$'\a' target="$1"
- shift
- [[ $'\a'"$*"$'\a' = *$'\a'$target$'\a'* ]]
-}
-##
-# Dies when it can't change directories
-cd() {
- if builtin cd -P "$@"; then
- if [[ $1 != $PWD ]]; then
- # Some symlink malfeasance is going on
- die 1 "Working directory expected to be $1, but it is $PWD"
- fi
- else
- die 1 "Unable to change working directory to '$@'"
- fi
-}
-##
-# Tries not to delete any files or directories it shouldn't
-setup_rm() {
- ##
- # Anything in the FILES array in tmpdir is fair game for removal
- rm() {
- local i IFS=$'\a'
- [[ $APP_NAME ]] || die 1 '$APP_NAME is not defined! (This is a bug.)'
- case $@ in
- */*|*-r*|*-R*) die 1 "Oops, I'm not allowed to delete that. ($@)";;
- esac
- for i; do
- # Don't delete files that are not listed in the array
- # Allow no slashes or recursive deletes at all.
- case $i in
- */*|-*r*|-*R*) :;; # Not OK
- -*) continue;; # OK
- esac
- has "$i" "${FILES[@]}" && continue
- die 1 "Oops, I'm not allowed to delete that. ($@)"
- done
- command rm "$@"
- }
- # delete this setup function so it's harmless to re-run
- setup_rm() { :; }
-}
-##
-# Make our temporary files directory
-# $1 - directory name
-# $2 - user name
-verify_tmpdir() {
- umask 007 || die $? "Unable to set umask 007"
- if [[ ! $1 ]]; then
- die 1 'Temporary file path is unset! (This is a bug.)'
- elif [[ -d $1 ]]; then
- # HACK: I hate using find this way
- if [[ $(find "$1" -type d ! \( -user $2 -perm -0700 \) ) ]]; then
- eerror "Incorrect permissions on $1"
- eerror "or at least one file in $1."
- die 1 "Please make sure it's not a symlink and then remove it."
- fi
- cd "$1"
- else
- die 1 "Unable to find a satisfactory location for temporary files ($1)"
- fi
- [[ $VERBOSE ]] && einfo "Temporary cache files are located in $PWD"
- setup_rm
-}
-get_search_env() {
- local new_env
- local old_env
- local uid=$(python -c 'import os; import pwd; print pwd.getpwuid(os.getuid())[0]')
- # Find a place to put temporary files
- if [[ "$uid" == "root" ]]; then
- local tmp_target="/var/cache/${APP_NAME}"
- else
- local tmp_target="$(mktemp -d -t revdep-rebuild.XXXXXXXXXX)"
- fi
-
- # From here on all work is done inside the temporary directory
- verify_tmpdir "$tmp_target" "$uid"
- WORKING_DIR="$tmp_target"
-
- if [[ $SEARCH_BROKEN ]]; then
- SONAME_SEARCH="$SONAME"
- HEAD_TEXT="broken by a package update"
- OK_TEXT="Dynamic linking on your system is consistent"
- WORKING_TEXT="consistency"
- else
- # first case is needed to test against /path/to/foo.so
- if [[ $SONAME = /* ]]; then
- # Set to "<space>$SONAME<space>"
- SONAME_SEARCH=" $SONAME "
- # Escape the "/" characters
- SONAME_SEARCH="${SONAME_SEARCH//\//\\/}"
- else
- # Set to "<tab>$SONAME<space>"
- SONAME_SEARCH=$'\t'"$SONAME "
- fi
- HEAD_TEXT="using $SONAME"
- OK_TEXT="There are no dynamic links to $SONAME"
- unset WORKING_TEXT
- fi
-
- # If any of our temporary files are older than 1 day, remove them all
- if [[ ! $KEEP_TEMP ]]; then
- while read; do
- RM_OLD_TEMPFILES=1
- break
- done < <(find -L . -maxdepth 1 -type f -name '*.rr' -mmin +1440 -print 2>/dev/null)
- fi
-
- # Compare old and new environments
- # Don't use our previous files if environment doesn't match
- new_env=$(
- # We do not care if these emerge options change
- EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--pretend/})
- EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--fetchonly/})
- EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--verbose/})
- cat <<- EOF
- SEARCH_DIRS="$SEARCH_DIRS"
- SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK"
- LD_LIBRARY_MASK="$LD_LIBRARY_MASK"
- PORTAGE_ROOT="$PORTAGE_ROOT"
- EMERGE_OPTIONS="${EMERGE_OPTIONS[@]}"
- ORDER_PKGS="$ORDER_PKGS"
- FULL_LD_PATH="$FULL_LD_PATH"
- EOF
- )
- if [[ -r "$ENV_FILE" && -s "$ENV_FILE" ]]; then
- old_env=$(<"$ENV_FILE")
- if [[ $old_env != $new_env ]]; then
- ewarn 'Environment mismatch from previous run, deleting temporary files...'
- RM_OLD_TEMPFILES=1
- fi
- else
- # No env file found, silently delete any other tempfiles that may exist
- RM_OLD_TEMPFILES=1
- fi
-
- # If we should remove old tempfiles, do so
- if [[ $RM_OLD_TEMPFILES ]]; then
- rm -f "${FILES[@]}"
- else
- for file in "${FILES[@]}"; do
- if [ -e "$file" ]; then
- chown ${uid}:portage "$file"
- chmod 700 "$file"
- fi
- done
- fi
-
- # Save the environment in a file for next time
- echo "$new_env" > "$ENV_FILE"
-
- [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
-
- echo
- einfo "Checking reverse dependencies"
- einfo "Packages containing binaries and libraries $HEAD_TEXT"
- einfo "will be emerged."
-}
-
-get_files() {
- einfo "Collecting system binaries and libraries"
- if [[ -r "$FILES_FILE" && -s "$FILES_FILE" ]]; then
- einfo "Found existing $FILES_FILE"
- else
- # Be safe and remove any extraneous temporary files
- # Don't remove 0_env.rr - The first file in the array
- rm -f "${FILES[@]:1}"
-
- clean_trap "$FILES_FILE"
-
- if [[ $SEARCH_DIRS_MASK ]]; then
- findMask=($SEARCH_DIRS_MASK)
- findMask="${findMask[@]/#/-o -path }"
- findMask="( ${findMask#-o } ) -prune -o"
- fi
- # TODO: Check this -- afaict SEARCH_DIRS isn't an array, so this should just be $SEARCH_DIRS?
- find ${SEARCH_DIRS[@]} $findMask -type f \( -perm -u+x -o -perm -g+x -o -perm -o+x -o \
- -name '*.so' -o -name '*.so.*' -o -name '*.la' \) -print 2> /dev/null |
- sort -u > "$FILES_FILE" ||
- die $? "find failed to list binary files (This is a bug.)"
- einfo "Generated new $FILES_FILE"
- fi
-}
-get_ldpath() {
- local COMPLETE_LD_LIBRARY_PATH
- [[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return
- einfo 'Collecting complete LD_LIBRARY_PATH'
- if [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]]; then
- einfo "Found existing $LDPATH_FILE."
- else
- clean_trap "$LDPATH_FILE"
- # Ensure that the "trusted" lib directories are at the start of the path
- COMPLETE_LD_LIBRARY_PATH=(
- /lib*
- /usr/lib*
- $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf)
- $(sed 's:/[^/]*$::' < "$FILES_FILE" | sort -ru)
- )
- IFS=':'
- COMPLETE_LD_LIBRARY_PATH="${COMPLETE_LD_LIBRARY_PATH[*]}"
- IFS="$OIFS"
- echo "$COMPLETE_LD_LIBRARY_PATH" > "$LDPATH_FILE"
- einfo "Generated new $LDPATH_FILE"
- fi
-}
-main_checks() {
- local target_file
- local -a files
- local i=0
- local ldd_output
- local ldd_status
- local numFiles
- local COMPLETE_LD_LIBRARY_PATH
- if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
- [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]] ||
- die 1 "Unable to find $LDPATH_FILE"
- COMPLETE_LD_LIBRARY_PATH=$(<"$LDPATH_FILE")
- fi
- einfo "Checking dynamic linking $WORKING_TEXT"
- if [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]]; then
- einfo "Found existing $BROKEN_FILE."
- else
- clean_trap "$BROKEN_FILE" "$ERRORS_FILE"
- files=($(<"$FILES_FILE"))
- numFiles="${#files[@]}"
- for target_file in "${files[@]}"; do
- if [[ $target_file != *.la ]]; then
- # Note: double checking seems to be faster than single with complete path
- # (special add ons are rare).
- ldd_output=$(ldd "$target_file" 2>> "$ERRORS_FILE" | sort -u)
- ldd_status=$? # TODO: Check this for problems with sort
- # HACK: if LD_LIBRARY_MASK is null or undefined grep -vF doesn't work
- if grep -vF "${LD_LIBRARY_MASK:=$'\a'}" <<< "$ldd_output" |
- grep -q "$SONAME_SEARCH"; then
- if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
- if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" ldd "$target_file" 2>/dev/null |
- grep -vF "$LD_LIBRARY_MASK" | grep -q "$SONAME_SEARCH"; then
- # FIXME: I hate duplicating code
- # Only build missing direct dependencies
- MISSING_LIBS=$(
- expr='s/[[:space:]]*\([^[:space:]]*\) => not found/\1/p'
- sed -n "$expr" <<< "$ldd_output"
- )
- REQUIRED_LIBS=$(
- expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
- objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
- )
- MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
- if [[ $MISSING_LIBS ]]; then
- echo "obj $target_file" >> "$BROKEN_FILE"
- echo_v " broken $target_file (requires $MISSING_LIBS)"
- fi
- fi
- else
- # FIXME: I hate duplicating code
- # Only rebuild for direct dependencies
- MISSING_LIBS=$(
- expr="/$SONAME_SEARCH/s/^[[:space:]]*\([^[:space:]]*\).*$/\1/p"
- sort -u <<< "$ldd_output" | sed -n "$expr"
- )
- REQUIRED_LIBS=$(
- expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
- objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
- )
- MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
- if [[ $MISSING_LIBS ]]; then
- echo "obj $target_file" >> "$BROKEN_FILE"
- if [[ $SEARCH_BROKEN ]]; then
- echo_v " broken $target_file (requires $MISSING_LIBS)"
- else
- echo_v " found $target_file"
- fi
- fi
- fi
- fi
- elif [[ $SEARCH_BROKEN ]]; then
- # Look for broken .la files
- la_SEARCH_DIRS="$SEARCH_DIRS"
- la_search_dir=""
- la_broken=""
- la_lib=""
- for depend in $(
- gawk -F"[=']" '/^dependency_libs/{
- print $3
- }' "$target_file"
- ); do
- if [[ $depend = /* && ! -e $depend ]]; then
- echo "obj $target_file" >> "$BROKEN_FILE"
- echo_v " broken $target_file (requires $depend)"
- elif [[ $depend = -[LR]/* ]]; then
- if ! [[ $'\n'${la_SEARCH_DIRS}$'\n' == *$'\n'${depend#-?}$'\n'* ]]; then
- la_SEARCH_DIRS+=$'\n'"${depend#-?}"
- fi
- elif [[ $depend = "-l"* ]]; then
- la_lib="lib${depend#-l}"
- la_broken="yes"
- IFS=$'\n'
- for la_search_dir in $la_SEARCH_DIRS; do
- if [[ -e ${la_search_dir}/${la_lib}.so || -e ${la_search_dir}/${la_lib}.a ]]; then
- la_broken="no"
- fi
- done
- IFS="$OIFS"
- if [[ $la_broken = yes ]]; then
- echo "obj $target_file" >> "$BROKEN_FILE"
- echo_v " broken $target_file (requires $depend)"
- fi
- fi
- done
- unset la_SEARCH_DIRS la_search_dir la_broken la_lib
- fi
- [[ $VERBOSE ]] &&
- progress $((++i)) $numFiles $target_file ||
- progress $((++i)) $numFiles
- done
- if [[ $SEARCH_BROKEN ]]; then
- # Look for missing version
- while read target_file; do
- echo "obj $target_file" >> "$BROKEN_FILE"
- echo_v " broken $target_file (no version information available)"
- done < <(
- # Regexify LD_LIBRARY_MASK. Exclude it from the search.
- LD_LIBRARY_MASK="${LD_LIBRARY_MASK//$'\n'/|}"
- gawk -v ldmask="(${LD_LIBRARY_MASK//./\\\.})" '
- /no version information available/ && $0 !~ ldmask {
- gsub(/[()]/, "", $NF)
- if (seen[$NF]++) next
- print $NF
- }' "$ERRORS_FILE"
- )
- fi
- [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]] || clean_exit
- sort -u "$BROKEN_FILE" -o "$BROKEN_FILE"
- einfo "Generated new $BROKEN_FILE"
- fi
-}
-get_packages() {
- local target_file
- local EXACT_PKG
- local PKG
- local obj
- einfo 'Assigning files to packages'
- if [[ -r "$RAW_FILE" && -s "$RAW_FILE" ]]; then
- einfo "Found existing $RAW_FILE"
- else
- clean_trap "$RAW_FILE" "$OWNERS_FILE"
- while read obj target_file; do
- EXACT_PKG=$(get_file_owner $target_file)
- if [[ $EXACT_PKG ]]; then
- # Strip version information
- PKG="${EXACT_PKG%%-r[[:digit:]]*}"
- PKG="${PKG%-*}"
- echo "$EXACT_PKG" >> "$RAW_FILE"
- echo "$target_file -> $EXACT_PKG" >> "$OWNERS_FILE"
- echo_v " $target_file -> $PKG"
- else
- ewarn " !!! $target_file not owned by any package is broken !!!"
- echo "$target_file -> (none)" >> "$OWNERS_FILE"
- echo_v " $target_file -> (none)"
- fi
- done < "$BROKEN_FILE"
- einfo "Generated new $RAW_FILE and $OWNERS_FILE"
- fi
- # if we find '(none)' on every line, exit out
- if ! grep -qvF '(none)' "$OWNERS_FILE"; then
- ewarn "Found some broken files, but none of them were associated with known packages"
- ewarn "Unable to proceed with automatic repairs."
- ewarn "The broken files are listed in $OWNERS_FILE"
- if [[ $VERBOSE ]]; then
- ewarn "The broken files are:"
- while read filename junk; do
- ewarn " $filename"
- done < "$OWNERS_FILE"
- fi
- exit 0 # FIXME: Should we exit 1 here?
- fi
-}
-clean_packages() {
- einfo 'Cleaning list of packages to rebuild'
- if [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
- einfo "Found existing $PKGS_FILE"
- else
- sort -u "$RAW_FILE" > "$PKGS_FILE"
- einfo "Generated new $PKGS_FILE"
- fi
-}
-assign_packages_to_ebuilds() {
- local EXACT_PKG
- local PKG
- local SLOT
- einfo 'Assigning packages to ebuilds'
- if [[ -r "$EBUILDS_FILE" && -s "$EBUILDS_FILE" ]]; then
- einfo "Found existing $EBUILDS_FILE"
- elif [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
- clean_trap "$EBUILDS_FILE"
- while read EXACT_PKG; do
- # Get the slot
- PKG="${EXACT_PKG%%-r[[:digit:]]*}"
- PKG="${PKG%-*}"
- SLOT=$(</var/db/pkg/$EXACT_PKG/SLOT)
- echo "$PKG:$SLOT"
- done < "$PKGS_FILE" > "$EBUILDS_FILE"
- einfo "Generated new $EBUILDS_FILE"
- else
- einfo 'Nothing to rebuild.'
- die 1 '(The program should have already quit, so this is a minor bug.)'
- fi
-}
-get_exact_ebuilds() {
- einfo 'Assigning files to ebuilds'
- if [[ -r $EBUILDS_FILE && -s $EBUILDS_FILE ]]; then
- einfo "Found existing $EBUILDS_FILE"
- elif [[ -r $BROKEN_FILE && -s $BROKEN_FILE ]]; then
- rebuildList=" $(<"$BROKEN_FILE") "
- rebuildList=(${rebuildList//[[:space:]]obj[[:space:]]/ })
- get_file_owner "${rebuildList[@]}" | sed 's/^/=/' > "$EBUILDS_FILE"
- einfo "Generated new $EBUILDS_FILE"
- else
- einfo 'Nothing to rebuild.'
- die 1 '(The program should have already quit, so this is a minor bug.)'
- fi
-}
-list_skipped_packages() {
- ewarn
- ewarn 'Portage could not find any version of the following packages it could build:'
- ewarn "${SKIP_LIST[@]}"
- ewarn
- ewarn '(Perhaps they are masked, blocked, or removed from portage.)'
- ewarn 'Try to emerge them manually.'
- ewarn
-}
-get_build_order() {
- local -r OLD_EMERGE_DEFAULT_OPTS="$EMERGE_DEFAULT_OPTS"
- local RAW_REBUILD_LIST
- local REBUILD_GREP
- local i
- if [[ ! $ORDER_PKGS ]]; then
- einfo 'Skipping package ordering'
- return
- fi
- einfo 'Evaluating package order'
- if [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]]; then
- einfo "Found existing $ORDER_FILE"
- else
- clean_trap "$ORDER_FILE"
- RAW_REBUILD_LIST=$(<"$EBUILDS_FILE")
- if [[ $RAW_REBUILD_LIST ]]; then
- export EMERGE_DEFAULT_OPTS="--nospinner --pretend --oneshot --quiet"
- RAW_REBUILD_LIST=($RAW_REBUILD_LIST) # convert into array
- # If PACKAGE_NAMES is defined we're using slots, not versions
- if [[ $PACKAGE_NAMES ]]; then
- # Eliminate atoms that can't be built
- for i in "${!RAW_REBUILD_LIST[@]}"; do
- if [[ "${RAW_REBUILD_LIST[i]}" = *[A-Za-z]* ]]; then
- portageq best_visible "$PORTAGE_ROOT" "${RAW_REBUILD_LIST[i]}" >/dev/null && continue
- SKIP_LIST+=("${RAW_REBUILD_LIST[i]}")
- fi
- unset RAW_REBUILD_LIST[i]
- done
- # If RAW_REBUILD_LIST is empty, then we have nothing to build.
- if (( ${#RAW_REBUILD_LIST[@]} == 0 )); then
- if (( ${#SKIP_LIST[@]} == 0 )); then
- ewarn "The list of packages to skip is empty, but there are no"
- ewarn "packages listed to rebuild either. (This is a bug.)"
- else
- list_skipped_packages
- fi
- die 1 'Warning: Portage cannot rebuild any of the necessary packages.'
- fi
- fi
- RAW_REBUILD_LIST="${RAW_REBUILD_LIST[@]}"
- REBUILD_GREP=$(emerge --nodeps $RAW_REBUILD_LIST | sed 's/\[[^]]*\]//g')
- if (( ${PIPESTATUS[0]} == 0 )); then
- emerge --deep $RAW_REBUILD_LIST |
- sed 's/\[[^]]*\]//g' |
- grep -F "$REBUILD_GREP" > "$ORDER_FILE"
- fi
-
- # Here we use the PIPESTATUS from the second emerge, the --deep one.
- if (( ${PIPESTATUS[0]} != 0 )); then
- eerror
- eerror 'Warning: Failed to resolve package order.'
- eerror 'Will merge in arbitrary order'
- eerror
- cat <<- EOF
- Possible reasons:
- - An ebuild is no longer in the portage tree.
- - An ebuild is masked, use /etc/portage/packages.keyword
- and/or /etc/portage/package.unmask to unmask it
- EOF
- countdown 5
- rm -f "$ORDER_FILE"
- fi
- export EMERGE_DEFAULT_OPTS="$OLD_EMERGE_DEFAULT_OPTS"
- else
- einfo 'Nothing to rebuild.'
- die 1 '(The program should have already quit, so this is a minor bug.)'
- fi
- fi
- [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]] && einfo "Generated new $ORDER_FILE"
-}
-
-show_unowned_files() {
- if grep -qF '(none)' "$OWNERS_FILE"; then
- ewarn "Found some broken files that weren't associated with known packages"
- ewarn "The broken files are:"
- while read filename junk; do
- [[ $junk = *none* ]] && ewarn " $filename"
- done < "$OWNERS_FILE" | gawk '!s[$0]++' # (omit dupes)
- fi
-}
-##
-# Setup portage and the search paths
-setup_portage() {
- local PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
- PORTAGE_ROOT=$(portageq envvar ROOT)
-
- # Obey PORTAGE_NICENESS
- if [[ $PORTAGE_NICENESS ]]; then
- renice $PORTAGE_NICENESS $$ > /dev/null
- # Since we have already set our nice value for our processes,
- # reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
- export PORTAGE_NICENESS="0"
- fi
-
- PORTAGE_ROOT="${PORTAGE_ROOT:-/}"
-}
-
-##
-# Setup the paths to search (and filter the ones to avoid)
-setup_search_paths_and_masks() {
- local configfile sdir mdir skip_me filter_SEARCH_DIRS
-
- einfo "Configuring search environment for $APP_NAME"
-
- # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
- # portage, and the environment
-
- # Read the incremental variables from environment and portage
- # Until such time as portage supports these variables as incrementals
- # The value will be what is in /etc/make.conf
- SEARCH_DIRS+=" "$(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)
- SEARCH_DIRS_MASK+=" "$(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)
- LD_LIBRARY_MASK+=" "$(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)
-
- # Add the defaults
- if [[ -d /etc/revdep-rebuild ]]; then
- for configfile in /etc/revdep-rebuild/*; do
- SEARCH_DIRS+=" "$(. $configfile; echo $SEARCH_DIRS)
- SEARCH_DIRS_MASK+=" "$(. $configfile; echo $SEARCH_DIRS_MASK)
- LD_LIBRARY_MASK+=" "$(. $configfile; echo $LD_LIBRARY_MASK)
- done
- else
- SEARCH_DIRS+=" /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
- SEARCH_DIRS_MASK+=" /opt/OpenOffice /usr/lib/openoffice"
- LD_LIBRARY_MASK+=" libodbcinst.so libodbc.so libjava.so libjvm.so"
- fi
-
- # Get the ROOTPATH and PATH from /etc/profile.env
- if [[ -r "/etc/profile.env" && -s "/etc/profile.env" ]]; then
- SEARCH_DIRS+=" "$(. /etc/profile.env; /usr/bin/tr ':' ' ' <<< "$ROOTPATH $PATH")
- fi
-
- # Get the directories from /etc/ld.so.conf
- if [[ -r /etc/ld.so.conf && -s /etc/ld.so.conf ]]; then
- SEARCH_DIRS+=" "$(sed '/^#/d;s/#.*$//' /etc/ld.so.conf)
- fi
-
- # Set the final variables
- SEARCH_DIRS=$(clean_var <<< "$SEARCH_DIRS")
- SEARCH_DIRS_MASK=$(clean_var <<< "$SEARCH_DIRS_MASK")
- LD_LIBRARY_MASK=$(clean_var <<< "$LD_LIBRARY_MASK")
- # Filter masked paths from SEARCH_DIRS
- for sdir in ${SEARCH_DIRS} ; do
- skip_me=
- for mdir in ${SEARCH_DIRS_MASK}; do
- [[ ${sdir} == ${mdir}/* ]] && skip_me=1 && break
- done
- [[ -n ${skip_me} ]] || filter_SEARCH_DIRS+=" ${sdir}"
- done
- SEARCH_DIRS=$(clean_var <<< "${filter_SEARCH_DIRS}")
- [[ $SEARCH_DIRS ]] || die 1 "No search defined -- this is a bug."
-}
-##
-# Rebuild packages owning broken binaries
-rebuild() {
- if [[ -r $LIST.5_order && -s $LIST.5_order ]]; then
- REBUILD_LIST=( $(<"$LIST.5_order") )
- REBUILD_LIST="${REBUILD_LIST[@]/#/=}"
- else
- REBUILD_LIST=$(sort -u "$EBUILDS_FILE")
- fi
-
- trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
-
- einfo 'All prepared. Starting rebuild'
- echo "emerge --oneshot ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
-
- is_real_merge && countdown 10
-
- # Link file descriptor #6 with stdin so --ask will work
- exec 6<&0
-
- # Run in background to correctly handle Ctrl-C
- {
- EMERGE_DEFAULT_OPTS="--oneshot ${EMERGE_OPTIONS[@]}" emerge $REBUILD_LIST <&6
- echo $? > "$STATUS_FILE"
- } &
- wait
-
- # Now restore stdin from fd #6, where it had been saved, and close fd #6 ( 6<&- ) to free it for other processes to use.
- exec 0<&6 6<&-
-}
-##
-# Finish up
-cleanup() {
- if (( $(<"$STATUS_FILE") != 0 )); then
- ewarn
- ewarn "$APP_NAME failed to emerge all packages."
- ewarn 'you have the following choices:'
- einfo "- If emerge failed during the build, fix the problems and re-run $APP_NAME."
- einfo '- Use /etc/portage/package.keywords to unmask a newer version of the package.'
- einfo " (and remove $ORDER_FILE to be evaluated again)"
- einfo '- Modify the above emerge command and run it manually.'
- einfo '- Compile or unmerge unsatisfied packages manually,'
- einfo ' remove temporary files, and try again.'
- einfo ' (you can edit package/ebuild list first)'
- einfo
- einfo 'To remove temporary files, please run:'
- einfo "rm ${WORKING_DIR}/*.rr"
- show_unowned_files
- exit $EMERGE_STATUS
- elif is_real_merge; then
- trap_cmd() {
- eerror "terminated. Please remove the temporary files manually:"
- eerror "rm ${WORKING_DIR}/*.rr"
- exit 1
- }
- [[ "${SKIP_LIST[@]}" != "" ]] && list_skipped_packages
- trap trap_cmd SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
- einfo 'Build finished correctly. Removing temporary files...'
- einfo
- einfo 'You can re-run revdep-rebuild to verify that all libraries and binaries'
- einfo 'are fixed. Possible reasons for remaining inconsistencies include:'
- einfo ' orphaned files'
- einfo ' deep dependencies'
- einfo " packages installed outside of portage's control"
- einfo ' specially-evaluated libraries'
- if [[ -r "$OWNERS_FILE" && -s "$OWNERS_FILE" ]]; then
- show_unowned_files
- fi
- [[ $KEEP_TEMP ]] || rm "${FILES[@]}"
- else
- einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'
- fi
-}
-
-main "$@"
+++ /dev/null
-#!/bin/bash
-# Copyright 1999-2007 Gentoo Foundation
-# $Header$
-
-# revdep-rebuild: Reverse dependency rebuilder.
-# Original Author: Stanislav Brabec
-# Current Maintainer: Paul Varner <fuzzyray@gentoo.org>
-
-# Known problems:
-#
-# In exact ebuild mode revdep-rebuild can fail to properly order packages,
-# which are not up to date.
-# http://bugs.gentoo.org/show_bug.cgi?id=23018
-#
-# Rebuilding using --package-names mode should be default, but emerge has no
-# feature to update to latest version of defined SLOT.
-# http://bugs.gentoo.org/show_bug.cgi?id=4698
-
-# Customizable variables:
-#
-# LD_LIBRARY_MASK - Mask of specially evaluated libraries
-# SEARCH_DIRS - List of directories to search for executables and libraries
-# SEARCH_DIRS_MASK - List of directories to not search
-#
-# These variables can be prepended to either by setting the variable in
-# your environment prior to execution, or by placing an entry in
-# /etc/make.conf.
-#
-# An entry of "-*" means to clear the variable from that point forward.
-# Example: env SEARCH_DIRS="/usr/bin -*" revdep-rebuild will set SEARCH_DIRS
-# to contain only /usr/bin
-
-if [ "$1" = "-h" -o "$1" = "--help" ]
-then
- echo "Usage: $0 [OPTIONS] [--] [EMERGE_OPTIONS]"
- echo
- echo "Broken reverse dependency rebuilder."
- echo
- echo " -X, --package-names Emerge based on package names, not exact versions"
- echo " --library NAME Emerge existing packages that use the library with NAME"
- echo " --library=NAME NAME can be a full path to the library or a basic"
- echo " regular expression (man grep)"
- echo " -np, --no-ld-path Do not set LD_LIBRARY_PATH"
- echo " -nc, --nocolor Turn off colored output"
- echo " -i, --ignore Ignore temporary files from previous runs"
- echo " -q, --quiet Be less verbose (also passed to emerge command)"
- echo " -vv, --extra-verbose Be extra verbose"
- echo
- echo "Calls emerge, all other options are used for it (e. g. -p, --pretend)."
- echo
- echo "Report bugs to <http://bugs.gentoo.org>"
- exit 0
-fi
-
-echo "Configuring search environment for revdep-rebuild"
-
-# Obey PORTAGE_NICENESS
-PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
-if [ ! -z "$PORTAGE_NICENESS" ]
-then
- renice $PORTAGE_NICENESS $$ > /dev/null
- # Since we have already set our nice value for our processes,
- # reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
- export PORTAGE_NICENESS="0"
-fi
-
-PORTAGE_ROOT=$(portageq envvar ROOT)
-[ -z "$PORTAGE_ROOT" ] && PORTAGE_ROOT="/"
-
-# Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
-# portage, and the environment
-
-# Read the incremental variables from environment and portage
-# Until such time as portage supports these variables as incrementals
-# The value will be what is in /etc/make.conf
-PRELIMINARY_SEARCH_DIRS="$SEARCH_DIRS $(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)"
-PRELIMINARY_SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK $(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)"
-PRELIMINARY_LD_LIBRARY_MASK="$LD_LIBRARY_MASK $(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)"
-
-# Add the defaults
-if [ -d /etc/revdep-rebuild ]
-then
- for file in $(ls /etc/revdep-rebuild)
- do
- PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $(. /etc/revdep-rebuild/${file}; echo $SEARCH_DIRS)"
- PRELIMINARY_SEARCH_DIRS_MASK="$PRELIMINARY_SEARCH_DIRS_MASK $(. /etc/revdep-rebuild/${file}; echo $SEARCH_DIRS_MASK)"
- PRELIMINARY_LD_LIBRARY_MASK="$PRELIMINARY_LD_LIBRARY_MASK $(. /etc/revdep-rebuild/${file}; echo $LD_LIBRARY_MASK)"
- done
-else
- PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
- PRELIMINARY_SEARCH_DIRS_MASK="$PRELIMINARY_SEARCH_DIRS_MASK /opt/OpenOffice /usr/lib/openoffice"
- PRELIMINARY_LD_LIBRARY_MASK="$PRELIMINARY_LD_LIBRARY_MASK libodbcinst.so libodbc.so libjava.so libjvm.so"
-fi
-
-# Get the ROOTPATH and PATH from /etc/profile.env
-if [ -e "/etc/profile.env" ]
-then
- PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $((. /etc/profile.env; echo ${ROOTPATH}:${PATH}) | tr ':' ' ')"
-fi
-
-# Get the directories from /etc/ld.so.conf
-if [ -e /etc/ld.so.conf ]
-then
- PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $(grep -v "^#" /etc/ld.so.conf | tr '\n' ' ')"
-fi
-
-# Set the final variables
-# Note: Using $(echo $variable) removes extraneous spaces from variable assignment
-unset SEARCH_DIRS
-for i in $(echo $PRELIMINARY_SEARCH_DIRS)
-do
- [ "$i" = "-*" ] && break
- # Append a / at the end so that links and directories are treated the same by find
- # Remove any existing trailing slashes to prevent double-slashes
- SEARCH_DIRS="$(echo $SEARCH_DIRS ${i/%\//}/)"
-done
-# Remove any double-slashes from the path
-SEARCH_DIRS="$(echo $SEARCH_DIRS | sed 's:/\+:/:g')"
-
-unset SEARCH_DIRS_MASK
-for i in $(echo $PRELIMINARY_SEARCH_DIRS_MASK)
-do
- [ "$i" = "-*" ] && break
- SEARCH_DIRS_MASK="$(echo $SEARCH_DIRS_MASK $i)"
-done
-
-unset LD_LIBRARY_MASK
-for i in $(echo $PRELIMINARY_LD_LIBRARY_MASK)
-do
- [ "$i" = "-*" ] && break
- LD_LIBRARY_MASK="$(echo $LD_LIBRARY_MASK $i)"
-done
-
-# Use the color preference from portage
-NOCOLOR=$(portageq envvar NOCOLOR)
-
-# Base of temporary files names.
-touch ${HOME}/.revdep-rebuild_0.test 2>/dev/null
-if [ $? -eq 0 ]
-then
- LIST="${HOME}/.revdep-rebuild"
- rm ~/.revdep-rebuild_0.test
-else
- # Try to use /var/tmp since $HOME is not available
- touch /var/tmp/.revdep-rebuild_0.test 2>/dev/null
- if [ $? -eq 0 ]
- then
- LIST="/var/tmp/.revdep-rebuild"
- rm /var/tmp/.revdep-rebuild_0.test
- else
- echo
- echo "!!! Unable to write temporary files to either $HOME or /var/tmp !!!"
- echo
- exit 1
- fi
-fi
-
-shopt -s nullglob
-shopt -s expand_aliases
-unalias -a
-
-# Color Definitions
-NO="\x1b[0m"
-BR="\x1b[0;01m"
-CY="\x1b[36;01m"
-GR="\x1b[32;01m"
-RD="\x1b[31;01m"
-YL="\x1b[33;01m"
-BL="\x1b[34;01m"
-
-# Check if portage-utils are installed
-portageq has_version $PORTAGE_ROOT portage-utils
-if [ "$?" -eq 0 ]
-then
- PORTAGE_UTILS=true
-else
- PORTAGE_UTILS=false
-fi
-
-alias echo_v=echo
-
-PACKAGE_NAMES=false
-SONAME="not found"
-SONAME_GREP=grep
-SEARCH_BROKEN=true
-EXTRA_VERBOSE=false
-KEEP_TEMP=false
-FULL_LD_PATH=true
-
-EMERGE_OPTIONS=""
-PRELIMINARY_CALLED_OPTIONS=""
-while [ ! -z "$1" ] ; do
- case "$1" in
- -X | --package-names )
- PACKAGE_NAMES=true
- PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --package_names"
- shift
- ;;
- -q | --quiet )
- alias echo_v=:
- EMERGE_OPTIONS="${EMERGE_OPTIONS} $1"
- shift
- ;;
- --library=* | --soname=* | --soname-regexp=* )
- SONAME="${1#*=}"
- SEARCH_BROKEN=false
- PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --library=${SONAME}"
- shift
- ;;
- --library | --soname | --soname-regexp )
- SONAME="$2"
- SEARCH_BROKEN=false
- PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --library=${SONAME}"
- shift 2
- ;;
- -nc | --no-color | --nocolor )
- NOCOLOR=true
- shift
- ;;
- -np | --no-ld-path )
- FULL_LD_PATH=false
- PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --no-ld-path"
- shift
- ;;
- -i | --ignore )
- rm -f ${LIST}*
- shift
- ;;
- --keep-temp )
- KEEPTEMP=true
- shift
- ;;
- -vv | --extra-verbose )
- EXTRA_VERBOSE=true
- shift
- ;;
- -- )
- shift
- ;;
- * )
- EMERGE_OPTIONS="${EMERGE_OPTIONS} $1"
- shift
- ;;
- esac
-done
-
-EMERGE_OPTIONS=$(echo $EMERGE_OPTIONS | sed 's/^ //')
-
-if [ -z "$PRELIMINARY_CALLED_OPTIONS" ]
-then
- CALLED_OPTIONS=""
-else
- for i in $(echo $PRELIMINARY_CALLED_OPTIONS | tr ' ' '\n'| sort)
- do
- CALLED_OPTIONS="$(echo $CALLED_OPTIONS $i)"
- done
-fi
-
-if [ "$NOCOLOR" = "yes" -o "$NOCOLOR" = "true" ]
-then
- NOCOLOR=true
-else
- NOCOLOR=false
-fi
-
-# Make the NOCOLOR variable visible to emerge
-export NOCOLOR
-
-if $NOCOLOR
-then
- NO=""
- BR=""
- CY=""
- GR=""
- RD=""
- YL=""
- BL=""
-fi
-
-function set_trap () {
- trap "rm_temp $1" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
-}
-
-function rm_temp () {
- echo " terminated."
- echo "Removing incomplete $1."
- rm $1
- echo
- exit 1
-}
-
-if $SEARCH_BROKEN ; then
- SONAME_SEARCH="$SONAME"
- LLIST=$LIST
- HEAD_TEXT="broken by a package update"
- OK_TEXT="Dynamic linking on your system is consistent"
- WORKING_TEXT=" consistency"
-else
- # first case is needed to test against /path/to/foo.so
- if [ ${SONAME:0:1} == '/' ] ; then
- # Set to "<space>$SONAME<space>"
- SONAME_SEARCH=" $SONAME "
- else
- # Set to "<tab>$SONAME<space>"
- SONAME_SEARCH=" $SONAME "
- fi
- LLIST=${LIST}_$(echo "$SONAME_SEARCH$SONAME" | md5sum | head -c 8)
- HEAD_TEXT="using $SONAME"
- OK_TEXT="There are no dynamic links to $SONAME"
- WORKING_TEXT=""
-fi
-
-# If any of our temporary files are older than 1 day, remove them all
-[ "$(find "${LIST%/*}/." ! -name . -prune -name "${LIST##*/}*" -type f -mmin +1440)" != "" ] && rm -f ${LIST}*
-
-# Don't use our previous files if environment doesn't match
-if [ -f $LIST.0_env ]
-then
- PREVIOUS_SEARCH_DIRS=$(. ${LIST}.0_env; echo "$SEARCH_DIRS")
- PREVIOUS_SEARCH_DIRS_MASK=$(. ${LIST}.0_env; echo "$SEARCH_DIRS_MASK")
- PREVIOUS_LD_LIBRARY_MASK=$(. ${LIST}.0_env; echo "$LD_LIBRARY_MASK")
- PREVIOUS_PORTAGE_ROOT=$(. ${LIST}.0_env; echo "$PORTAGE_ROOT")
- PREVIOUS_OPTIONS=$(. ${LIST}.0_env; echo "$CALLED_OPTIONS")
- if [ "$PREVIOUS_SEARCH_DIRS" != "$SEARCH_DIRS" ] || \
- [ "$PREVIOUS_SEARCH_DIRS_MASK" != "$SEARCH_DIRS_MASK" ] || \
- [ "$PREVIOUS_LD_LIBRARY_MASK" != "$LD_LIBRARY_MASK" ] || \
- [ "$PREVIOUS_PORTAGE_ROOT" != "$PORTAGE_ROOT" ] || \
- [ "$PREVIOUS_OPTIONS" != "$CALLED_OPTIONS" ]
- then
- echo
- echo "Environment mismatch from previous run, deleting temporary files..."
- rm -f ${LIST}*
- fi
-fi
-
-# Clean up no longer needed environment variables
-unset PREVIOUS_SEARCH_DIRS PREVIOUS_SEARCH_DIRS_MASK PREVIOUS_LD_LIBRARY_MASK PREVIOUS_PORTAGE_ROOT PREVIOUS_OPTIONS
-unset PRELIMINARY_SEARCH_DIRS PRELIMINARY_SEARCH_DIRS_MASK PRELIMINARY_LD_LIBRARY_MASK PRELIMINARY_CALLED_OPTIONS
-
-# Log our environment
-echo "SEARCH_DIRS=\"$SEARCH_DIRS\"" > $LIST.0_env
-echo "SEARCH_DIRS_MASK=\"$SEARCH_DIRS_MASK\"" >> $LIST.0_env
-echo "LD_LIBRARY_MASK=\"$LD_LIBRARY_MASK\"" >> $LIST.0_env
-echo "PORTAGE_ROOT=\"$PORTAGE_ROOT\"" >> $LIST.0_env
-echo "CALLED_OPTIONS=\"$CALLED_OPTIONS\"" >> $LIST.0_env
-echo "EMERGE_OPTIONS=\"$EMERGE_OPTIONS\"" >> $LIST.0_env
-
-if $EXTRA_VERBOSE
-then
- echo
- echo "revdep-rebuild environment:"
- cat $LIST.0_env
-fi
-
-echo
-echo "Checking reverse dependencies..."
-echo
-echo "Packages containing binaries and libraries $HEAD_TEXT"
-echo "will be emerged."
-
-echo
-echo -n -e "${GR}Collecting system binaries and libraries...${NO}"
-
-if [ -f $LIST.1_files ]
-then
- echo " using existing $LIST.1_files."
-else
- # Be safe and remove any extraneous temporary files
- rm -f ${LIST}.[1-9]_*
-
- set_trap "$LIST.1_*"
-
- # Hack for the different versions of find.
- # Be extra paranoid and pipe results through sed to remove multiple slashes
- find_results=$(find /usr/bin/revdep-rebuild -type f -perm /u+x 2>/dev/null)
- if [ -z $find_results ]
- then
- find_results=$(find /usr/bin/revdep-rebuild -type f -perm +u+x 2>/dev/null)
- if [ -z $find_results ]
- then
- echo -e "\n"
- echo -e "${RD}Unable to determine how to use find to locate executable files${NO}"
- echo -e "${RD}Open a bug at http://bugs.gentoo.org${NO}"
- echo
- exit 1
- else
- # using -perm +u+x for find command
- find $SEARCH_DIRS -type f \( -perm +u+x -o -name '*.so' -o -name '*.so.*' -o -name '*.la' \) 2>/dev/null | sort | uniq | sed 's:/\+:/:g' >$LIST.0_files
- fi
- else
- # using -perm /u+x for find command
- find $SEARCH_DIRS -type f \( -perm /u+x -o -name '*.so' -o -name '*.so.*' -o -name '*.la' \) 2>/dev/null | sort | uniq | sed 's:/\+:/:g' >$LIST.0_files
- fi
-
- # Remove files that match SEARCH_DIR_MASK
- for dir in $SEARCH_DIRS_MASK
- do
- grep -v "^$dir" $LIST.0_files > $LIST.1_files
- mv $LIST.1_files $LIST.0_files
- done
-
- mv $LIST.0_files $LIST.1_files
- echo -e " done.\n ($LIST.1_files)"
-fi
-
-if $SEARCH_BROKEN && $FULL_LD_PATH ; then
- echo
- echo -n -e "${GR}Collecting complete LD_LIBRARY_PATH...${NO}"
- if [ -f $LIST.2_ldpath ] ; then
- echo " using existing $LIST.2_ldpath."
- else
- set_trap "$LIST.2_ldpath"
- # Ensure that the "trusted" lib directories are at the start of the path
- (
- echo /lib* /usr/lib* | sed 's/ /:/g'
- sed '/^#/d;s/#.*$//' </etc/ld.so.conf
- sed 's:/[^/]*$::' <$LIST.1_files | sort -ru
- ) | tr '\n' : | tr -d '\r' | sed 's/:$//' >$LIST.2_ldpath
- echo -e " done.\n ($LIST.2_ldpath)"
- fi
- COMPLETE_LD_LIBRARY_PATH="$(cat $LIST.2_ldpath)"
-fi
-
-echo
-echo -n -e "${GR}Checking dynamic linking$WORKING_TEXT...${NO}"
-if [ -f $LLIST.3_rebuild ] ; then
- echo " using existing $LLIST.3_rebuild."
-else
- echo_v
- set_trap "$LLIST.3_rebuild"
- LD_MASK="\\( $(echo "$LD_LIBRARY_MASK" | sed 's/\./\\./g;s/ / \\| /g') \\)"
- echo -n >$LLIST.3_rebuild
- echo -n >$LLIST.3_ldd_errors
- cat $LIST.1_files | egrep -v '*\.la$' | while read FILE ; do
- # Note: double checking seems to be faster than single
- # with complete path (special add ons are rare).
- if ldd "$FILE" 2>>$LLIST.3_ldd_errors | grep -v "$LD_MASK" | $SONAME_GREP -q "$SONAME_SEARCH" ; then
- if $SEARCH_BROKEN && $FULL_LD_PATH ; then
- if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" ldd "$FILE" 2>/dev/null | grep -v "$LD_MASK" | $SONAME_GREP -q "$SONAME_SEARCH" ; then
- # FIX: I hate duplicating code
- # Only build missing direct dependencies
- ALL_MISSING_LIBS=$(ldd "$FILE" 2>/dev/null | sort -u | sed -n 's/ \(.*\) => not found/\1/p' | tr '\n' ' ' | sed 's/ $//' )
- REQUIRED_LIBS=$(objdump -x $FILE | grep NEEDED | awk '{print $2}' | tr '\n' ' ' | sed 's/ $//')
- MISSING_LIBS=""
- for lib in $ALL_MISSING_LIBS
- do
- if echo $REQUIRED_LIBS | grep -q $lib
- then
- MISSING_LIBS="$MISSING_LIBS $lib"
- fi
- done
- if [ "$MISSING_LIBS" != "" ]
- then
- echo "obj $FILE" >>$LLIST.3_rebuild
- echo_v " broken $FILE (requires ${MISSING_LIBS})"
- fi
- fi
- else
- # FIX: I hate duplicating code
- # Only rebuild for direct dependencies
- ALL_MISSING_LIBS=$(ldd "$FILE" 2>/dev/null | sort -u | $SONAME_GREP "$SONAME_SEARCH" | awk '{print $1}' | tr '\n' ' ' | sed 's/ $//' )
- REQUIRED_LIBS=$(objdump -x $FILE | grep NEEDED | awk '{print $2}' | tr '\n' ' ' | sed 's/ $//')
- MISSING_LIBS=""
- for lib in $ALL_MISSING_LIBS
- do
- if echo $REQUIRED_LIBS | grep -q $lib
- then
- MISSING_LIBS="$MISSING_LIBS $lib"
- fi
- done
- if [ "$MISSING_LIBS" != "" ]
- then
- echo "obj $FILE" >>$LLIST.3_rebuild
- if $SEARCH_BROKEN ; then
- echo_v " broken $FILE (requires ${MISSING_LIBS})"
- else
- echo_v " found $FILE"
- fi
- fi
- fi
- fi
- done
- if $SEARCH_BROKEN ; then
- # Look for missing version
- for FILE in $(grep "no version information available" $LLIST.3_ldd_errors | awk '{print $NF}' | sed 's/[()]//g' | sort -u) ; do
- echo "obj $FILE" >>$LLIST.3_rebuild
- echo_v " broken $FILE (no version information available)"
- done
- # Look for broken .la files
- cat $LIST.1_files | egrep '*\.la$' | while read FILE ; do
- for depend in $(grep '^dependency_libs' $FILE | awk -F'=' '{print $2}' | sed "s/'//g") ; do
- [ ${depend:0:1} != '/' ] && continue
- if [ ! -e $depend ] ; then
- echo "obj $FILE" >>$LLIST.3_rebuild
- echo_v " broken $FILE (requires ${depend})"
- fi
- done
- done
- fi
- echo -e " done.\n ($LLIST.3_rebuild)"
-fi
-
-if $PACKAGE_NAMES ; then
- EXACT_EBUILDS=false
-
- echo
- echo -n -e "${GR}Assigning files to packages...${NO}"
- if [ -f $LLIST.4_packages_raw ] ; then
- echo " using existing $LLIST.4_packages_raw."
- else
- set_trap "$LLIST.4_packages*"
- echo -n >$LLIST.4_packages_raw
- echo -n >$LLIST.4_package_owners
- cat $LLIST.3_rebuild | while read obj FILE ; do
- if $PORTAGE_UTILS ; then
- EXACT_PKG="$(qfile -qvC ${FILE} )"
- else
- EXACT_PKG=$(find /var/db/pkg -name CONTENTS | xargs fgrep -l "obj $FILE " | sed -e 's:/var/db/pkg/\(.*\)/CONTENTS:\1:g')
- fi
- # Ugly sed hack to strip version information
- PKG="$(echo $EXACT_PKG | sed 's/-r[0-9].*$//;s/\(^.*\/*\)-.*$/\1/')"
- if [ -z "$PKG" ] ; then
- echo -n -e "\n ${RD}*** $FILE not owned by any package is broken! ***${NO}"
- echo "$FILE -> (none)" >> $LLIST.4_package_owners
- echo_v -n -e "\n $FILE -> (none)"
- else
- echo "$EXACT_PKG" >> $LLIST.4_packages_raw
- echo "$FILE -> $EXACT_PKG" >> $LLIST.4_package_owners
- echo_v -n -e "\n $FILE -> $PKG"
- fi
- done
- echo_v
- echo -e " done.\n ($LLIST.4_packages_raw, $LLIST.4_package_owners)"
- fi
-
- echo
- echo -n -e "${GR}Cleaning list of packages to rebuild...${NO}"
- if [ -f $LLIST.4_packages ] ; then
- echo " using existing $LLIST.4_packages."
- else
- sort -u $LLIST.4_packages_raw >$LLIST.4_packages
- echo -e " done.\n ($LLIST.4_packages)"
- fi
-
- echo
- echo -n -e "${GR}Assigning packages to ebuilds...${NO}"
- if [ -f $LLIST.4_ebuilds ] ; then
- echo " using existing $LLIST.4_ebuilds."
- else
- if [ -s "$LLIST.4_packages" ]
- then
- set_trap "$LLIST.4_ebuilds"
- cat $LLIST.4_packages | while read EXACT_PKG
- do
- PKG="$(echo $EXACT_PKG | sed 's/-r[0-9].*$//;s/\(^.*\/*\)-.*$/\1/')"
- SLOT=$(cat /var/db/pkg/${EXACT_PKG}/SLOT)
- best_visible=$(portageq best_visible $PORTAGE_ROOT ${PKG}:${SLOT})
- [ "x" != "x$best_visible" ] && echo $best_visible
- done > $LLIST.4_ebuilds
- echo -e " done.\n ($LLIST.4_ebuilds)"
- else
- echo " Nothing to rebuild"
- echo -n > $LLIST.4_ebuilds
- fi
- fi
-else
- EXACT_EBUILDS=true
-
- echo
- echo -n -e "${GR}Assigning files to ebuilds...${NO}"
- if [ -f $LLIST.4_ebuilds ] ; then
- echo " using existing $LLIST.4_ebuilds."
- else
- if [ -s "$LLIST.3_rebuild" ] ; then
- set_trap "$LLIST.4_ebuilds"
- find /var/db/pkg -name CONTENTS | xargs fgrep -l -f $LLIST.3_rebuild |
- sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:' > $LLIST.4_ebuilds
- echo -e " done.\n ($LLIST.4_ebuilds)"
- else
- echo " Nothing to rebuild"
- echo -n > $LLIST.4_ebuilds
- fi
- fi
-
-fi
-
-echo
-echo -n -e "${GR}Evaluating package order...${NO}"
-if [ -f $LLIST.5_order ] ; then
- echo " using existing $LLIST.5_order."
-else
- set_trap "$LLIST.5_order"
- RAW_REBUILD_LIST="$(cat $LLIST.4_ebuilds | sed s/^/=/ | tr '\n' ' ')"
- if [ ! -z "$RAW_REBUILD_LIST" ] ; then
- REBUILD_GREP="^\\($( (EMERGE_DEFAULT_OPTS="" emerge --nospinner --pretend --oneshot --nodeps --quiet $RAW_REBUILD_LIST ; echo $? >$LLIST.5a_status ) | sed -n 's/\./\\&/g;s/ //g;s/$/\\/;s/\[[^]]*\]//gp' | tr '\n' '|' | sed 's/|$//'))\$"
- if [ $(cat $LLIST.5a_status) -gt 0 ] ; then
- echo ""
- echo -e "${RD}Warning: Failed to resolve package order."
- echo -e "Will merge in \"random\" order!${NO}"
- echo "Possible reasons:"
- echo "- An ebuild is no longer in the portage tree."
- echo "- An ebuild is masked, use /etc/portage/packages.keyword"
- echo " and/or /etc/portage/package.unmask to unmask it"
- for i in . . . . . ; do
- echo -n -e '\a.'
- sleep 1
- done
- ln -f $LLIST.4_ebuilds $LLIST.5_order
- else
- (EMERGE_DEFAULT_OPTS="" emerge --nospinner --pretend --oneshot --deep --quiet $RAW_REBUILD_LIST ; echo $? >$LLIST.5b_status ) | sed -n 's/ *$//;s/^\[.*\] //p' | awk '{print $1}' | grep "$REBUILD_GREP" >$LLIST.5_order
- if [ $(cat $LLIST.5b_status) -gt 0 ] ; then
- echo ""
- echo -e "${RD}Warning: Failed to resolve package order."
- echo -e "Will merge in \"random\" order!${NO}"
- echo "Possible reasons:"
- echo "- An ebuild is no longer in the portage tree."
- echo "- An ebuild is masked, use /etc/portage/packages.keyword"
- echo " and/or /etc/portage/package.unmask to unmask it"
- for i in . . . . . ; do
- echo -n -e '\a.'
- sleep 1
- done
- rm -f $LLIST.5_order
- ln -f $LLIST.4_ebuilds $LLIST.5_order
- fi
- fi
- else
- echo -n "" >$LLIST.5_order
- fi
- echo -e " done.\n ($LLIST.5_order)"
-fi
-
-# Clean up no longer needed environment variables
-unset COMPLETE_LD_LIBRARY_PATH SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK PORTAGE_ROOT CALLED_OPTIONS
-
-REBUILD_LIST="$(cat $LLIST.5_order | sed s/^/=/ | tr '\n' ' ')"
-
-trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
-
-if [ -z "$REBUILD_LIST" ] ; then
- echo -e "\n${GR}$OK_TEXT... All done.${NO} "
- if [ ! $KEEPTEMP ]
- then
- rm $LIST.[0-2]_*
- rm $LLIST.[3-9]_*
- fi
- exit 0
-fi
-
-IS_REAL_MERGE=true
-echo " $EMERGE_OPTIONS " | grep -q '\( -p \| --pretend \| -f \| --fetchonly \)' && IS_REAL_MERGE=false
-
-echo
-echo -e "${GR}All prepared. Starting rebuild...${NO}"
-
-echo "emerge --oneshot $EMERGE_OPTIONS $REBUILD_LIST"
-
-if $IS_REAL_MERGE ; then
- for i in . . . . . . . . . . ; do
- echo -n -e '\a.'
- sleep 1
- done
- echo
-fi
-
-# Link file descriptor #6 with stdin
-exec 6<&0
-
-# Run in background to correctly handle Ctrl-C
-(
- EMERGE_DEFAULT_OPTS="" emerge --oneshot $EMERGE_OPTIONS $REBUILD_LIST <&6
- echo $? >$LLIST.6_status
-) &
-wait
-
-# Now restore stdin from fd #6, where it had been saved, and close fd #6 ( 6<&- ) to free it for other processes to use.
-exec 0<&6 6<&-
-
-#if $EXACT_EBUILDS ; then
-# mv -i /usr/portage/profiles/package.mask.hidden /usr/portage/profiles/package.mask
-# trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
-#fi
-
-if [ "$(cat $LLIST.6_status)" -gt 0 ] ; then
- echo
- echo -e "${RD}revdep-rebuild failed to emerge all packages${NO}"
- echo -e "${RD}you have the following choices:${NO}"
- echo
- echo "- if emerge failed during the build, fix the problems and re-run revdep-rebuild"
- echo " or"
- echo "- use -X or --package-names as first argument (trys to rebuild package, not exact"
- echo " ebuild)"
- echo " or"
- echo "- set ACCEPT_KEYWORDS=\"~<your platform>\" and/or /etc/portage/package.unmask"
- echo " (and remove $LLIST.5_order to be evaluated again)"
- echo " or"
- echo "- modify the above emerge command and run it manually"
- echo " or"
- echo "- compile or unmerge unsatisfied packages manually, remove temporary files and"
- echo " try again (you can edit package/ebuild list first)"
- echo
- echo -e "${GR}To remove temporary files, please run:${NO}"
- echo "rm $LIST*.?_*"
- exit $(cat $LLIST.6_status)
-else
- if $IS_REAL_MERGE ; then
- trap "echo -e \" terminated. Please remove them manually:\nrm $LIST*.?_*\" ; exit 1" \
- SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
- echo -n -e "${GR}Build finished correctly. Removing temporary files...${NO} "
- echo
- rm $LIST.[0-2]_*
- rm $LLIST.[3-9]_*
- echo "You can re-run revdep-rebuild to verify that all libraries and binaries"
- echo "are fixed. If some inconsistency remains, it can be orphaned file, deep"
- echo "dependency, binary package or specially evaluated library."
- else
- echo -e "${GR}Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.${NO}"
- fi
-fi
-exit 0
+++ /dev/null
-#!/bin/sh
-# Copyright 1999-2007 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-
-appname=${0##*/}
-
-# If baselayout is broken, define our own functions
-[ -r /etc/init.d/functions.sh ] && . /etc/init.d/functions.sh
-if ! type eend >/dev/null 2>&1 || ! eend 0 >/dev/null 2>&1; then
- einfo() { echo " * $*"; }
- eerror() { echo " * $*" >&2; return 1; }
- eindent() { :; }
- eoutdent() { :; }
-fi
-
-# No temporary files used, so nothing to clean up :)
-trap "export RC_EINDENT=; echo; eerror 'Caught interrupt'; exit 1" \
- SIGINT SIGQUIT
-
-print_usage() {
- cat << EOF
-Usage: ${appname} [OPTIONS] [--] [EMERGE_OPTIONS]
-
-Broken reverse dependency rebuilder.
-
- -h, --help Print this usage
- -e, --exact Emerge based on exact package version
- -C, --nocolor Turn off colored output
- -L, --library NAME Emerge existing packages that use the library with NAME
- --library=NAME NAME can be a full path to the library or a basic
- regular expression (man grep)
-
-Calls emerge, all other options are used for it (e. g. -p, --pretend).
-
-Report bugs to <http://bugs.gentoo.org>
-EOF
-}
-
-# Have we linked to this library?
-elf_linked() {
- local f=$1
- shift
- while [ -n "$1" ]; do
- ldd "${f}" 2>/dev/null | grep -q "=> $1 " && return 0
- shift
- done
- return 1
-}
-
-# Work out of we really need this library or not
-elf_needed() {
- local f=$1
- shift
- while [ -n "$1" ]; do
- objdump -p "${f}" 2>/dev/null | \
- grep -vF "${ld_mask:=$'\a'}" | \
- grep -q "^ NEEDED ${1##*/}" && return 0
- shift
- done
- return 1
-}
-
-elf_broken() {
- local lib=
-
- for lib in $(ldd "$1" 2>/dev/null | \
- sed -n -e 's/[[:space:]]*\(.*\) => not found.*/\1/p'); do
- if elf_needed "$1" "${lib}"; then
- echo "(missing ${lib})"
- return 0
- fi
- done
- return 1
-}
-
-# Check that all direct files exist in .la files
-la_broken() {
- local x=
- for x in $(sed -n -e "s/^dependency_libs=\'\(.*\)'\$/\1/p" "$1"); do
- case "${x}" in
- /*)
- if [ ! -e "${x}" ]; then
- echo "(missing ${x})"
- return 0
- fi
- ;;
- esac
- done
-
- return 1
-}
-
-# Return a $PATH style variable based on ld.so.conf
-read_so_conf() {
- local line=
- while read line; do
- case "${line}" in
- "#"*) ;;
- *) printf ":%s" "${line}";;
- esac
- done < /etc/ld.so.conf
-}
-
-# Check to see if we have already scanned a dir or not
-scanned() {
- local dir=$1 IFS=:
- set -- ${scanned}
-
- while [ -n "$1" ]; do
- [ "$1" = "$dir" ] && return 0
- shift
- done
-
- scanned="${scanned}${scanned:+:}${dir}"
- return 1
-}
-
-# Hit the portage vdb to work out our ebuilds
-# If everything is 100% then this happens in one very fast pass
-# Otherwise we have to take the slow approach to inform the user which files
-# are orphans
-get_exact_ebuilds() {
- local regex= ebuilds= x= IFS=:
- set -- $@
- IFS=" "
-
- # Hit the vdb in one go - this is fast!
- regex=$(printf "%s|" "$@")
- regex=${regex%*|}
- find /var/db/pkg -name CONTENTS | \
- xargs egrep "^obj (${regex}) " | \
- sed -e 's,/var/db/pkg/\(.*\/.*\)/CONTENTS:.*,=\1,g' | \
- tr '\n' ' '
-}
-
-# Get our args
-libs=
-exact=false
-order=true
-while [ -n "$1" ]; do
- case "$1" in
- --*=*)
- arg1=${1%%=*}
- arg2=${1#*=}
- shift
- set -- ${arg1} ${arg2} $@
- continue
- ;;
- -h|--help) print_usage; exit 0;;
- -L|--library|--soname|--soname-regexp)
- if [ -z "$2" ]; then
- eerror "Missing expected argument to $1"
- exit 1
- fi
- libs="${libs}${libs:+ }$2"
- shift
- ;;
- -e|--exact) exact=true;;
- -X|--package-names) ;; #compat
- --) shift; emerge_opts="$@"; break;;
- *) eerror "$0: unknown option $1"; exit 1;;
- esac
- shift
-done
-
-einfo "Configuring search environment for ${appname}"
-# OK, this truely sucks. Paths can have spaces in, but our config format
-# is space separated?
-sdirs=$(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)
-sdirs_mask=$(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)
-ld_mask=$(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)
-
-if [ -d /etc/revdep-rebuild ]; then
- for x in /etc/revdep-rebuild/*; do
- sdirs="${sdirs}${sdirs:+ }$(unset SEARCH_DIRS; . "${x}"; echo "${SEARCH_DIRS}")"
- sdirs_mask="${sdirs_mask}${sdirs_mask:+ }$(unset SEARCH_DIRS_MASK; . "${x}" ; echo "${SEARCH_DIRS_MASK}")"
- ld_mask="${ld_mask}${ld_mask:+ }$(unset LD_LIBRARY_MASK; . "${x}"; echo "${LD_LIBRARY_MASK}")"
- done
-else
- sdirs="${sdirs}${sdirs:+ }/bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
- sdirs_mask="${sdirs_mask}${sdirs_mask:+ }/opt/OpenOffice /usr/lib/openoffice"
- ld_mask="${ld_mask}${ld_mask:+ }libodbcinst.so libodbc.so libjava.so libjvm.so"
-fi
-
-sdirs=$(find ${sdirs} -type d)
-
-einfo "Starting scan"
-eindent
-# Mark our masked dirs already scanned
-scanned=
-for dir in ${sdirs_mask}; do
- scanned "${dir}"
-done
-
-# Now scan our dirs
-for dir in ${sdirs}; do
- scanned "${dir}" && continue
-
- einfo "in ${dir}"
- eindent
- for x in "${dir}"/*; do
- [ -d "${x}" ] && continue
- [ -L "${x}" ] && continue
-
- scan=true
- process=false
- reason=
- case "${x}" in
- *.so|*.so.*) process=true;;
- *.la)
- scan=false
- if [ -z "${libs}" ]; then
- reason=$(la_broken "${x}")
- [ $? = 0 ] && process=true
- fi
- ;;
- esac
- [ -x "${x}" ] && ${scan} && process=true
- ${process} || continue
-
- if ${scan}; then
- process=false
- if [ -n "${libs}" ]; then
- for lib in ${libs}; do
- if [ "${lib#/}" != "${lib}" ]; then
- # If lib starts with / then check if the exact
- # lib is linked
- elf_linked "${x}" "${lib}" || continue
- fi
- if elf_needed "${x}" ${lib}; then
- process=true
- break
- fi
- done
- else
- reason=$(elf_broken "${x}")
- [ $? = 0 ] && process=true
- fi
- fi
-
- ${process} || continue
- einfo "found ${x} ${reason}"
- files="${files}${files:+:}${x}"
- done
- eoutdent
-done
-eoutdent
-
-if [ -z "${files}" ]; then
- if [ -z "${libs}" ]; then
- einfo "Nothing found that needs rebuilding"
- else
- einfo "No dynamic binaries found with these libraries"
- fi
- exit 0
-fi
-
-einfo "Assigning files to packages"
-eindent
-ebuilds=$(get_exact_ebuilds "${files}")
-
-if [ -z "${ebuilds}" ]; then
- eerror "No packages own these files"
- exit 1
-fi
-
-# Work out the best visible package for the slot
-if ! ${exact}; then
- root=$(portageq envvar ROOT)
- root=${root:-/}
-
- set -- ${ebuilds}
- ebuilds=
- for x in "$@"; do
- x=${x#=*}
- pkg=${x%-r[0-9]*}
- pkg=${pkg%-*}
- slot=$(cat "/var/db/pkg/${x}/SLOT")
- ebd=$(portageq best_visible "${root}" "${pkg}:${slot}")
- if [ -z "${ebd}" ]; then
- eerror "Cannot find an ebuild visible for ${x}"
- else
- ebuilds="${ebuilds}${ebuilds:+ }=${ebd}"
- fi
- done
-fi
-eoutdent
-
-# Work out the build order
-if ${order}; then
- einfo "Ordering packages"
- order="$(EMERGE_DEFAULT_OPTS="" \
- emerge --nospinner --pretend --deep --quiet ${ebuilds})"
- if [ $? = 0 ]; then
- ebuilds=$(echo "${order}" | \
- sed -e 's:^\[.*\] \([^ ]*\)[ ].*$:=\1:' | \
- grep -F "$(printf "%s\n" ${ebuilds})" | \
- tr '\n' ' ')
- else
- eerror "Unable to order packages!"
- fi
-fi
-
-if [ -z "${ebuilds}" ]; then
- eerror "Don't know how to find which package owns what file :/"
- exit 1
-fi
-
-echo
-einfo "About to execute"
-echo "emerge --oneshot ${emerge_opts} ${ebuilds}"
-echo
-
-i=5
-printf "in"
-while [ ${i} -gt 0 ]; do
- printf " ${i}"
- sleep 1
- i=$((${i} - 1))
-done
-printf "\n\n"
-
-EMERGE_DEFAULT_OPTS="" emerge --oneshot ${emerge_opts} ${ebuilds}
-retval=$?
-
-if [ "${retval}" = 0 ]; then
- einfo "All done"
- exit 0
-fi
-
-eerror "There was an error trying to emerge the broken packages"
-exit "${retval}"
+++ /dev/null
-.TH "revdep\-rebuild" "1" "" "gentoolkit" ""
-.SH "NAME"
-revdep\-rebuild \- Gentoo: Reverse Dependency Rebuilder
-.SH "SYNOPSIS"
-.B revdep\-rebuild
-[OPTIONS] [\-\-] [EMERGE OPTIONS]
-.SH "DESCRIPTION"
-revdep\-rebuild scans libraries and binaries for missing shared library dependencies and attempts to fix them by re\-emerging those broken binaries and shared libraries. It is useful when an upgraded package breaks other software packages that are dependent upon the upgraded package.
-.SH "OPTIONS"
-.TP
-.B \-C | \-\-nocolor
-Turn off colored output. (This option is also passed to portage.)
-.TP
-.B \-e | \-\-exact
-Emerge the most recent version of found packages, without regard to SLOT.
-.TP
-.B \-h | \-\-help
-Print usage.
-.TP
-.B \-i | \-\-ignore
-Delete temporary files from previous runs.
-.TP
-.B \-k | \-\-keep\-temp
-Force revdep\-rebuild not to delete temporary files after it successfully rebuilds packages. This option will NOT prevent revdep\-rebuild from deleting inconsistent or out\-of\-date temporary files.
-.TP
-.B \-\-library NAME | -L NAME
-Search for reverse dependencies for a particular library or group of libraries, rather than every library on the system. Emerge packages that use the named library. NAME can be a full path to a library or basic regular expression. (See regex(7).)
-.TP
-.B \-l | \-\-no\-ld\-path
-Do not set LD_LIBRARY_PATH. \fBNote:\fR Using this option will cause revdep-rebuild to report some false positives.
-.TP
-.B \-o | \-\-no-order
-Do not check the build order against the deep dependency list. This will make revdep-rebuild faster, but it can cause emerge failures. Please try revdep\-rebuild without \-o before reporting any bugs.
-.TP
-.B \-p | \-\-pretend
-Do a dry-run. Do not delete temporary files. (\-k \-p is redundant, but harmless.) \-\-pretend is assumed when not running revdep\-rebuild as root.
-.TP
-.B \-P | \-\-no\-progress
-Turn off the progress meter
-.TP
-.B \-q | \-\-quiet
-Print less output and disable the progress meter. (This option is also passed to portage.)
-.TP
-.B \-u UTIL | \-\-no-util UTIL
-Do not use features provided by UTIL.
-UTIL can be one of portage-utils or pkgcore, or it can be a \fBquoted\fR space-delimited list.
-.TP
-.B \-v | \-\-verbose
-More output. (Prints the revdep\-rebuild search environment.)
-.TP
-.B All other options (including unrecognized ones) are passed to the emerge command. Single\-letter options may not be combined, so for example, \-pv is not valid. Please use \-p \-v.
-.SH "CONFIGURATION"
-revdep\-rebuild no longer uses hardcoded paths. To change the default behavior the following variables can be changed by the user.
-
-LD_LIBRARY_MASK \- Mask of specially evaluated libraries
-.LP
-SEARCH_DIRS \- List of directories to search for executables and libraries
-.LP
-SEARCH_DIRS_MASK \- List of directories to not search
-
-You can prepend to these variables by setting the variable in your environment prior to execution, by placing an entry in /etc/make.conf, or by placing a file in /etc/revdep\-rebuild containing the appropriate variables.
-
-The variables are read and set in the following order:
-
-environment settings \- one time changes by user
-.br
-/etc/make.conf \- persistent changes by user
-.br
-/etc/revdep\-rebuild/* \- persistent changes by ebuild authors
-
-While a user can edit and modify the files in the /etc/revdep\-rebuild directory, please be aware that the /etc/revdep\-rebuild directory is not under configuration protection and files can be removed and/or overwritten by an ebuild. To change this add /etc/revdep\-rebuild to the CONFIG_PROTECT variable in /etc/make.conf.
-
-An entry of "\-*" means to clear the variable from that point forward.
-Example: SEARCH_DIRS="/usr/bin \-*" will set SEARCH_DIRS to contain only /usr/bin
-
-revdep\-rebuild honors the NOCOLOR and PORTAGE_NICENESS variables from /etc/make.conf
-.SH "EXAMPLES"
-It is recommended that when running revdep\-rebuild that the following command be used initially:
-.br
-\fBrevdep\-rebuild \-\-ignore \-\-pretend\fR
-
-To search the entire system, while excluding /mnt and /home:
-.br
-\fBenv SEARCH_DIRS="/ \-*" SEARCH_DIRS_MASK="/mnt /home" revdep\-rebuild\fR
-
-To rebuild packages that depend on libkdecore.so.4 from KDE 3.3:
-.br
-\fBrevdep\-rebuild \-\-library /usr/kde/3.3/lib/libkdecore.so.4\fR
-
-To rebuild packages that depend upon libImlib.so and libImlib2.so:
-.br
-\fBrevdep\-rebuild \-\-library libImlib[2]*.so.*\fR
-
-.SH "FILES"
-.P
-revdep\-rebuild keeps several pseudo-temporary files in /var/cache/revdep\-rebuild/. Deleting these files can improve accuracy at the cost of speed:
-.TP 15
-.I 0_env.rr
-Contains environment variables
-.TP
-.I 1_files.rr
-Contains a list of files to search
-.TP
-.I 2_ldpath.rr
-Contains the LDPATH
-.TP
-.I 3_broken.rr
-Contains the list of broken files
-.TP
-.I 3_errors.rr
-Contains the ldd error output
-.TP
-.I 4_raw.rr
-Contains the raw list of packages
-.TP
-.I 4_owners.rr
-Contains the file owners
-.TP
-.I 4_pkgs.rr
-Contains the unsorted bare package names
-.TP
-.I 4_ebuilds.rr
-Contains the unsorted atoms
-.TP
-.I 5_order.rr
-Contains the sorted atoms
-.TP
-.I 6_status.rr
-Contains the ldd error output
-
-.SH "EXIT STATUS"
-revdep\-rebuild returns a zero exit status if it \fBand emerge\fR succeeds, and a nonzero exit status otherwise.
-.SH "BUGS"
-.LP
-Report bugs to <http://bugs.gentoo.org>. Please do not report emerge failures caused by \-o or \-e. Please include your .revdep\-rebuild* files, your emerge \-\-info, and patches. ;)
-
-.SH "SEE ALSO"
-emerge(1), portage(5), regex(7)