import re
import signal
import sys
+import textwrap
import time
from optparse import OptionParser, OptionValueError
class WorldHandler(object):
+ short_desc = "Fix problems in the world file"
+
def name():
return "world"
name = staticmethod(name)
class BinhostHandler(object):
+ short_desc = "Generate a metadata index for binary packages"
+
def name():
return "binhost"
name = staticmethod(name)
return errors
class MoveInstalled(MoveHandler):
+
+ short_desc = "Perform package move updates for installed packages"
+
def name():
return "moveinst"
name = staticmethod(name)
MoveHandler.__init__(self, portage.db[myroot]["vartree"])
class MoveBinary(MoveHandler):
+
+ short_desc = "Perform package move updates for binary packages"
+
def name():
return "movebin"
name = staticmethod(name)
raise NotImplementedError(self)
class CleanResume(object):
+
+ short_desc = "Discard emerge --resume merge lists"
+
def name():
return "cleanresume"
name = staticmethod(name)
setattr(parser, var, str(option))
- usage = "usage: emaint [options] " + " | ".join(module_names)
+ usage = "usage: emaint [options] COMMAND"
- usage+= "\n\nCurrently emaint can only check and fix problems with one's world\n"
- usage+= "file. Future versions will integrate other portage check-and-fix\n"
- usage+= "tools and provide a single interface to system health checks."
+ desc = "The emaint program provides an interface to system health " + \
+ "checks and maintenance. See the emaint(1) man page for " + \
+ "for additional information about the following commands:"
+ usage += "\n\n"
+ for line in textwrap.wrap(desc, 65):
+ usage += "%s\n" % line
+ usage += "\n"
+ usage += " %s" % "all".ljust(15) + \
+ "Perform all supported commands\n"
+ for m in module_names[1:]:
+ usage += " %s%s\n" % (m.ljust(15), modules[m].short_desc)
parser = OptionParser(usage=usage, version=portage.VERSION)
parser.add_option("-c", "--check", help="check for problems",
read my_input
# failed integer conversions will break a loop unless they're enclosed
# in a subshell.
- echo "${my_input}" | ( declare -i x; read x) && break
+ echo "${my_input}" | ( declare -i x; read x) 2>/dev/null && break
+ echo -n "Value '$my_input' is not valid. Please enter an integer value:" >&2
done
echo ${my_input}
}
}
die() {
- trap "" TERM
- trap "" KILL
+ trap SIGTERM SIGINT
- if [ ${2} -eq 0 ]; then
+ if [ "$2" -eq 0 ]; then
echo "Exiting: ${1}"
scan > /dev/null
[ ${count} -gt 0 ] && echo "NOTE: ${count} updates remaining"
export EROOT=${ROOT%/}${EPREFIX}/
TMP="${PORTAGE_TMPDIR}/etc-update-$$"
-trap die term
+trap "die terminated 1" SIGTERM
+trap "die interrupted 1" SIGINT
[ -w ${PORTAGE_CONFIGROOT}etc ] || die "Need write access to ${PORTAGE_CONFIGROOT}etc" 1
#echo $PORTAGE_TMPDIR
from itertools import chain, izip
from stat import S_ISDIR, ST_CTIME
-try:
- import cPickle as pickle
-except ImportError:
- import pickle
-
try:
import cStringIO as StringIO
except ImportError:
'fix' : 'Fix simple QA issues (stray digests, missing digests)',
'full' : 'Scan directory tree and print all issues (not a summary)',
'help' : 'Show this screen',
- 'last' : 'Remember report from last run',
- 'lfull' : 'Remember report from last run (full listing)',
'manifest' : 'Generate a Manifest (fetches files if necessary)',
'scan' : 'Scan directory tree for QA issues'
}
break
if not opts.mode:
- opts.mode = 'full' #default to full
+ opts.mode = 'full'
if opts.mode == 'ci':
opts.mode = 'commit' # backwards compat shortcut
# file.executable
no_exec = frozenset(["Manifest","ChangeLog","metadata.xml"])
-def last(full=False):
- """Print the results of the last repoman run
- Args:
- full - Print the complete results, if false, print a summary
- Returns:
- Doesn't return (invokes sys.exit()
- """
- #Retrieve and unpickle stats and fails from saved files
- savedf=open(os.path.join(portage.const.CACHE_PATH, 'repo.stats'),'r')
- stats = pickle.load(savedf)
- savedf.close()
- savedf=open(os.path.join(portage.const.CACHE_PATH, 'repo.fails'),'r')
- fails = pickle.load(savedf)
- savedf.close()
-
- #dofail will be set to 1 if we have failed in at least one non-warning category
- dofail=0
- #dowarn will be set to 1 if we tripped any warnings
- dowarn=0
- #dofull will be set if we should print a "repoman full" informational message
- dofull=0
-
- dofull = options.mode not in ("full", "lfull")
-
- for x in qacats:
- if not stats[x]:
- continue
- dowarn = 1
- if x not in qawarnings:
- dofail = 1
-
- print
- print green("RepoMan remembers...")
- print
- style_file = ConsoleStyleFile(sys.stdout)
- console_writer = StyleWriter(file=style_file, maxcol=9999)
- console_writer.style_listener = style_file.new_styles
- f = formatter.AbstractFormatter(console_writer)
- utilities.format_qa_output(f, stats, fails, dofull, dofail, options, qawarnings)
- print
- if dofull:
- print bold("Note: type \"repoman lfull\" for a complete listing of repomans last run.")
- print
- if dowarn and not dofail:
- print green("RepoMan sez:"),"\"You only gave me a partial QA payment last time?\n I took it, but I wasn't happy.\""
- elif not dofail:
- print green("RepoMan sez:"),"\"If everyone were like you, I'd be out of business!\""
- print
- sys.exit(0)
-
options, arguments = ParseArgs(sys.argv, qahelp)
-if options.mode in ('last', 'lfull'):
- last('lfull' in options.mode)
-
# Set this to False when an extraordinary issue (generally
# something other than a QA issue) makes it impossible to
# commit (like if Manifest generation fails).
if options.mode == "manifest":
sys.exit(dofail)
-#Pickle and save results for instant reuse in last and lfull
-if os.access(portage.const.CACHE_PATH, os.W_OK):
- for myobj, fname in (stats, "repo.stats"), (fails, "repo.fails"):
- fpath = os.path.join(portage.const.CACHE_PATH, fname)
- savef = open(fpath, 'w')
- pickle.dump(myobj, savef)
- savef.close()
- portage.apply_secpass_permissions(fpath, gid=portage.portage_gid,
- mode=0664)
-
-# TODO(antarus) This function and last () look familiar ;)
-
#dofail will be set to 1 if we have failed in at least one non-warning category
dofail=0
#dowarn will be set to 1 if we tripped any warnings
dowarn=0
#dofull will be set if we should print a "repoman full" informational message
-dofull = options.mode not in ("full", "lfull")
+dofull = options.mode != 'full'
for x in qacats:
if not stats[x]:
[downgrade]
class = portage.sets.dbapi.DowngradeSet
world-candidate = False
+
+# Installed packages for which there are no visible ebuilds
+# corresponding to the same $CATEGORY/$PN:$SLOT.
+[unavailable]
+class = portage.sets.dbapi.UnavailableSet
+world-candidate = False
</itemizedlist>
</para>
</sect2>
+ <sect2 id='config-set-classes-UnavailableSet'>
+ <title>portage.sets.dbapi.UnavailableSet</title>
+ <para>
+ Package set which contains all installed
+ packages for which there are no visible ebuilds
+ corresponding to the same $CATEGORY/$PN:$SLOT.
+ This class supports the following options:
+ <itemizedlist>
+ <listitem><varname>metadata-source</varname>: Optional, defaults to
+ "porttree". Specifies the repository to use for getting the metadata
+ to check.</listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
<sect2 id='config-set-classes-DowngradeSet'>
<title>portage.sets.dbapi.DowngradeSet</title>
<para>
<listitem><varname>live-rebuild</varname>: uses <classname>VariableSet</classname></listitem>
<listitem><varname>module-rebuild</varname>: uses <classname>OwnerSet</classname></listitem>
<listitem><varname>downgrade</varname>: uses <classname>DowngradeSet</classname></listitem>
+ <listitem><varname>unavailable</varname>: uses <classname>UnavailableSet</classname></listitem>
</itemizedlist>
Additionally the default configuration includes a multi set section based on
the <classname>StaticFileSet</classname> defaults that creates a set for each
is possible to prefix flags with + or - in order to create default settings
that respectively enable or disable the corresponding \fBUSE\fR flags. For
details about \fBUSE\fR flag stacking order, refer to the \fBUSE_ORDER\fR
-variable in \fBmake.conf\fR(5).
+variable in \fBmake.conf\fR(5). Given the default \fBUSE_ORDER\fR setting,
+negative IUSE default settings are ineffective since profile and user
+configuration settings override them.
.TP
\fBDEPEND\fR
This should contain a list of all packages that are required for the
.SH SYNOPSIS
.BR emaint
[\fIoptions\fR]
-[\fBall\fR | \fBworld\fR]
+[\fBall\fR | \fBbinhost\fR | \fBcleanresume\fR | \
+\fBmovebin\fR | \fBmoveinst\fR | \fBworld\fR]
.SH DESCRIPTION
-.B emaint
-checks for and fixes problems in the portage \fIworld\fR file.
+The emaint program provides an interface to system health
+checks and maintenance.
+.SH COMMANDS
+.TP
+.BR all
+Perform all supported commands.
+.TP
+.BR binhost
+Generate a metadata index for binary packages located in \fBPKGDIR\fR (for
+download by remote clients). See the \fBPORTAGE_BINHOST\fR documentation in
+the \fBmake.conf\fR(5) man page for additional information.
+.TP
+.BR cleanresume
+Discard merge lists saved for the \fBemerge\fR(1) \fB--resume\fR action.
+.TP
+.BR movebin
+Perform package move updates for binary packages located in \fBPKGDIR\fR.
+.TP
+.BR moveinst
+Perform package move updates for installed packages.
+.TP
+.BR world
+Fix problems in the \fIworld\fR file.
.SH OPTIONS
.TP
.B \-c, \-\-check
.B full
Scan directory tree for QA issues (full listing)
.TP
-.B last
-Remember report from last run
-.TP
.B help
Show this screen
.TP
.B fix
Fix simple QA issues (stray digests, missing digests)
.TP
-.B lfull
-Remember report from last run (full listing)
-.TP
.B manifest
Generate a Manifest (fetches files if necessary)
.TP
print "\nemerge: there are no ebuilds to satisfy "+green(xinfo)+"."
# Show parent nodes and the argument that pulled them in.
+ traversed_nodes = set()
node = myparent
msg = []
while node is not None:
+ traversed_nodes.add(node)
msg.append('(dependency required by "%s" [%s])' % \
(colorize('INFORM', str(node.cpv)), node.type_name))
- parent = None
+ # When traversing to parents, prefer arguments over packages
+ # since arguments are root nodes. Never traverse the same
+ # package twice, in order to prevent an infinite loop.
+ selected_parent = None
for parent in self.digraph.parent_nodes(node):
if isinstance(parent, DependencyArg):
msg.append('(dependency required by "%s" [argument])' % \
(colorize('INFORM', str(parent))))
- parent = None
+ selected_parent = None
break
- node = parent
+ if parent not in traversed_nodes:
+ selected_parent = parent
+ node = selected_parent
for line in msg:
print line
"is known to be triggered " + \
"by things such as failed variable " + \
"assignments (bug #190128) or bad substitution " + \
- "errors (bug #200313)."
+ "errors (bug #200313). This behavior may also be " + \
+ "triggered by a corrupt bash binary or a hardware " + \
+ "problem such as memory or cpu malfunction."
return msg
def _doebuild_exit_status_check_and_log(settings, mydo, retval):
singleBuilder = classmethod(singleBuilder)
+class UnavailableSet(EverythingSet):
+
+ _operations = ["unmerge"]
+
+ description = "Package set which contains all installed " + \
+ "packages for which there are no visible ebuilds " + \
+ "corresponding to the same $CATEGORY/$PN:$SLOT."
+
+ def __init__(self, vardb, metadatadb=None):
+ super(UnavailableSet, self).__init__(vardb)
+ self._metadatadb = metadatadb
+
+ def _filter(self, atom):
+ return not self._metadatadb.match(atom)
+
+ def singleBuilder(cls, options, settings, trees):
+
+ metadatadb = options.get("metadata-source", "porttree")
+ if not metadatadb in trees:
+ raise SetConfigError(("invalid value '%s' for option " + \
+ "metadata-source") % (metadatadb,))
+
+ return cls(trees["vartree"].dbapi,
+ metadatadb=trees[metadatadb].dbapi)
+
+ singleBuilder = classmethod(singleBuilder)
+
class CategorySet(PackageSet):
_operations = ["merge", "unmerge"]
Returns:
None (modifies formatter)
"""
- full = options.mode in ("full", "lfull")
+ full = options.mode == 'full'
# we only want key value pairs where value > 0
for category, number in \
itertools.ifilter(lambda myitem: myitem[1] > 0, stats.iteritems()):