good = create_color_func("GOOD")
bad = create_color_func("BAD")
+import portage_dep
import portage_util
import portage_locks
import portage_exception
self.root = real_vartree.root
self.settings = real_vartree.settings
self.dbapi = portage.fakedbapi(settings=real_vartree.settings)
- global_updates = None
vdb_path = os.path.join(self.root, portage.VDB_PATH)
try:
# At least the parent needs to exist for the lock file.
vdb_lock = portage_locks.lockdir(vdb_path)
mykeys = ["SLOT", "COUNTER", "PROVIDE", "USE", "IUSE",
"DEPEND", "RDEPEND", "PDEPEND"]
- portdb_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
real_dbapi = real_vartree.dbapi
slot_counters = {}
for cpv in real_dbapi.cpv_all():
continue
slot_counters[myslot_atom] = mycounter
self.dbapi.cpv_inject(cpv, metadata=metadata)
- try:
- # Use the live ebuild metadata if possible.
- live_metadata = dict(izip(portdb_keys,
- portdb.aux_get(cpv, portdb_keys)))
- self.dbapi.aux_update(cpv, live_metadata)
- except (KeyError, portage_exception.PortageException):
- if global_updates is None:
- global_updates = \
- grab_global_updates(portdb.porttree_root)
- perform_global_updates(
- cpv, self.dbapi, global_updates)
finally:
if vdb_lock:
portage_locks.unlockdir(vdb_lock)
self.settings.treeVirtuals = portage_util.map_dictlist_vals(
portage.getCPFromCPV, self.get_all_provides())
+ # Intialize variables needed for lazy cache pulls of the live ebuild
+ # metadata. This ensures that the vardb lock is released ASAP, without
+ # being delayed in case cache generation is triggered.
+ self._aux_get = self.dbapi.aux_get
+ self.dbapi.aux_get = self._aux_get_wrapper
+ self._aux_get_history = set()
+ self._portdb_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
+ self._portdb = portdb
+ self._global_updates = None
+
+ def _aux_get_wrapper(self, pkg, wants):
+ if pkg in self._aux_get_history:
+ return self._aux_get(pkg, wants)
+ self._aux_get_history.add(pkg)
+ try:
+ # Use the live ebuild metadata if possible.
+ live_metadata = dict(izip(self._portdb_keys,
+ self._portdb.aux_get(pkg, self._portdb_keys)))
+ self.dbapi.aux_update(pkg, live_metadata)
+ except (KeyError, portage_exception.PortageException):
+ if self._global_updates is None:
+ self._global_updates = \
+ grab_global_updates(self._portdb.porttree_root)
+ perform_global_updates(
+ pkg, self.dbapi, self._global_updates)
+ return self._aux_get(pkg, wants)
+
def grab_global_updates(portdir):
from portage_update import grab_updates, parse_updates
updpath = os.path.join(portdir, "profiles", "updates")
p_type, p_root, p_key, p_status = parent_node
msg = []
if p_status == "nomerge":
+ category, pf = portage.catsplit(p_key)
+ pkg_location = os.path.join(p_root, portage.VDB_PATH, category, pf)
msg.append("Portage is unable to process the dependencies of the ")
msg.append("'%s' package. " % p_key)
msg.append("In order to correct this problem, the package ")
msg.append("should be uninstalled, reinstalled, or upgraded. ")
msg.append("As a temporary workaround, the --nodeps option can ")
- msg.append("be used to ignore all dependencies.")
+ msg.append("be used to ignore all dependencies. For reference, ")
+ msg.append("the problematic dependencies can be found in the ")
+ msg.append("*DEPEND files located in '%s/'." % pkg_location)
else:
msg.append("This package can not be installed. ")
msg.append("Please notify the '%s' package maintainer " % p_key)
# have after new packages have been installed.
fakedb = portage.fakedbapi(settings=self.pkgsettings[myroot])
self.mydbapi[myroot] = fakedb
- for pkg in vardb.cpv_all():
- fakedb.cpv_inject(pkg,
- metadata=dict(izip(self._mydbapi_keys,
- vardb.aux_get(pkg, self._mydbapi_keys))))
+ if "--nodeps" not in self.myopts and \
+ "--buildpkgonly" not in self.myopts:
+ # --nodeps bypasses this, since it isn't needed in this case
+ # and the cache pulls might trigger (slow) cache generation.
+ for pkg in vardb.cpv_all():
+ self.spinner.update()
+ fakedb.cpv_inject(pkg,
+ metadata=dict(izip(self._mydbapi_keys,
+ vardb.aux_get(pkg, self._mydbapi_keys))))
del vardb, fakedb
self.useFlags[myroot] = {}
if "--usepkg" in self.myopts:
bindb = self.trees[myroot]["bintree"].dbapi
vardb = self.trees[myroot]["vartree"].dbapi
pkgsettings = self.pkgsettings[myroot]
+ if myparent:
+ p_type, p_root, p_key, p_status = myparent
if "--debug" in self.myopts:
print
#processing dependencies
""" Call portage.dep_check to evaluate the use? conditionals and make sure all
dependencies are satisfiable. """
- mycheck = portage.dep_check(depstring, None,
- pkgsettings, myuse=myuse,
- use_binaries=("--usepkgonly" in self.myopts),
- myroot=myroot, trees=self.trees)
+ try:
+ if myparent and p_status == "nomerge":
+ portage_dep._dep_check_strict = False
+ mycheck = portage.dep_check(depstring, None,
+ pkgsettings, myuse=myuse,
+ use_binaries=("--usepkgonly" in self.myopts),
+ myroot=myroot, trees=self.trees)
+ finally:
+ portage_dep._dep_check_strict = True
if not mycheck[0]:
show_invalid_depstring_notice(myparent, depstring, mycheck[1])
"--nodeps" in self.myopts:
return True
+ modified_slots = {}
+ for myroot in self.trees:
+ myslots = {}
+ modified_slots[myroot] = myslots
+ final_db = self.mydbapi[myroot]
+ slot_node_map = self._slot_node_map[myroot]
+ for slot_atom, mynode in slot_node_map.iteritems():
+ mytype, myroot, mycpv, mystatus = mynode
+ if mystatus == "merge":
+ myslots[slot_atom] = mycpv
+
#if "deep" in self.myparams:
if True:
# Pull in blockers from all installed packages that haven't already
# It is crucial to pass in final_db here in order to
# optimize dep_check calls by eliminating atoms via
# dep_wordreduce and dep_eval calls.
- success, atoms = portage.dep_check(depstr, final_db,
- pkgsettings, myuse=myuse, trees=dep_check_trees,
- myroot=myroot)
+ try:
+ portage_dep._dep_check_strict = False
+ success, atoms = portage.dep_check(depstr,
+ final_db, pkgsettings, myuse=myuse,
+ trees=dep_check_trees, myroot=myroot)
+ finally:
+ portage_dep._dep_check_strict = True
if not success:
+ slot_atom = "%s:%s" % (portage.dep_getkey(pkg),
+ vardb.aux_get(pkg, ["SLOT"])[0])
+ if slot_atom in modified_slots[myroot]:
+ # This package is being replaced anyway, so
+ # ignore invalid dependencies so as not to
+ # annoy the user too much (otherwise they'd be
+ # forced to manually unmerge it first).
+ continue
show_invalid_depstring_notice(
("installed", myroot, pkg, "nomerge"),
depstr, atoms)
self.blocker_parents[blocker] = myparents
myparents.add(myparent)
- modified_slots = {}
- if self.blocker_parents:
- for myroot in self.trees:
- myslots = {}
- modified_slots[myroot] = myslots
- final_db = self.mydbapi[myroot]
- slot_node_map = self._slot_node_map[myroot]
- for slot_atom, mynode in slot_node_map.iteritems():
- mytype, myroot, mycpv, mystatus = mynode
- if mystatus == "merge":
- modified_slots[myroot][slot_atom] = mycpv
-
for blocker in self.blocker_parents.keys():
mytype, myroot, mydep = blocker
initial_db = self.trees[myroot]["vartree"].dbapi
#we're done... return
return 0
if "--ask" in myopts:
- if userquery("Would you like to unmerge these packages?",
- responses=["No", "Yes"], colours=[red, green]) == "No":
+ if userquery("Would you like to unmerge these packages?")=="No":
# enter pretend mode for correct formatting of results
myopts["--pretend"] = True
print
vartree=vartree, ldpath_mtimes=ldpath_mtimes)
if retval != os.EX_OK:
emergelog(xterm_titles, " !!! unmerge FAILURE: "+y)
+ ebuild = vartree.dbapi.findname(y)
+ show_unmerge_failure_message(y, ebuild, retval)
+ sys.exit(retval)
else:
clean_world(vartree.dbapi, y)
emergelog(xterm_titles, " >>> unmerge success: "+y)
return 1
+def show_unmerge_failure_message(pkg, ebuild, retval):
+
+ from formatter import AbstractFormatter, DumbWriter
+ f = AbstractFormatter(DumbWriter(maxcol=72))
+
+ msg = []
+ msg.append("A removal phase of the '%s' package " % pkg)
+ msg.append("has failed with exit value %s. " % retval)
+ msg.append("The problem occurred while executing ")
+ msg.append("the ebuild located at '%s'. " % ebuild)
+ msg.append("If necessary, manually remove the ebuild " )
+ msg.append("in order to skip the execution of removal phases.")
+
+ print
+ for x in msg:
+ f.add_flowing_data(x)
+ f.end_paragraph(1)
+
def chk_updated_info_files(root, infodirs, prev_mtimes, retval):
print
else:
print "hard"
- success, atoms = portage.dep_check(depstr, None, settings,
- myuse=usedef, trees=dep_check_trees, myroot=myroot)
+ try:
+ portage_dep._dep_check_strict = False
+ success, atoms = portage.dep_check(depstr, None, settings,
+ myuse=usedef, trees=dep_check_trees, myroot=myroot)
+ finally:
+ portage_dep._dep_check_strict = True
if not success:
show_invalid_depstring_notice(
("installed", myroot, pkg, "nomerge"),
sys.exit(0)
myparams = create_depgraph_params(myopts, myaction)
- mydepgraph = depgraph(settings, trees,
- myopts, myparams, spinner)
if myaction in ["system","world"]:
if not ("--quiet" in myopts):
print "Calculating",myaction,"dependencies ",
sys.stdout.flush()
+ mydepgraph = depgraph(settings, trees, myopts, myparams, spinner)
if not mydepgraph.xcreate(myaction):
print "!!! Depgraph creation failed."
sys.exit(1)
if not ("--quiet" in myopts):
print "Calculating dependencies ",
sys.stdout.flush()
+ mydepgraph = depgraph(settings, trees, myopts, myparams, spinner)
try:
retval, favorites = mydepgraph.select_files(myfiles)
except portage_exception.PackageNotFound, e:
# XXX This would be to replace getstatusoutput completely.
# XXX Issue: cannot block execution. Deadlock condition.
-def spawn(mystring,mysettings,debug=0,free=0,droppriv=0,sesandbox=0,fd_pipes=None,**keywords):
+def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, **keywords):
"""spawn a subprocess with optional sandbox protection,
depending on whether sandbox is enabled. The "free" argument,
when set to 1, will disable sandboxing. This allows us to
# get possible slot information from the deps file
if mydo == "depend":
writemsg("!!! DEBUG: dbkey: %s\n" % str(dbkey), 2)
- if dbkey:
+ if isinstance(dbkey, dict):
+ mysettings["dbkey"] = ""
+ pr, pw = os.pipe()
+ fd_pipes = {0:0, 1:1, 2:2, 9:pw}
+ mypids = spawn(EBUILD_SH_BINARY + " depend", mysettings,
+ fd_pipes=fd_pipes, returnpid=True)
+ os.close(pw) # belongs exclusively to the child process now
+ maxbytes = 1024
+ mybytes = []
+ while True:
+ mybytes.append(os.read(pr, maxbytes))
+ if not mybytes[-1]:
+ break
+ os.close(pr)
+ mybytes = "".join(mybytes)
+ global auxdbkeys
+ dbkey.update(izip(auxdbkeys, mybytes.split("\n")))
+ retval = os.waitpid(mypids[0], 0)[1]
+ # If it got a signal, return the signal that was sent, but
+ # shift in order to distinguish it from a return value. (just
+ # like portage_exec.spawn() would do).
+ if retval & 0xff:
+ return (retval & 0xff) << 8
+ # Otherwise, return its exit code.
+ return retval >> 8
+ elif dbkey:
mysettings["dbkey"] = dbkey
else:
mysettings["dbkey"] = \
return 1
# Build directory creation isn't required for any of these.
- if mydo not in ["fetch","digest","manifest"]:
+ if mydo not in ("digest", "fetch", "help", "manifest"):
mystatus = prepare_build_dirs(myroot, mysettings, cleanup)
if mystatus:
return mystatus
try:
mylink.lockdb()
if mylink.exists():
- mylink.unmerge(trimworld=mytrimworld, cleanup=1,
+ retval = mylink.unmerge(trimworld=mytrimworld, cleanup=1,
ldpath_mtimes=ldpath_mtimes)
- mylink.delete()
- return 0
- return 1
+ if retval == os.EX_OK:
+ mylink.delete()
+ return retval
+ return os.EX_OK
finally:
mylink.unlockdb()
newsplit.append(_expand_new_virtuals(x, edebug, mydbapi,
mysettings, myroot=myroot, trees=trees, **kwargs))
continue
- if not isvalidatom(x, allow_blockers=True):
+ if portage_dep._dep_check_strict and \
+ not isvalidatom(x, allow_blockers=True):
raise portage_exception.ParseError(
"invalid atom: '%s'" % x)
mykey = dep_getkey(x)
writemsg("doregen: %s %s\n" % (doregen,mycpv), 2)
writemsg("Generating cache entry(0) for: "+str(myebuild)+"\n",1)
- if self.tmpfs:
- mydbkey = self.tmpfs+"/aux_db_key_temp"
- else:
- mydbkey = self.depcachedir+"/aux_db_key_temp"
-
- mylock = None
- try:
- mylock = portage_locks.lockfile(mydbkey, wantnewlockfile=1)
- try:
- os.unlink(mydbkey)
- except (IOError, OSError), e:
- if e.errno != errno.ENOENT:
- raise
- del e
-
- self.doebuild_settings.reset()
- myret = doebuild(myebuild, "depend", "/",
- self.doebuild_settings, dbkey=mydbkey, tree="porttree",
- mydbapi=self)
- if myret != os.EX_OK:
- #depend returned non-zero exit code...
- writemsg((red("\naux_get():") + \
- " (0) Error in '%s'. (%s)\n" + \
- " Check for syntax error or " + \
- "corruption in the ebuild. (--debug)\n\n") % \
- (myebuild, myret), noiselevel=-1)
- raise KeyError(mycpv)
-
- try:
- mycent = open(mydbkey, "r")
- os.unlink(mydbkey)
- mylines = mycent.readlines()
- mycent.close()
- except (IOError, OSError):
- writemsg((red("\naux_get():") + \
- " (1) Error in '%s' ebuild.\n" + \
- " Check for syntax error or " + \
- "corruption in the ebuild. (--debug)\n\n") % myebuild,
- noiselevel=-1)
- raise KeyError(mycpv)
- finally:
- if mylock:
- portage_locks.unlockfile(mylock)
-
+ self.doebuild_settings.reset()
mydata = {}
- for x in range(0,len(mylines)):
- if mylines[x][-1] == '\n':
- mylines[x] = mylines[x][:-1]
- mydata[auxdbkeys[x]] = mylines[x]
+ myret = doebuild(myebuild, "depend",
+ self.doebuild_settings["ROOT"], self.doebuild_settings,
+ dbkey=mydata, tree="porttree", mydbapi=self)
+ if myret != os.EX_OK:
+ raise KeyError(mycpv)
if "EAPI" not in mydata or not mydata["EAPI"].strip():
mydata["EAPI"] = "0"
if cache_me:
aux_cache = {}
+ if not mydata.setdefault("EAPI", "0"):
+ mydata["EAPI"] = "0"
for x in self._aux_cache_keys:
- aux_cache[x] = mydata[x]
- if not aux_cache["EAPI"]:
- aux_cache["EAPI"] = "0"
+ aux_cache[x] = mydata.get(x, "")
self._aux_cache[mycpv] = aux_cache
return returnme
# XXX: Decide how to handle failures here.
if retval != os.EX_OK:
writemsg("!!! FAILED prerm: %s\n" % retval, noiselevel=-1)
- sys.exit(123)
+ return retval
self._unmerge_pkgfiles(pkgfiles)
# XXX: Decide how to handle failures here.
if retval != os.EX_OK:
writemsg("!!! FAILED postrm: %s\n" % retval, noiselevel=-1)
- sys.exit(123)
+ return retval
doebuild(myebuildpath, "cleanrm", self.myroot, self.settings,
tree="vartree", mydbapi=self.vartree.dbapi,
vartree=self.vartree)
portage_locks.unlockdir(catdir_lock)
env_update(target_root=self.myroot, prev_mtimes=ldpath_mtimes,
contents=contents)
+ return os.EX_OK
def _unmerge_pkgfiles(self, pkgfiles):