summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorPaul Varner <fuzzyray@gentoo.org>2010-12-28 18:30:14 -0600
committerPaul Varner <fuzzyray@gentoo.org>2010-12-28 18:30:14 -0600
commit879cf3ce1f3041854c9dc886b59ac7e136ae9b9b (patch)
tree7faa716b853d76a4c430d7b43024d82222d329e7 /bin
parent258a81471b4106f12bafee2e5c0a5458e2db2280 (diff)
parenta9ac560d5f3e056d14146d5033e5637bbc9f68ef (diff)
downloadgentoolkit-879cf3ce1f3041854c9dc886b59ac7e136ae9b9b.tar.gz
Merge branch 'gentoolkit' into euse
Conflicts: bin/euse
Diffstat (limited to 'bin')
-rwxr-xr-xbin/analyse48
-rwxr-xr-xbin/eclean849
-rwxr-xr-xbin/epkginfo284
-rwxr-xr-xbin/equery28
-rw-r--r--bin/eshowkw9
-rwxr-xr-xbin/euse137
-rwxr-xr-xbin/glsa-check126
-rwxr-xr-xbin/revdep-rebuild192
8 files changed, 452 insertions, 1221 deletions
diff --git a/bin/analyse b/bin/analyse
new file mode 100755
index 0000000..a90410b
--- /dev/null
+++ b/bin/analyse
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+#
+# Copyright 2010 Brian Dolbec <brian.dolbec@gmail.com>
+# Copyright 2002-2010 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2 or later
+#
+# $Header$
+
+"""'analyse' is a flexible utility for Gentoo linux which can display various
+information about installed packages, such as the USE flags used and the
+packages that use them. It can also be used to help rebuild /etc/portage/package.*
+files in the event of corruption, and possibly more.
+"""
+
+from __future__ import print_function
+
+import sys
+# This block ensures that ^C interrupts are handled quietly.
+try:
+ import signal
+
+ def exithandler(signum,frame):
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ print()
+ sys.exit(1)
+
+ signal.signal(signal.SIGINT, exithandler)
+ signal.signal(signal.SIGTERM, exithandler)
+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+
+except KeyboardInterrupt:
+ print()
+ sys.exit(1)
+
+from gentoolkit import analyse, errors
+
+try:
+ analyse.main()
+except errors.GentoolkitException as err:
+ if '--debug' in sys.argv:
+ raise
+ else:
+ from gentoolkit import pprinter as pp
+ sys.stderr.write(pp.error(str(err)))
+ print()
+ print("Add '--debug' to global options for traceback.")
+ sys.exit(1)
diff --git a/bin/eclean b/bin/eclean
index 9953fa7..e17f9f0 100755
--- a/bin/eclean
+++ b/bin/eclean
@@ -1,834 +1,49 @@
#!/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
+"""Copyright 2003-2010 Gentoo Foundation
+Distributed under the terms of the GNU General Public License v2
+"""
+
+from __future__ import print_function
+
-###############################################################################
# Meta:
-__author__ = "Thomas de Grenier de Latour (tgl)"
-__email__ = "degrenier@easyconnect.fr"
-__version__ = open('/usr/share/gentoolkit/VERSION').read().strip()
+__author__ = "Thomas de Grenier de Latour (tgl), " + \
+ "modular re-write by: Brian Dolbec (dol-sen)"
+__email__ = "degrenier@easyconnect.fr, " + \
+ "brian.dolbec@gmail.com"
+__version__ = "svn"
__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
-
-import portage
-from portage.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 (%s) - %s" \
- % (__productname__, __version__, __description__)
- print
- print "Author: %s <%s>" % (__author__,__email__)
- print "Copyright 2003-2009 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
+# This block ensures that ^C interrupts are handled quietly.
+try:
+ import signal
-###############################################################################
-# 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
-
+ def exithandler(signum,frame):
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ print()
+ sys.exit(1)
-###############################################################################
-# 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'])
+ signal.signal(signal.SIGINT, exithandler)
+ signal.signal(signal.SIGTERM, exithandler)
+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+except KeyboardInterrupt:
+ print()
+ sys.exit(1)
-###############################################################################
-# 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)
+from gentoolkit.eclean.cli import main
-###############################################################################
-# actually call main() if launched as a script
-if __name__ == "__main__":
- try: main()
- except KeyboardInterrupt:
- print "Aborted."
- sys.exit(130)
- sys.exit(0)
+try:
+ main()
+except KeyboardInterrupt:
+ print("Aborted.")
+ sys.exit(130)
+sys.exit(0)
diff --git a/bin/epkginfo b/bin/epkginfo
index 747527a..953b4a4 100755
--- a/bin/epkginfo
+++ b/bin/epkginfo
@@ -1,244 +1,54 @@
#!/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)
+#
+# Copyright 2009 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2 or later
+#
+# $Header$
-# Gentoo metadata xml and arch keyword checking tool.
+"""Shortcut to equery meta"""
-import os
-import sys
-import re
-from stat import *
-from xml.sax import saxutils, make_parser, handler
-from xml.sax.handler import feature_namespaces
-
-import portage
-from portage.output import *
-
-version = open('/usr/share/gentoolkit/VERSION').read().strip()
-
-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)))
-
- slot_list = []
-
- for pkg in ebuildlist:
- portdb = portage.portdbapi(portdir)
- aux = portdb.aux_get(workdir.rsplit("/")[-2] + "/" + pkg, ['SLOT', 'KEYWORDS'])
-
- slot = aux[0]
- keywords = keywords = re.split(' ',aux[1])
-
- if not slot in slot_list:
- slot_list.append(slot)
-
- for arch in keywords:
- if arch in archdict:
- archdict[arch].append((pkg, slot))
- else:
- archdict[arch] = [ (pkg, slot) ]
-
- archlist = archdict.keys();
- archlist.sort()
-
- slot_list.sort()
-
- for slot in slot_list:
- visible_stable = {}
- visible_unstable = {}
-
- for arch in archlist:
- visible_stable[arch] = None
- visible_unstable[arch] = None
-
- for pkg in ebuildlist:
- for arch in archlist:
- if (arch and (pkg, slot) in archdict[arch]):
- if arch[0] == "-":
- pass
- elif "~" == arch[0]:
- visible_unstable[arch] = pkg
- else:
- visible_unstable[arch] = None
- visible_stable[arch] = pkg
-
- for pkg in ebuildlist:
- found = False
- for arch in archlist:
- if (pkg, slot) in archdict[arch]:
- found = True
-
- if not found:
- continue
-
- if not pkg == ebuildlist[0]:
- print ""
-
- print darkgreen("Keywords: ") + pkg + "[" + slot + "]:",
-
- for arch in archlist:
- if (arch and (pkg, slot) in archdict[arch]):
- if arch[0] == "-":
- print red(arch),
- elif "~" == arch[0]:
- if visible_unstable[arch] == pkg:
- print blue(arch),
- else:
- if visible_stable[arch] == pkg:
- print green(arch),
-
-
-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.append(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 herd 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
+from __future__ import print_function
- parser = make_parser()
- handler = Metadata_XML()
- handler._maintainers = []
- parser.setContentHandler(handler)
- parser.parse( metadata_file )
-
- if handler._herd:
- herds = ", ".join(handler._herd)
- print darkgreen("Herd: ") + herds
- else:
- print darkgreen("Herd: ") + red("Error (No Herd)")
- return 1
-
-
- if handler._maintainers:
- print darkgreen("Maintainer: ") + ", ".join(handler._maintainers)
- else:
- print darkgreen("Maintainer: ") + "none"
-
- 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"), "(%s)" % version
- print
- 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])
+__authors__ = (
+ 'Douglas Anderson <douglasjanderson@gmail.com>: equery meta',
+ 'Ned Ludd <solar@gentoo.org>: first full implimentation'
+ 'Eldad Zack <eldad@gentoo.org>: earch',
+ 'Eric Olinger <EvvL AT RustedHalo DOT net>: metadata'
+ )
+import sys
-def grab_changelog_devs(catpkg):
+from gentoolkit import equery, errors
+from gentoolkit.equery import mod_usage
+from gentoolkit.equery.meta import main, print_help
+from portage.exception import AmbiguousPackageName
+
+def print_epkginfo_help():
+ print(mod_usage(mod_name="epkginfo"))
+ print()
+ print_help(with_usage=False)
+
+equery.initialize_configuration()
+args = sys.argv[1:]
+if not args or set(('-h', '--help')).intersection(args):
+ print_epkginfo_help()
+else:
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 ""
- else:
- print "!!! No package '%s'" % pkg
- except:
- print red("Error: "+pkg+"\n")
-
-
-if __name__ == '__main__':
- main()
+ main(args)
+ except AmbiguousPackageName as e:
+ pkgs = e.args[0]
+ for candidate in pkgs:
+ print(candidate)
+
+ from gentoolkit import pprinter as pp
+ from os.path import basename # To get the short name
+
+ print(file=sys.stderr)
+ print(pp.error("The short ebuild name '%s' is ambiguous. Please specify" % basename(pkgs[0])),
+ file=sys.stderr, end="")
+ pp.die(1, "one of the above fully-qualified ebuild names instead.")
+ except errors.GentoolkitException as err:
+ from gentoolkit import pprinter as pp
+ pp.die(1, str(err))
+
+# vim: set ts=4 sw=4 tw=79:
diff --git a/bin/equery b/bin/equery
index bac8a3a..54c3a07 100755
--- a/bin/equery
+++ b/bin/equery
@@ -2,12 +2,17 @@
#
# Copyright 2002-2009 Gentoo Technologies, Inc.
# Distributed under the terms of the GNU General Public License v2 or later
+#
+# $Header$
-"""equery is a flexible utility for Gentoo linux which can display various
-information about packages, such as the files they own, their USE flags,
+"""equery is a flexible utility for Gentoo linux which can display various
+information about packages, such as the files they own, their USE flags,
the MD5 sum of each file owned by a given package, and many other things.
"""
+from __future__ import print_function
+
+import os
import sys
# This block ensures that ^C interrupts are handled quietly.
try:
@@ -16,7 +21,7 @@ try:
def exithandler(signum,frame):
signal.signal(signal.SIGINT, signal.SIG_IGN)
signal.signal(signal.SIGTERM, signal.SIG_IGN)
- print
+ print()
sys.exit(1)
signal.signal(signal.SIGINT, exithandler)
@@ -24,9 +29,20 @@ try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except KeyboardInterrupt:
- print
+ print()
sys.exit(1)
-from gentoolkit import equery
+from gentoolkit import equery, errors
-equery.main()
+try:
+ equery.main()
+except errors.GentoolkitException as err:
+ if '--debug' in sys.argv or bool(os.getenv('DEBUG', False)):
+ raise
+ else:
+ from gentoolkit import pprinter as pp
+ sys.stderr.write(pp.error(str(err)))
+ if err.is_serious:
+ print()
+ print("Add '--debug' to global options for traceback.")
+ sys.exit(1)
diff --git a/bin/eshowkw b/bin/eshowkw
new file mode 100644
index 0000000..e987cce
--- /dev/null
+++ b/bin/eshowkw
@@ -0,0 +1,9 @@
+#!/usr/bin/python
+# vim:fileencoding=utf-8
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+from gentoolkit.eshowkw import main as emain
+
+sys.exit(emain(sys.argv[1:])) \ No newline at end of file
diff --git a/bin/euse b/bin/euse
index fc9d60f..c54135f 100755
--- a/bin/euse
+++ b/bin/euse
@@ -7,13 +7,53 @@
# Licensed under the GPL v2
PROGRAM_NAME=euse
-PROGRAM_VERSION=$(cat /usr/share/gentoolkit/VERSION)
+VERSION="svn"
-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
-PACKAGE_USE_PATH=/etc/portage/package.use
+EPREFIX=${EPREFIX:-$(portageq envvar EPREFIX)}
+ETC="${EPREFIX}/etc"
+USR_SHARE_PORTAGE="${EPREFIX}/usr/share/portage"
+
+# define error functions so they can be used immediately
+fatal() {
+ echo -e "ERROR: ${*}"
+ set +f
+ exit 1
+}
+
+error() {
+ echo -e "ERROR: ${*}"
+}
+
+warn() {
+ echo -e "WARNING: ${*}"
+}
+
+# /etc/make.conf can now exist in /etc/portage/make.conf, prefer it over /etc/make.conf for changes
+if [ -e "${ETC}/portage/make.conf" ]; then
+ MAKE_CONF_PATH="${ETC}/portage/make.conf"
+elif [ -e "${ETC}/make.conf" ]; then
+ MAKE_CONF_PATH="${ETC}/make.conf"
+else
+ fatal "make.conf does not exist"
+fi
+MAKE_CONF_BACKUP_PATH="${MAKE_CONF_PATH}.euse_backup"
+
+# /etc/make.globals has been moved to /usr/share/portage/config/make.globals
+if [ -e "${USR_SHARE_PORTAGE}/config/make.globals" ]; then
+ MAKE_GLOBALS_PATH="${USR_SHARE_PORTAGE}/config/make.globals"
+else
+ MAKE_GLOBALS_PATH="${ETC}/make.globals"
+fi
+
+# /etc/make.profile or /etc/portage/make.profile, if /etc/make.profile exists, it will be used
+if [ -e "${ETC}/make.profile" ]; then
+ MAKE_PROFILE_PATH="${ETC}/make.profile"
+elif [ -e "${ETC}/portage/make.profile" ]; then
+ MAKE_PROFILE_PATH="${ETC}/portage/make.profile"
+else
+ fatal "make.profile does not exist"
+fi
+PACKAGE_USE_PATH=${ETC}/portage/package.use
[ -z "${MODE}" ] && MODE="showhelp" # available operation modes: showhelp, showversion, showdesc, showflags, modify
@@ -51,20 +91,6 @@ parse_arguments() {
done
}
-fatal() {
- echo -e "${*}" | sed -e "s/^/ERROR: /g"
- set +f
- exit 1
-}
-
-error() {
- echo -e "${*}" | sed -e "s/^/ERROR: /g"
-}
-
-warn() {
- echo -e "${*}" | sed -e "s/^/WARNING: /g"
-}
-
get_real_path() {
set -P
cd "$1"
@@ -79,16 +105,22 @@ check_sanity() {
# file permission tests
local descdir
local make_defaults
-
+ local make_conf
+
+ [[ ! -d "${MAKE_PROFILE_PATH}" || ! -r "${MAKE_PROFILE_PATH}" ]] && error "${MAKE_PROFILE_PATH} is not readable"
+ #
+ for make_conf in $(get_all_make_conf); do
+ [ ! -r "${make_conf}" ] && fatal "${make_conf} is not readable"
+ done
+
descdir="$(get_portdir)/profiles"
- [ ! -r "${MAKE_CONF_PATH}" ] && fatal "${MAKE_CONF_PATH} is not readable"
[ ! -r "${MAKE_GLOBALS_PATH}" ] && fatal "${MAKE_GLOBALS_PATH} is not readable"
- [ ! -h "${MAKE_PROFILE_PATH}" ] && fatal "${MAKE_PROFILE_PATH} is not a symlink"
[ -z "$(get_portdir)" ] && fatal "\$PORTDIR couldn't be determined"
[ ! -d "${descdir}" ] && fatal "${descdir} does not exist or is not a directory"
[ ! -r "${descdir}/use.desc" ] && fatal "${descdir}/use.desc is not readable"
[ ! -r "${descdir}/use.local.desc" ] && fatal "${descdir}/use.local.desc is not readable"
+
for make_defaults in $(get_all_make_defaults); do
[ ! -r "$make_defaults" ] && fatal "$_make_defaults is not readable"
done
@@ -98,7 +130,7 @@ check_sanity() {
showhelp() {
cat << HELP
-${PROGRAM_NAME} (${PROGRAM_VERSION}-JJ0)
+${PROGRAM_NAME} (${VERSION})
Syntax: ${PROGRAM_NAME} <option> [suboptions] [useflaglist]
@@ -128,7 +160,7 @@ HELP
showversion() {
cat << VER
-${PROGRAM_NAME} (${PROGRAM_VERSION})
+${PROGRAM_NAME} (${VERSION})
Written by Marius Mauch
Copyright (C) 2004-2009 Gentoo Foundation, Inc.
@@ -238,8 +270,10 @@ get_useflags() {
ACTIVE_FLAGS[0]="$(reduce_incrementals ${USE})"
USE=""
- source "${MAKE_CONF_PATH}"
- ACTIVE_FLAGS[1]="$(reduce_incrementals ${USE})"
+ for x in $(get_all_make_conf); do
+ source "${x}"
+ ACTIVE_FLAGS[1]="$(reduce_incrementals ${ACTIVE_FLAGS[1]} ${USE})"
+ done
USE=""
for x in $(get_all_make_defaults); do
source "${x}"
@@ -275,7 +309,7 @@ get_portageuseflags() {
# 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
# Bug 181309, emerge may complain if EMERGE_DEFAULT_OPTS="--ask" is set
- ACTIVE_FLAGS[9]="$(emerge --ignore-default-opts --info | grep 'USE=' | cut -b 5- | sed -e 's:"::g')" #'
+ ACTIVE_FLAGS[9]="$(portageq envvar USE)" #'
_PORTAGE_USE_FLAGS_CALCULATED=1
} # }}}
@@ -379,6 +413,13 @@ get_useflaglist_ebuild() {
done
} # }}}
+# get all make.conf files that exist on the system
+get_all_make_conf() {
+ # At least one of the files exists or we would not have made it this far
+ for x in ${ETC}/make.conf ${ETC}/portage/make.conf; do
+ [ -e "${x}" ] && echo "${x}"
+ done
+}
# Function: traverse_profile {{{
# General method of collecting the contents of a profile
# component by traversing through the cascading profile
@@ -631,7 +672,9 @@ get_portdir() {
for x in $(get_all_make_defaults); do
source "${x}"
done
- source "${MAKE_CONF_PATH}"
+ for x in $(get_all_make_conf); do
+ source "${x}"
+ done
USE="${use_backup}"
fi
echo "${PORTDIR}"
@@ -687,7 +730,7 @@ showdesc() {
set -f
args="${*:-*}"
-
+
if [ -z "${SCOPE}" ]; then
SCOPE="global" showdesc ${args}
echo
@@ -704,7 +747,7 @@ showdesc() {
if [ "${args}" == "*" ]; then
args="${useflags[*]}"
fi
-
+
set ${args}
foundone=0
@@ -718,7 +761,7 @@ showdesc() {
foundone=1
fi
fi
- # local flags are a bit more complicated as there can be multiple
+ # 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 array_contains "${useflags[*]}" "$1"; then
@@ -788,13 +831,13 @@ showinstdesc() {
descdir="$(get_portdir)/profiles"
echo "************************************************************"
-
+
if [ "${args}" = "*" ]; then
args="$(get_useflaglist | sort -u)"
fi
-
+
set "${args[@]}"
-
+
while [ -n "${1}" ]; do
case "${SCOPE}" in
"global")
@@ -834,7 +877,7 @@ showinstdesc() {
esac
shift
done
-
+
if [ ${foundone} -lt 1 ]; then
echo "no matching entries found"
fi
@@ -847,13 +890,13 @@ showflags() {
local args
get_useflags
-
+
args="${*:-*}"
-
+
if [ "${args}" == "*" ]; then
args="$(get_useflaglist | sort -u)"
fi
-
+
set ${args}
get_portageuseflags
@@ -1127,11 +1170,11 @@ modify() {
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
@@ -1176,13 +1219,13 @@ modify() {
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
@@ -1195,9 +1238,9 @@ modify() {
# 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
+ # 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
@@ -1226,7 +1269,7 @@ modify() {
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}"
} # }}}
diff --git a/bin/glsa-check b/bin/glsa-check
index c24ef23..a8c0188 100755
--- a/bin/glsa-check
+++ b/bin/glsa-check
@@ -3,35 +3,29 @@
# $Header: $
# This program is licensed under the GPL, version 2
-import os
import sys
+import os
import codecs
-try:
- import portage
-except ImportError:
- sys.path.insert(0, "/usr/lib/portage/pym")
- import portage
+from functools import reduce
-try:
- from portage.output import *
-except ImportError:
- from output import *
+import portage
+from portage.output import *
from getopt import getopt, GetoptError
__program__ = "glsa-check"
__author__ = "Marius Mauch <genone@gentoo.org>"
-__version__ = open("/usr/share/gentoolkit/VERSION").read().strip()
+__version__ = "svn"
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)"],
+["-l", "--list", "list the GLSAs"],
+["-d", "--dump", "--print", "show all information about the GLSAs"],
+["-t", "--test", "test if this system is affected by the GLSAs"],
+["-p", "--pretend", "show the necessary steps to apply the GLSAs"],
+["-f", "--fix", "try to auto-apply the GLSAs (experimental)"],
["-i", "--inject", "inject the given GLSA into the glsa_injected file"],
["-n", "--nocolor", "disable colors (option)"],
-["-e", "--emergelike", "do not use a least-change algorithm (option)"],
+["-e", "--emergelike", "upgrade to latest version (not least-change, option)"],
["-h", "--help", "show this help message"],
["-V", "--version", "some information about this tool"],
["-v", "--verbose", "print more information (option)"],
@@ -55,12 +49,12 @@ 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])])
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:
@@ -72,7 +66,7 @@ try:
if option in args:
list_cve = True
args.remove(option)
-
+
least_change = True
for option in ["--emergelike", "-e"]:
if option in args:
@@ -100,7 +94,7 @@ try:
if args in [o for o in m[:-1]]:
mode = m[1][2:]
-except GetoptError, e:
+except GetoptError as e:
sys.stderr.write("unknown option given: ")
sys.stderr.write(str(e)+"\n")
mode = "HELP"
@@ -112,8 +106,8 @@ if len(params) <= 0 and mode in ["fix", "test", "pretend", "dump", "inject", "ma
sys.stderr.write("(specify \"all\" as parameter)\n\n")
mode = "HELP"
elif len(params) <= 0 and mode == "list":
- params.append("new")
-
+ params.append("affected")
+
# show help message
if mode == "help" or mode == "HELP":
msg = "Syntax: glsa-check <option> [glsa-list]\n\n"
@@ -123,7 +117,7 @@ if mode == "help" or mode == "HELP":
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"
+ msg += "'all' and 'affected'\n"
if mode == "help":
sys.stdout.write(msg)
sys.exit(0)
@@ -154,8 +148,8 @@ glsaconfig = checkconfig(portage.config(clone=portage.settings))
if quiet:
glsaconfig["EMERGE_OPTS"] += " --quiet"
-vardb = portage.db["/"]["vartree"].dbapi
-portdb = portage.db["/"]["porttree"].dbapi
+vardb = portage.db[portage.root]["vartree"].dbapi
+portdb = portage.db[portage.root]["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"])):
@@ -173,18 +167,19 @@ todolist = [e for e in completelist if e not in checklist]
glsalist = []
if "new" in params:
- glsalist = todolist
params.remove("new")
-
+ sys.stderr.write("Warning: The 'new' glsa-list target has been removed, using 'affected'.\n")
+ params.append("affected")
+
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:
+ except (GlsaTypeException, GlsaFormatException) as e:
if verbose:
sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (x, e)))
continue
@@ -201,6 +196,13 @@ for p in params[:]:
glsalist.extend([g for g in params if g not in glsalist])
def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr, encoding="utf-8"):
+ # Get to the raw streams in py3k before wrapping them with an encoded writer
+ # to avoid writing bytes to a text stream (stdout/stderr are text streams
+ # by default in py3k)
+ if hasattr(fd1, "buffer"):
+ fd1 = fd1.buffer
+ if hasattr(fd2, "buffer"):
+ fd2 = fd2.buffer
fd1 = codecs.getwriter(encoding)(fd1)
fd2 = codecs.getwriter(encoding)(fd2)
if not quiet:
@@ -212,7 +214,7 @@ def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr, encoding="utf-8"):
for myid in myglsalist:
try:
myglsa = Glsa(myid, glsaconfig)
- except (GlsaTypeException, GlsaFormatException), e:
+ except (GlsaTypeException, GlsaFormatException) as e:
if verbose:
fd2.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
continue
@@ -233,7 +235,7 @@ def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr, encoding="utf-8"):
fd1.write(color(myglsa.nr) + " " + color(status) + " " + color(access) + myglsa.title + " (")
if not verbose:
- for pkg in myglsa.packages.keys()[:3]:
+ for pkg in list(myglsa.packages.keys())[:3]:
fd1.write(" " + pkg + " ")
if len(myglsa.packages) > 3:
fd1.write("... ")
@@ -258,17 +260,21 @@ if mode in ["dump", "fix", "inject", "pretend"]:
for myid in glsalist:
try:
myglsa = Glsa(myid, glsaconfig)
- except (GlsaTypeException, GlsaFormatException), e:
+ except (GlsaTypeException, GlsaFormatException) as 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 GLSA "+myid+"\n")
+ if not quiet:
+ sys.stdout.write("Fixing GLSA "+myid+"\n")
if not myglsa.isVulnerable():
- sys.stdout.write(">>> no vulnerable packages installed\n")
+ if not quiet:
+ sys.stdout.write(">>> no vulnerable packages installed\n")
else:
+ if quiet:
+ sys.stdout.write("Fixing GLSA "+myid+"\n")
mergelist = myglsa.getMergeList(least_change=least_change)
if mergelist == []:
sys.stdout.write(">>> cannot fix GLSA, no unaffected packages available\n")
@@ -287,24 +293,36 @@ if mode in ["dump", "fix", "inject", "pretend"]:
exitcode >>= 8
if exitcode:
sys.exit(exitcode)
- if len(mergelist):
- sys.stdout.write("\n")
+ if len(mergelist):
+ sys.stdout.write("\n")
elif mode == "pretend":
- sys.stdout.write("Checking GLSA "+myid+"\n")
+ if not quiet:
+ sys.stdout.write("Checking GLSA "+myid+"\n")
if not myglsa.isVulnerable():
- sys.stdout.write(">>> no vulnerable packages installed\n")
+ if not quiet:
+ sys.stdout.write(">>> no vulnerable packages installed\n")
else:
+ if quiet:
+ sys.stdout.write("Checking GLSA "+myid+"\n")
mergedict = {}
for (vuln, update) in myglsa.getAffectionTable(least_change=least_change):
mergedict.setdefault(update, []).append(vuln)
-
- sys.stdout.write(">>> The following updates will be performed for this GLSA:\n")
- for pkg in mergedict:
- if pkg != "":
- sys.stdout.write(" " + pkg + " (vulnerable: " + ", ".join(mergedict[pkg]) + ")\n")
+
+ # first, extract the atoms that cannot be upgraded (where key == "")
+ no_upgrades = []
if "" in mergedict:
- sys.stdout.write("\n>>> For the following packages, no upgrade path exists:\n")
- sys.stdout.write(" " + ", ".join(mergedict[""]))
+ no_upgrades = mergedict[""]
+ del mergedict[""]
+
+ # see if anything is left that can be upgraded
+ if mergedict:
+ sys.stdout.write(">>> Updates that will be performed:\n")
+ for (upd, vuln) in mergedict.items():
+ sys.stdout.write(" " + green(upd) + " (vulnerable: " + red(", ".join(vuln)) + ")\n")
+
+ if no_upgrades:
+ sys.stdout.write(">>> No upgrade path exists for these packages:\n")
+ sys.stdout.write(" " + red(", ".join(no_upgrades)) + "\n")
elif mode == "inject":
sys.stdout.write("injecting " + myid + "\n")
myglsa.inject()
@@ -316,7 +334,7 @@ if mode == "test":
for myid in glsalist:
try:
myglsa = Glsa(myid, glsaconfig)
- except (GlsaTypeException, GlsaFormatException), e:
+ except (GlsaTypeException, GlsaFormatException) as e:
if verbose:
sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
continue
@@ -338,9 +356,9 @@ if mode == "mail":
import portage.mail as portage_mail
except ImportError:
import portage_mail
-
+
import socket
- from StringIO import StringIO
+ from io import StringIO
try:
from email.mime.text import MIMEText
except ImportError:
@@ -353,7 +371,7 @@ if mode == "mail":
myrecipient = glsaconfig["PORTAGE_ELOG_MAILURI"].split()[0]
else:
myrecipient = "root@localhost"
-
+
if "PORTAGE_ELOG_MAILFROM" in glsaconfig:
myfrom = glsaconfig["PORTAGE_ELOG_MAILFROM"]
else:
@@ -373,7 +391,7 @@ if mode == "mail":
for myid in glsalist:
try:
myglsa = Glsa(myid, glsaconfig)
- except (GlsaTypeException, GlsaFormatException), e:
+ except (GlsaTypeException, GlsaFormatException) as e:
if verbose:
sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
continue
@@ -382,12 +400,12 @@ if mode == "mail":
myattachments.append(MIMEText(str(myfd.getvalue()), _charset="utf8"))
myfd.close()
- if glsalist or not quiet:
+ if glsalist or not quiet:
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)
diff --git a/bin/revdep-rebuild b/bin/revdep-rebuild
index b44dadc..e034124 100755
--- a/bin/revdep-rebuild
+++ b/bin/revdep-rebuild
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright 1999-2008 Gentoo Foundation
+# Copyright 1999-2010 Gentoo Foundation
# revdep-rebuild: Reverse dependency rebuilder.
# Original Author: Stanislav Brabec
@@ -18,6 +18,7 @@ unset GREP_OPTIONS
# Readonly variables:
declare -r APP_NAME="${0##*/}" # The name of this application
+declare -r VERSION="svn"
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
@@ -89,11 +90,12 @@ declare WORKING_DIR # Working directory where cache files are kept
main() {
# preliminary setup
+ portage_settings
get_opts "$@"
setup_portage
setup_search_paths_and_masks
get_search_env
- echo
+ [[ $QUIET -ne 1 ]] && echo
# Search for broken binaries
get_files
@@ -163,6 +165,11 @@ EW
print_usage() {
cat << EOF
+${APP_NAME}: (${VERSION})
+
+Copyright (C) 2003-2010 Gentoo Foundation, Inc.
+This is free software; see the source for copying conditions.
+
Usage: $APP_NAME [OPTIONS] [--] [EMERGE_OPTIONS]
Broken reverse dependency rebuilder.
@@ -189,6 +196,7 @@ Calls emerge, options after -- are ignored by $APP_NAME
and passed directly to emerge.
Report bugs to <http://bugs.gentoo.org>
+
EOF
}
##
@@ -233,7 +241,17 @@ clean_var() {
die() {
local status=$1
shift
- eerror "$@"
+
+ # Check if eerror has been loaded.
+ # Its loaded _after_ opt parsing but not before due to RC_NOCOLOR.
+ type eerror &> /dev/null
+
+ if [[ $? -eq 0 ]];
+ then
+ eerror "$@"
+ else
+ echo " * ${@}" >> /dev/stderr
+ fi
exit $status
}
##
@@ -246,19 +264,35 @@ clean_exit() {
builtin cd; rmdir "$WORKING_DIR"
fi
fi
- echo
- einfo "$OK_TEXT... All done. "
+ if [[ $QUIET -ne 1 ]];
+ then
+ echo
+ einfo "$OK_TEXT... All done. "
+ fi
exit 0
}
##
# Get the name of the package that owns a file or list of files given as args.
+# NOTE: depends on app-misc/realpath!
get_file_owner() {
local IFS=$'\n'
- # ${*/%/ } adds a space to the end of each object name to prevent false
+
+ rpath=$(realpath "${*}" 2>/dev/null)
+ # To ensure we always have something in rpath...
+ [[ -z $rpath ]] && rpath=${*}
+
+ # Workaround for bug 280341
+ mlib=$(echo ${*}|sed 's:/lib/:/lib64/:')
+ [[ "${*}" == "${mlib}" ]] && mlib=$(echo ${*}|sed 's:/lib64/:/lib/:')
+
+ # Add 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:'
+ # The same for "${rpath} ".
+ # Don't match an entry with a '-' at the start of the package name. This
+ # prevents us from matching invalid -MERGING entries. (bug #338031)
+ find -L /var/db/pkg -type f -name CONTENTS -print0 |
+ xargs -0 grep -m 1 -Fl -e "${*} " -e "${rpath} " -e "${mlib} " |
+ sed 's:/var/db/pkg/\(.*\)/\([^-].*\)/CONTENTS:\1/\2:'
}
##
# Normalize some EMERGE_OPTIONS
@@ -273,7 +307,6 @@ normalize_emerge_opts() {
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
}
@@ -342,10 +375,10 @@ get_longopts() {
--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
+ --pretend) EMERGE_OPTIONS+=("--pretend")
+ PRETEND=1;;
+ --quiet) progress() { :; }
+ QUIET=1
EMERGE_OPTIONS+=($1);;
--verbose) VERBOSE=1
EMERGE_OPTIONS+=("--verbose");;
@@ -381,10 +414,10 @@ get_shortopts() {
l) unset FULL_LD_PATH;;
o) unset ORDER_PKGS;;
P) progress() { :; };;
- p) EMERGE_OPTIONS+=("--pretend");;
- q) echo_v() { :; }
- progress() { :; }
- quiet=1
+ p) EMERGE_OPTIONS+=("--pretend")
+ PRETEND=1;;
+ q) progress() { :; }
+ QUIET=1
EMERGE_OPTIONS+=("--quiet");;
v) VERBOSE=1
EMERGE_OPTIONS+=("--verbose");;
@@ -520,7 +553,7 @@ verify_tmpdir() {
get_search_env() {
local new_env
local old_env
- local uid=$(python -c 'import os; import pwd; print pwd.getpwuid(os.getuid())[0]')
+ 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}"
@@ -606,16 +639,19 @@ get_search_env() {
[[ $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."
+ if [[ $QUIET -ne 1 ]];
+ then
+ echo
+ einfo "Checking reverse dependencies"
+ einfo "Packages containing binaries and libraries $HEAD_TEXT"
+ einfo "will be emerged."
+ fi
}
get_files() {
- einfo "Collecting system binaries and libraries"
+ [[ $QUIET -ne 1 ]] && einfo "Collecting system binaries and libraries"
if [[ -r "$FILES_FILE" && -s "$FILES_FILE" ]]; then
- einfo "Found existing $FILES_FILE"
+ [[ $QUIET -ne 1 ]] && 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
@@ -633,29 +669,48 @@ get_files() {
-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"
+ [[ $QUIET -ne 1 ]] && einfo "Generated new $FILES_FILE"
fi
}
+parse_ld_so_conf() {
+ # FIXME: not safe for paths with spaces
+ local include
+ for path in $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf); do
+ if [[ $include = true ]]; then
+ for include_path in $(sed '/^#/d;s/#.*$//' /etc/${path} 2>/dev/null); do
+ echo $include_path
+ done
+ include=""
+ continue
+ fi
+ if [[ $path != include ]]; then
+ echo $path
+ else
+ include="true"
+ continue
+ fi
+ done
+}
get_ldpath() {
local COMPLETE_LD_LIBRARY_PATH
[[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return
- einfo 'Collecting complete LD_LIBRARY_PATH'
+ [[ $QUIET -ne 1 ]] && einfo 'Collecting complete LD_LIBRARY_PATH'
if [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]]; then
- einfo "Found existing $LDPATH_FILE."
+ [[ $QUIET -ne 1 ]] && 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)
+ $(parse_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"
+ [[ $QUIET -ne 1 ]] && einfo "Generated new $LDPATH_FILE"
fi
}
main_checks() {
@@ -671,9 +726,9 @@ main_checks() {
die 1 "Unable to find $LDPATH_FILE"
COMPLETE_LD_LIBRARY_PATH=$(<"$LDPATH_FILE")
fi
- einfo "Checking dynamic linking $WORKING_TEXT"
+ [[ $QUIET -ne 1 ]] && einfo "Checking dynamic linking $WORKING_TEXT"
if [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]]; then
- einfo "Found existing $BROKEN_FILE."
+ [[ $QUIET -ne 1 ]] && einfo "Found existing $BROKEN_FILE."
else
clean_trap "$BROKEN_FILE" "$ERRORS_FILE"
files=($(<"$FILES_FILE"))
@@ -686,10 +741,10 @@ main_checks() {
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
+ grep -q -E "$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
+ grep -vF "$LD_LIBRARY_MASK" | grep -q -E "$SONAME_SEARCH"; then
# FIXME: I hate duplicating code
# Only build missing direct dependencies
MISSING_LIBS=$(
@@ -710,8 +765,8 @@ main_checks() {
# 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"
+ expr="s/^[[:space:]]*\([^[:space:]]*\).*$/\1/p"
+ sort -u <<< "$ldd_output" | grep -E "$SONAME" | sed -n "$expr"
)
REQUIRED_LIBS=$(
expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
@@ -768,7 +823,7 @@ main_checks() {
progress $((++i)) $numFiles $target_file ||
progress $((++i)) $numFiles
done
- if [[ $SEARCH_BROKEN ]]; then
+ if [[ $SEARCH_BROKEN && -f $ERRORS_FILE ]]; then
# Look for missing version
while read target_file; do
echo "obj $target_file" >> "$BROKEN_FILE"
@@ -786,7 +841,7 @@ main_checks() {
fi
[[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]] || clean_exit
sort -u "$BROKEN_FILE" -o "$BROKEN_FILE"
- einfo "Generated new $BROKEN_FILE"
+ [[ $QUIET -ne 1 ]] && einfo "Generated new $BROKEN_FILE"
fi
}
get_packages() {
@@ -814,7 +869,7 @@ get_packages() {
echo_v " $target_file -> (none)"
fi
done < "$BROKEN_FILE"
- einfo "Generated new $RAW_FILE and $OWNERS_FILE"
+ [[ $QUIET -ne 1 ]] && 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
@@ -831,12 +886,12 @@ get_packages() {
fi
}
clean_packages() {
- einfo 'Cleaning list of packages to rebuild'
+ [[ $QUIET -ne 1 ]] && einfo 'Cleaning list of packages to rebuild'
if [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
- einfo "Found existing $PKGS_FILE"
+ [[ $QUIET -ne 1 ]] && einfo "Found existing $PKGS_FILE"
else
sort -u "$RAW_FILE" > "$PKGS_FILE"
- einfo "Generated new $PKGS_FILE"
+ [[ $QUIET -ne 1 ]] && einfo "Generated new $PKGS_FILE"
fi
}
assign_packages_to_ebuilds() {
@@ -855,7 +910,7 @@ assign_packages_to_ebuilds() {
SLOT=$(</var/db/pkg/$EXACT_PKG/SLOT)
echo "$PKG:$SLOT"
done < "$PKGS_FILE" > "$EBUILDS_FILE"
- einfo "Generated new $EBUILDS_FILE"
+ [[ $QUIET -ne 1 ]] && einfo "Generated new $EBUILDS_FILE"
else
einfo 'Nothing to rebuild.'
die 1 '(The program should have already quit, so this is a minor bug.)'
@@ -869,7 +924,7 @@ get_exact_ebuilds() {
rebuildList=" $(<"$BROKEN_FILE") "
rebuildList=(${rebuildList//[[:space:]]obj[[:space:]]/ })
get_file_owner "${rebuildList[@]}" | sed 's/^/=/' > "$EBUILDS_FILE"
- einfo "Generated new $EBUILDS_FILE"
+ [[ $QUIET -ne 1 ]] && einfo "Generated new $EBUILDS_FILE"
else
einfo 'Nothing to rebuild.'
die 1 '(The program should have already quit, so this is a minor bug.)'
@@ -893,7 +948,7 @@ get_build_order() {
einfo 'Skipping package ordering'
return
fi
- einfo 'Evaluating package order'
+ [[ $QUIET -ne 1 ]] && einfo 'Evaluating package order'
if [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]]; then
einfo "Found existing $ORDER_FILE"
else
@@ -952,7 +1007,7 @@ get_build_order() {
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"
+ [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" && $QUIET -ne 1 ]] && einfo "Generated new $ORDER_FILE"
}
show_unowned_files() {
@@ -964,14 +1019,31 @@ show_unowned_files() {
done < "$OWNERS_FILE" | gawk '!s[$0]++' # (omit dupes)
fi
}
+
+# Get multiple portage variables at once to speedup revdep-rebuild.
+portage_settings() {
+ local ORIG_SEARCH_DIRS="$SEARCH_DIRS"
+ local ORIG_SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK"
+ local ORIG_LD_LIBRARY_MASK="$LD_LIBRARY_MASK"
+ unset SEARCH_DIRS
+ unset SEARCH_DIRS_MASK
+ unset LD_LIBRARY_MASK
+
+ eval $(portageq envvar -v PORTAGE_ROOT PORTAGE_NICENESS EMERGE_DEFAULT_OPTS NOCOLOR SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK)
+ export NOCOLOR
+
+ SEARCH_DIRS="$ORIG_SEARCH_DIRS $SEARCH_DIRS"
+ SEARCH_DIRS_MASK="$ORIG_SEARCH_DIRS_MASK $SEARCH_DIRS_MASK"
+ LD_LIBRARY_MASK="$ORIG_LD_LIBRARY_MASK $LD_LIBRARY_MASK"
+}
+
##
# Setup portage and the search paths
setup_portage() {
- local PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
- PORTAGE_ROOT=$(portageq envvar ROOT)
-
- # Obey PORTAGE_NICENESS
+ # Obey PORTAGE_NICENESS (which is incremental to the current nice value)
if [[ $PORTAGE_NICENESS ]]; then
+ current_niceness=$(nice)
+ let PORTAGE_NICENESS=${current_niceness}+${PORTAGE_NICENESS}
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.
@@ -986,7 +1058,7 @@ setup_portage() {
setup_search_paths_and_masks() {
local configfile sdir mdir skip_me filter_SEARCH_DIRS
- einfo "Configuring search environment for $APP_NAME"
+ [[ $QUIET -ne 1 ]] && einfo "Configuring search environment for $APP_NAME"
# Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
# portage, and the environment
@@ -994,9 +1066,9 @@ setup_search_paths_and_masks() {
# 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)
+# 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
@@ -1018,7 +1090,7 @@ setup_search_paths_and_masks() {
# 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)
+ SEARCH_DIRS+=" "$(parse_ld_so_conf)
fi
# Set the final variables
@@ -1048,8 +1120,8 @@ rebuild() {
trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
- einfo 'All prepared. Starting rebuild'
- echo "emerge --oneshot ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
+ [[ $QUIET -ne 1 ]] && einfo 'All prepared. Starting rebuild'
+ echo "emerge --oneshot ${EMERGE_DEFAULT_OPTS} ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
is_real_merge && countdown 10
@@ -1058,7 +1130,7 @@ rebuild() {
# Run in background to correctly handle Ctrl-C
{
- EMERGE_DEFAULT_OPTS="--oneshot ${EMERGE_OPTIONS[@]}" emerge $REBUILD_LIST <&6
+ emerge --oneshot ${EMERGE_DEFAULT_OPTS} ${EMERGE_OPTIONS[@]} $REBUILD_LIST <&6
echo $? > "$STATUS_FILE"
} &
wait
@@ -1069,7 +1141,7 @@ rebuild() {
##
# Finish up
cleanup() {
- if (( $(<"$STATUS_FILE") != 0 )); then
+ if [[ (( $(<"$STATUS_FILE") != 0 )) && ! is_real_merge ]]; then
ewarn
ewarn "$APP_NAME failed to emerge all packages."
ewarn 'you have the following choices:'
@@ -1104,7 +1176,7 @@ cleanup() {
if [[ -r "$OWNERS_FILE" && -s "$OWNERS_FILE" ]]; then
show_unowned_files
fi
- [[ $KEEP_TEMP ]] || rm "${FILES[@]}"
+ [[ $KEEP_TEMP ]] || rm -f "${FILES[@]}"
else
einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'
fi