from portage.util import normalize_path as normpath
from portage.util import writemsg
-if not hasattr(__builtins__, "set"):
- from sets import Set as set
from itertools import chain, izip
from UserDict import DictMixin
def clean_world(vardb, cpv):
"""Remove a package from the world file when unmerged."""
- world_filename = os.path.join(vardb.root, portage.WORLD_FILE)
- worldlist = portage.util.grabfile(world_filename)
+ world_set = WorldSet(vardb.settings)
+ world_set.lock()
+ world_set.load()
+ worldlist = list(world_set)
mykey = portage.cpv_getkey(cpv)
newworldlist = []
for x in worldlist:
else:
#this doesn't match the package we're unmerging; keep it.
newworldlist.append(x)
-
- newworldlist.sort()
-
- portage.util.ensure_dirs(os.path.join(vardb.root, portage.PRIVATE_PATH),
- gid=portage.portage_gid, mode=02770)
- portage.util.write_atomic(world_filename, "\n".join(newworldlist)+"\n")
-def genericdict(mylist):
- mynewdict={}
- for x in mylist:
- mynewdict[portage.dep_getkey(x)]=x
- return mynewdict
+ world_set.clear()
+ world_set.update(newworldlist)
+ world_set.save()
+ world_set.unlock()
+
+class AtomSet(object):
+ def __init__(self, atoms=None):
+ self._atoms = {}
+ if atoms:
+ self.update(atoms)
+ def clear(self):
+ self._atoms.clear()
+ def add(self, atom):
+ cp = portage.dep_getkey(atom)
+ cp_list = self._atoms.get(cp)
+ if cp_list is None:
+ cp_list = []
+ self._atoms[cp] = cp_list
+ if atom not in cp_list:
+ cp_list.append(atom)
+ def update(self, atoms):
+ for atom in atoms:
+ self.add(atom)
+ def __contains__(self, atom):
+ cp = portage.dep_getkey(atom)
+ if cp in self._atoms and atom in self._atoms[cp]:
+ return True
+ return False
+ def findAtomForPackage(self, cpv, metadata):
+ """Return the best match for a given package from the arguments, or
+ None if there are no matches. This matches virtual arguments against
+ the PROVIDE metadata. This can raise an InvalidDependString exception
+ if an error occurs while parsing PROVIDE."""
+ cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
+ cp = portage.dep_getkey(cpv)
+ atoms = self._atoms.get(cp)
+ if atoms:
+ best_match = portage.best_match_to_list(cpv_slot, atoms)
+ if best_match:
+ return best_match
+ if not metadata["PROVIDE"]:
+ return None
+ provides = portage.flatten(portage.dep.use_reduce(
+ portage.dep.paren_reduce(metadata["PROVIDE"]),
+ uselist=metadata["USE"].split()))
+ for provide in provides:
+ provided_cp = portage.dep_getkey(provide)
+ atoms = self._atoms.get(provided_cp)
+ if atoms:
+ transformed_atoms = [atom.replace(provided_cp, cp) for atom in atoms]
+ best_match = portage.best_match_to_list(cpv_slot, transformed_atoms)
+ if best_match:
+ return atoms[transformed_atoms.index(best_match)]
+ return None
+ def __iter__(self):
+ for atoms in self._atoms.itervalues():
+ for atom in atoms:
+ yield atom
+
+class SystemSet(AtomSet):
+ def __init__(self, settings, **kwargs):
+ AtomSet.__init__(self, **kwargs)
+ self.update(getlist(settings, "system"))
+
+class WorldSet(AtomSet):
+ def __init__(self, settings, **kwargs):
+ AtomSet.__init__(self, **kwargs)
+ self.world_file = os.path.join(settings["ROOT"], portage.WORLD_FILE)
+ self._lock = None
+ def _ensure_dirs(self):
+ portage.util.ensure_dirs(os.path.dirname(self.world_file),
+ gid=portage.portage_gid, mode=02750, mask=02)
+ def load(self):
+ self.clear()
+ self.update(portage.util.grabfile_package(self.world_file))
+ def save(self):
+ self._ensure_dirs()
+ portage.write_atomic(self.world_file,
+ "\n".join(sorted(self)) + "\n")
+ def lock(self):
+ self._ensure_dirs()
+ self._lock = portage.locks.lockfile(self.world_file, wantnewlockfile=1)
+ def unlock(self):
+ portage.locks.unlockfile(self._lock)
+ self._lock = None
+
+class RootConfig(object):
+ """This is used internally by depgraph to track information about a
+ particular $ROOT."""
+ def __init__(self, trees):
+ self.trees = trees
+ self.settings = trees["vartree"].settings
+ self.root = self.settings["ROOT"]
+ self.sets = {}
+ world_set = WorldSet(self.settings)
+ world_set.load()
+ self.sets["world"] = world_set
+ system_set = SystemSet(self.settings)
+ self.sets["system"] = system_set
+
+def create_world_atom(pkg_key, metadata, args_set, sets, portdb):
+ """Create a new atom for the world file if one does not exist. If the
+ argument atom is precise enough to identify a specific slot then a slot
+ atom will be returned. Atoms that are in the system set may also be stored
+ in world since system atoms can only match one slot while world atoms can
+ be greedy with respect to slots. Unslotted system packages will not be
+ not be stored in world."""
+ arg_atom = args_set.findAtomForPackage(pkg_key, metadata)
+ cp = portage.dep_getkey(arg_atom)
+ new_world_atom = cp
+ available_slots = set(portdb.aux_get(cpv, ["SLOT"])[0] \
+ for cpv in portdb.match(cp))
+ slotted = len(available_slots) > 1 or "0" not in available_slots
+ if slotted and arg_atom != cp:
+ # If the user gave a specific atom, store it as a
+ # slot atom in the world file.
+ slot_atom = "%s:%s" % (cp, metadata["SLOT"])
+ # First verify the slot is in the portage tree to avoid
+ # adding a bogus slot like that produced by multislot.
+ if portdb.match(slot_atom):
+ # Now verify that the argument is precise enough to identify a
+ # specific slot.
+ matches = portdb.match(arg_atom)
+ matched_slots = set()
+ for cpv in matches:
+ matched_slots.add(portdb.aux_get(cpv, ["SLOT"])[0])
+ if len(matched_slots) == 1:
+ new_world_atom = slot_atom
+ if new_world_atom == sets["world"].findAtomForPackage(pkg_key, metadata):
+ # Both atoms would be identical, so there's nothing to add.
+ return None
+ if not slotted and sets["system"].findAtomForPackage(pkg_key, metadata):
+ return None
+ return new_world_atom
def filter_iuse_defaults(iuse):
for flag in iuse:
if os.access(vdb_path, os.W_OK):
vdb_lock = portage.locks.lockdir(vdb_path)
mykeys = ["SLOT", "COUNTER", "PROVIDE", "USE", "IUSE",
- "DEPEND", "RDEPEND", "PDEPEND", "repository"]
+ "RESTRICT", "DEPEND", "RDEPEND", "PDEPEND", "repository"]
real_dbapi = real_vartree.dbapi
slot_counters = {}
for cpv in real_dbapi.cpv_all():
"""
return self.BlockerData(*self._cache_data["blockers"][cpv])
+ def keys(self):
+ """This needs to be implemented so that self.__repr__() doesn't raise
+ an AttributeError."""
+ if self._cache_data and "blockers" in self._cache_data:
+ return self._cache_data["blockers"].keys()
+ return []
+
def show_invalid_depstring_notice(parent_node, depstring, error_msg):
from formatter import AbstractFormatter, DumbWriter
self._slot_node_map = {}
self.mydbapi = {}
self._mydbapi_keys = ["SLOT", "DEPEND", "RDEPEND", "PDEPEND",
- "USE", "IUSE", "PROVIDE", "repository"]
+ "USE", "IUSE", "PROVIDE", "RESTRICT", "repository"]
self.useFlags = {}
self.trees = {}
+ self.roots = {}
for myroot in trees:
self.trees[myroot] = {}
for tree in ("porttree", "bintree"):
self.pkg_node_map[myroot] = {}
self._slot_node_map[myroot] = {}
vardb = self.trees[myroot]["vartree"].dbapi
+ self.roots[myroot] = RootConfig(self.trees[myroot])
# This fakedbapi instance will model the state that the vdb will
# have after new packages have been installed.
fakedb = portage.fakedbapi(settings=self.pkgsettings[myroot])
self._parent_child_digraph = digraph()
self.orderedkeys=[]
self.outdatedpackages=[]
- self._args_atoms = {}
- self._args_nodes = set()
+ # contains all sets added to the graph
self._sets = {}
- self._sets_nodes = {}
+ # contains atoms given as arguments
+ self._sets["args"] = AtomSet()
+ # contains all atoms from all sets added to the graph, including
+ # atoms given as arguments
+ self._set_atoms = AtomSet()
+ # contains all nodes pulled in by self._set_atoms
+ self._set_nodes = set()
self.blocker_digraph = digraph()
self.blocker_parents = {}
self._unresolved_blocker_parents = {}
if not arg and myroot == self.target_root:
try:
- arg = self._find_atom_for_pkg(self._args_atoms, mykey, metadata)
+ arg = self._set_atoms.findAtomForPackage(mykey, metadata)
except portage.exception.InvalidDependString, e:
if mytype != "installed":
show_invalid_depstring_notice(tuple(mybigkey+["merge"]),
priority=priority)
if arg:
- self._args_nodes.add(jbigkey)
- try:
- for set_name, pkg_set in self._sets.iteritems():
- atom = self._find_atom_for_pkg(pkg_set, mykey, metadata)
- if atom:
- self._sets_nodes[set_name].add(jbigkey)
- except portage.exception.InvalidDependString, e:
- if mytype != "installed":
- show_invalid_depstring_notice(jbigkey,
- metadata["PROVIDE"], str(e))
- return 0
- del e
+ self._set_nodes.add(jbigkey)
# Do this even when addme is False (--onlydeps) so that the
# parent/child relationship is always known in case
else:
print "\n\n!!! Binary package '"+str(x)+"' does not exist."
print "!!! Please ensure the tbz2 exists as specified.\n"
- sys.exit(1)
+ return 0, myfavorites
mytbz2=portage.xpak.tbz2(x)
mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.splitext(os.path.basename(x))[0]
if os.path.realpath(x) != \
os.path.realpath(self.trees[myroot]["bintree"].getname(mykey)):
print colorize("BAD", "\n*** You need to adjust PKGDIR to emerge this package.\n")
- sys.exit(1)
+ return 0, myfavorites
if not self.create(["binary", myroot, mykey],
- None, "--onlydeps" not in self.myopts):
+ None, "--onlydeps" not in self.myopts,
+ myuse=mytbz2.getelements("USE"), arg=x):
return (0,myfavorites)
- elif not "--oneshot" in self.myopts:
- myfavorites.append(mykey)
+ arg_atoms.append((x, "="+mykey))
elif ext==".ebuild":
- x = os.path.realpath(x)
- mykey=os.path.basename(os.path.normpath(x+"/../.."))+"/"+os.path.splitext(os.path.basename(x))[0]
+ ebuild_path = portage.util.normalize_path(os.path.abspath(x))
+ pkgdir = os.path.dirname(ebuild_path)
+ tree_root = os.path.dirname(os.path.dirname(pkgdir))
+ cp = pkgdir[len(tree_root)+1:]
+ e = portage.exception.PackageNotFound(
+ ("%s is not in a valid portage tree " + \
+ "hierarchy or does not exist") % x)
+ if not portage.isvalidatom(cp):
+ raise e
+ cat = portage.catsplit(cp)[0]
+ mykey = cat + "/" + os.path.basename(ebuild_path[:-7])
+ if not portage.isvalidatom("="+mykey):
+ raise e
ebuild_path = portdb.findname(mykey)
if ebuild_path:
- if os.path.realpath(ebuild_path) != x:
+ if ebuild_path != os.path.join(os.path.realpath(tree_root),
+ cp, os.path.basename(ebuild_path)):
print colorize("BAD", "\n*** You need to adjust PORTDIR or PORTDIR_OVERLAY to emerge this package.\n")
- sys.exit(1)
+ return 0, myfavorites
if mykey not in portdb.xmatch(
"match-visible", portage.dep_getkey(mykey)):
print colorize("BAD", "\n*** You are emerging a masked package. It is MUCH better to use")
raise portage.exception.PackageNotFound(
"%s is not in a valid portage tree hierarchy or does not exist" % x)
if not self.create(["ebuild", myroot, mykey],
- None, "--onlydeps" not in self.myopts):
+ None, "--onlydeps" not in self.myopts, arg=x):
return (0,myfavorites)
- elif not "--oneshot" in self.myopts:
- myfavorites.append(mykey)
+ arg_atoms.append((x, "="+mykey))
else:
if not is_valid_package_atom(x):
portage.writemsg("\n\n!!! '%s' is not a valid package atom.\n" % x,
greedy_atoms.append((myarg, myslot_atom))
arg_atoms = greedy_atoms
+ oneshot = "--oneshot" in self.myopts or "--onlydeps" in self.myopts
""" These are used inside self.create() in order to ensure packages
that happen to match arguments are not incorrectly marked as nomerge."""
+ args_set = self._sets["args"]
for myarg, myatom in arg_atoms:
- self._args_atoms.setdefault(
- portage.dep_getkey(myatom), []).append(myatom)
+ if myatom in args_set:
+ continue
+ args_set.add(myatom)
+ self._set_atoms.add(myatom)
+ if not oneshot:
+ myfavorites.append(myatom)
for myarg, myatom in arg_atoms:
try:
self.mysd = self.select_dep(myroot, myatom, arg=myarg)
if not self.mysd:
return (0,myfavorites)
- elif not "--oneshot" in self.myopts:
- mykey = portage.dep_getkey(myatom)
- if mykey not in myfavorites:
- myfavorites.append(mykey)
missing=0
if "--usepkgonly" in self.myopts:
if not mymerge and arg:
# A provided package has been specified on the command line. The
# package will not be merged and a warning will be displayed.
- cp = portage.dep_getkey(depstring)
- if cp in self._args_atoms and depstring in self._args_atoms[cp]:
+ if depstring in self._set_atoms:
self._pprovided_args.append((arg, depstring))
if myparent:
if "portage" == portage.catsplit(portage.dep_getkey(cpv))[-1]:
asap_nodes.append(node)
break
- ignore_priority_range = [None]
- ignore_priority_range.extend(
- xrange(DepPriority.MIN, DepPriority.MEDIUM + 1))
+ ignore_priority_soft_range = [None]
+ ignore_priority_soft_range.extend(
+ xrange(DepPriority.MIN, DepPriority.SOFT + 1))
tree_mode = "--tree" in self.myopts
+ # Tracks whether or not the current iteration should prefer asap_nodes
+ # if available. This is set to False when the previous iteration
+ # failed to select any nodes. It is reset whenever nodes are
+ # successfully selected.
+ prefer_asap = True
while not mygraph.empty():
- ignore_priority = None
- nodes = None
- if asap_nodes:
+ selected_nodes = None
+ if prefer_asap and asap_nodes:
"""ASAP nodes are merged before their soft deps."""
+ asap_nodes = [node for node in asap_nodes \
+ if mygraph.contains(node)]
for node in asap_nodes:
- if not mygraph.contains(node):
- asap_nodes.remove(node)
- continue
if not mygraph.child_nodes(node,
ignore_priority=DepPriority.SOFT):
- nodes = [node]
+ selected_nodes = [node]
asap_nodes.remove(node)
break
- if not nodes:
- for ignore_priority in ignore_priority_range:
+ if not selected_nodes and \
+ not (prefer_asap and asap_nodes):
+ for ignore_priority in ignore_priority_soft_range:
nodes = get_nodes(ignore_priority=ignore_priority)
if nodes:
break
- selected_nodes = None
- if nodes:
- if ignore_priority <= DepPriority.SOFT:
+ if nodes:
if ignore_priority is None and not tree_mode:
# Greedily pop all of these nodes since no relationship
# has been ignored. This optimization destroys --tree
if not selected_nodes:
# settle for a root node
selected_nodes = [nodes[0]]
- else:
+ if not selected_nodes:
+ nodes = get_nodes(ignore_priority=DepPriority.MEDIUM)
+ if nodes:
"""Recursively gather a group of nodes that RDEPEND on
eachother. This ensures that they are merged as a group
and get their RDEPENDs satisfied as soon as possible."""
return False
return True
mergeable_nodes = set(nodes)
+ if prefer_asap and asap_nodes:
+ nodes = asap_nodes
for ignore_priority in xrange(DepPriority.SOFT,
DepPriority.MEDIUM_SOFT + 1):
for node in nodes:
if selected_nodes:
break
+ if prefer_asap and asap_nodes and not selected_nodes:
+ # We failed to find any asap nodes to merge, so ignore
+ # them for the next iteration.
+ prefer_asap = False
+ continue
+
if selected_nodes and ignore_priority > DepPriority.SOFT:
# Try to merge ignored medium deps as soon as possible.
for node in selected_nodes:
for child in medium_soft:
if child in selected_nodes:
continue
+ if child in asap_nodes:
+ continue
# TODO: Try harder to make these nodes get
# merged absolutely as soon as possible.
asap_nodes.append(child)
print "!!! disabling USE flags that trigger optional dependencies."
sys.exit(1)
+ # At this point, we've succeeded in selecting one or more nodes, so
+ # it's now safe to reset the prefer_asap to it's default state.
+ prefer_asap = True
+
for node in selected_nodes:
retlist.append(list(node))
mygraph.remove(node)
matches = portdb.gvisible(portdb.visible(mylist))
return [x for x in mylist \
if x in matches or not portdb.cpv_exists(x)]
- def create_cp_dict(atom_list):
- cp_dict = {}
- for atom in atom_list:
- cp_dict.setdefault(portage.dep_getkey(atom), []).append(atom)
- return cp_dict
world_problems = False
- if mode=="system":
- mylist = getlist(self.settings, "system")
- self._sets["system"] = create_cp_dict(mylist)
- self._sets_nodes["system"] = set()
- else:
- #world mode
- worldlist = getlist(self.settings, "world")
- self._sets["world"] = create_cp_dict(worldlist)
- self._sets_nodes["world"] = set()
- mylist = getlist(self.settings, "system")
- self._sets["system"] = create_cp_dict(mylist)
- self._sets_nodes["system"] = set()
- worlddict=genericdict(worldlist)
-
- for x in worlddict:
+
+ root_config = self.roots[self.target_root]
+ world_set = root_config.sets["world"]
+ system_set = root_config.sets["system"]
+ mylist = list(system_set)
+ self._sets["system"] = system_set
+ if mode == "world":
+ self._sets["world"] = world_set
+ for x in world_set:
if not portage.isvalidatom(x):
world_problems = True
continue
mykey = portage.dep_getkey(atom)
if True:
newlist.append(atom)
- """Make sure all installed slots are updated when possible.
- Do this with --emptytree also, to ensure that all slots are
- remerged."""
+ if mode == "system" or atom not in world_set:
+ # only world is greedy for slots, not system
+ continue
+ # Make sure all installed slots are updated when possible.
+ # Do this with --emptytree also, to ensure that all slots are
+ # remerged.
myslots = set()
for cpv in vardb.match(mykey):
myslots.add(vardb.aux_get(cpv, ["SLOT"])[0])
mylist = newlist
for myatom in mylist:
- self._args_atoms.setdefault(
- portage.dep_getkey(myatom), []).append(myatom)
+ self._set_atoms.add(myatom)
missing_atoms = []
for mydep in mylist:
return 1
- def _find_atom_for_pkg(self, pkg_set, cpv, metadata):
- """Return the best match for a given package from the arguments, or
- None if there are no matches. This matches virtual arguments against
- the PROVIDE metadata. This can raise an InvalidDependString exception
- if an error occurs while parsing PROVIDE."""
- cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
- cp = portage.dep_getkey(cpv)
- atoms = pkg_set.get(cp)
- if atoms:
- best_match = portage.best_match_to_list(cpv_slot, atoms)
- if best_match:
- return best_match
- provides = portage.flatten(portage.dep.use_reduce(
- portage.dep.paren_reduce(metadata["PROVIDE"]),
- uselist=metadata["USE"].split()))
- for provide in provides:
- provided_cp = portage.dep_getkey(provide)
- atoms = pkg_set.get(provided_cp)
- if atoms:
- transformed_atoms = [atom.replace(provided_cp, cp) for atom in atoms]
- best_match = portage.best_match_to_list(cpv_slot, transformed_atoms)
- if best_match:
- return atoms[transformed_atoms.index(best_match)]
- return None
-
- def display(self,mylist,verbosity=None):
+ def display(self, mylist, favorites=[], verbosity=None):
if verbosity is None:
verbosity = ("--quiet" in self.myopts and 1 or \
"--verbose" in self.myopts and 3 or 2)
+ if "--resume" in self.myopts and favorites:
+ self._sets["args"].update(favorites)
+ favorites_set = AtomSet()
+ favorites_set.update(favorites)
changelogs=[]
p=[]
blockers = []
# Do not traverse to parents if this node is an
# an argument or a direct member of a set that has
# been specified as an argument (system or world).
- if current_node not in self._args_nodes:
+ if current_node not in self._set_nodes:
parent_nodes = mygraph.parent_nodes(current_node)
if parent_nodes:
child_nodes = set(mygraph.child_nodes(current_node))
else:
# An ebuild "nomerge" node, so USE come from the vardb.
mydbapi = vartree.dbapi
+ # reuse cached metadata from when the depgraph was built
+ if "--resume" in self.myopts:
+ # Populate the fakedb with relevant metadata, just like
+ # would have happened when the depgraph was originally
+ # built.
+ metadata = dict(izip(self._mydbapi_keys,
+ mydbapi.aux_get(pkg_key, self._mydbapi_keys)))
+ self.mydbapi[myroot].cpv_inject(pkg_key, metadata=metadata)
+ else:
+ metadata = dict(izip(self._mydbapi_keys,
+ self.mydbapi[myroot].aux_get(
+ pkg_key, self._mydbapi_keys)))
+ mydbapi = self.mydbapi[myroot] # use the cached metadata
if pkg_key not in self.useFlags[myroot]:
"""If this is a --resume then the USE flags need to be
fetched from the appropriate locations here."""
restrict = mydbapi.aux_get(pkg_key, ["RESTRICT"])[0]
show_invalid_depstring_notice(x, restrict, str(e))
del e
- sys.exit(1)
+ return 1
restrict = []
if "ebuild" == pkg_type and x[3] != "nomerge" and \
"fetch" in restrict:
src_uri = portdb.aux_get(pkg_key, ["SRC_URI"])[0]
show_invalid_depstring_notice(x, src_uri, str(e))
del e
- sys.exit(1)
+ return 1
if myfilesdict is None:
myfilesdict="[empty/missing/bad digest]"
else:
myoldbest=blue("["+myoldbest+"]")
pkg_cp = xs[0]
- pkg_arg = False
- pkg_world = False
+ root_config = self.roots[myroot]
+ system_set = root_config.sets["system"]
+ world_set = root_config.sets["world"]
+
pkg_system = False
- pkg_node = tuple(x)
- if pkg_node in self._args_nodes:
- pkg_arg = True
- world_nodes = self._sets_nodes.get("world")
- if world_nodes and pkg_node in world_nodes:
- pkg_world = True
- if world_nodes is None:
- # Don't colorize system package when in "world" mode.
- system_nodes = self._sets_nodes.get("system")
- if system_nodes and pkg_node in system_nodes:
- pkg_system = True
+ pkg_world = False
+ try:
+ pkg_system = system_set.findAtomForPackage(pkg_key, metadata)
+ pkg_world = world_set.findAtomForPackage(pkg_key, metadata)
+ if not pkg_world and myroot == self.target_root and \
+ favorites_set.findAtomForPackage(pkg_key, metadata):
+ # Maybe it will be added to world now.
+ if create_world_atom(pkg_key, metadata,
+ favorites_set, root_config.sets, portdb):
+ pkg_world = True
+ except portage.exception.InvalidDependString:
+ # This is reported elsewhere if relevant.
+ pass
def pkgprint(pkg):
if pkg_merge:
- if pkg_arg:
- if pkg_world:
- return colorize("PKG_MERGE_WORLD", pkg)
- elif pkg_system:
- return colorize("PKG_MERGE_SYSTEM", pkg)
- else:
- return colorize("PKG_MERGE_ARG", pkg)
+ if pkg_world:
+ return colorize("PKG_MERGE_WORLD", pkg)
+ elif pkg_system:
+ return colorize("PKG_MERGE_SYSTEM", pkg)
else:
return colorize("PKG_MERGE", pkg)
else:
- if pkg_arg:
- if pkg_world:
- return colorize("PKG_NOMERGE_WORLD", pkg)
- elif pkg_system:
- return colorize("PKG_NOMERGE_SYSTEM", pkg)
- else:
- return colorize("PKG_NOMERGE_ARG", pkg)
+ if pkg_world:
+ return colorize("PKG_NOMERGE_WORLD", pkg)
+ elif pkg_system:
+ return colorize("PKG_NOMERGE_SYSTEM", pkg)
else:
return colorize("PKG_NOMERGE", pkg)
arg, atom = arg_atom
arg_refs[arg_atom] = []
cp = portage.dep_getkey(atom)
- for set_name, pkg_set in self._sets.iteritems():
- if cp in pkg_set and atom in pkg_set[cp]:
+ for set_name, atom_set in self._sets.iteritems():
+ if atom in atom_set:
arg_refs[arg_atom].append(set_name)
msg = []
msg.append(bad("\nWARNING: "))
msg.append("The best course of action depends on the reason that an offending\n")
msg.append("package.provided entry exists.\n\n")
sys.stderr.write("".join(msg))
+ return os.EX_OK
def calc_changelog(self,ebuildpath,current,next):
if ebuildpath == None or not os.path.exists(ebuildpath):
if release.endswith('-r0'):
release = release[:-3]
- def outdated(self):
- return self.outdatedpackages
+ def saveNomergeFavorites(self):
+ """Find atoms in favorites that are not in the mergelist and add them
+ to the world file if necessary."""
+ for x in ("--fetchonly", "--fetch-all-uri",
+ "--oneshot", "--onlydeps", "--pretend"):
+ if x in self.myopts:
+ return
+ root_config = self.roots[self.target_root]
+ world_set = root_config.sets["world"]
+ world_set.lock()
+ world_set.load()
+ args_set = self._sets["args"]
+ portdb = self.trees[self.target_root]["porttree"].dbapi
+ added_favorites = set()
+ for x in self._set_nodes:
+ pkg_type, root, pkg_key, pkg_status = x
+ if pkg_status != "nomerge":
+ continue
+ metadata = dict(izip(self._mydbapi_keys,
+ self.mydbapi[root].aux_get(pkg_key, self._mydbapi_keys)))
+ try:
+ myfavkey = create_world_atom(pkg_key, metadata,
+ args_set, root_config.sets, portdb)
+ if myfavkey:
+ if myfavkey in added_favorites:
+ continue
+ added_favorites.add(myfavkey)
+ world_set.add(myfavkey)
+ print ">>> Recording",myfavkey,"in \"world\" favorites file..."
+ except portage.exception.InvalidDependString, e:
+ writemsg("\n\n!!! '%s' has invalid PROVIDE: %s\n" % \
+ (pkg_key, str(e)), noiselevel=-1)
+ writemsg("!!! see '%s'\n\n" % os.path.join(
+ root, portage.VDB_PATH, pkg_key, "PROVIDE"), noiselevel=-1)
+ del e
+ if added_favorites:
+ world_set.save()
+ world_set.unlock()
class PackageCounters(object):
def merge(self, mylist, favorites, mtimedb):
from portage.elog import elog_process
+ from portage.elog.filtering import filter_mergephases
failed_fetches = []
fetchonly = "--fetchonly" in self.myopts or \
"--fetch-all-uri" in self.myopts
+ pretend = "--pretend" in self.myopts
mymergelist=[]
ldpath_mtimes = mtimedb["ldpath"]
xterm_titles = "notitles" not in self.settings.features
del x, mytype, myroot, mycpv, mystatus, quiet_config
del shown_verifying_msg, quiet_settings
- #buildsyspkg: I need mysysdict also on resume (moved from the else block)
- mysysdict = genericdict(getlist(self.settings, "system"))
+ system_set = SystemSet(self.settings)
+ args_set = AtomSet(favorites)
+ world_set = WorldSet(self.settings)
if "--resume" not in self.myopts:
- myfavs = portage.grabfile(
- os.path.join(self.target_root, portage.WORLD_FILE))
- myfavdict=genericdict(myfavs)
- for x in range(len(mylist)):
- if mylist[x][3]!="nomerge":
- # Add to the mergelist
- mymergelist.append(mylist[x])
- else:
- myfavkey=portage.cpv_getkey(mylist[x][2])
- if "--onlydeps" in self.myopts:
- continue
- # Add to the world file. Since we won't be able to later.
- if "--fetchonly" not in self.myopts and \
- myfavkey in favorites:
- #don't record if already in system profile or already recorded
- if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)):
- #we don't have a favorites entry for this package yet; add one
- myfavdict[myfavkey]=myfavkey
- print ">>> Recording",myfavkey,"in \"world\" favorites file..."
- if not ("--fetchonly" in self.myopts or \
- "--fetch-all-uri" in self.myopts or \
- "--pretend" in self.myopts):
- portage.write_atomic(
- os.path.join(self.target_root, portage.WORLD_FILE),
- "\n".join(sorted(myfavdict.values())) + "\n")
-
+ mymergelist = mylist
mtimedb["resume"]["mergelist"]=mymergelist[:]
mtimedb.commit()
del fetch_log, logfile, fd_pipes, fetch_env, fetch_args, \
resume_opts
+ metadata_keys = [k for k in portage.auxdbkeys \
+ if not k.startswith("UNUSED_")] + ["USE"]
+
mergecount=0
for x in mymergelist:
mergecount+=1
+ pkg_type = x[0]
myroot=x[1]
pkg_key = x[2]
pkgindex=2
bindb = self.trees[myroot]["bintree"].dbapi
vartree = self.trees[myroot]["vartree"]
pkgsettings = self.pkgsettings[myroot]
+ metadata = {}
+ if pkg_type == "blocks":
+ pass
+ elif pkg_type == "ebuild":
+ mydbapi = portdb
+ metadata.update(izip(metadata_keys,
+ mydbapi.aux_get(pkg_key, metadata_keys)))
+ pkgsettings.setcpv(pkg_key, mydb=mydbapi)
+ metadata["USE"] = pkgsettings["USE"]
+ else:
+ if pkg_type == "binary":
+ mydbapi = bindb
+ else:
+ raise AssertionError("Package type: '%s'" % pkg_type)
+ metadata.update(izip(metadata_keys,
+ mydbapi.aux_get(pkg_key, metadata_keys)))
if x[0]=="blocks":
pkgindex=3
y = portdb.findname(pkg_key)
#buildsyspkg: Check if we need to _force_ binary package creation
issyspkg = ("buildsyspkg" in myfeat) \
and x[0] != "blocks" \
- and mysysdict.has_key(portage.cpv_getkey(x[2])) \
+ and system_set.findAtomForPackage(pkg_key, metadata) \
and "--buildpkg" not in self.myopts
if x[0] in ["ebuild","blocks"]:
if x[0] == "blocks" and "--fetchonly" not in self.myopts:
del pkgsettings["PORTAGE_BINPKG_TMPFILE"]
if retval != os.EX_OK or \
"--buildpkgonly" in self.myopts:
- elog_process(pkg_key, pkgsettings)
+ elog_process(pkg_key, pkgsettings, phasefilter=filter_mergephases)
if retval != os.EX_OK:
return retval
bintree = self.trees[myroot]["bintree"]
#need to check for errors
if "--buildpkgonly" not in self.myopts:
self.trees[x[1]]["vartree"].inject(x[2])
- myfavkey=portage.cpv_getkey(x[2])
- if "--fetchonly" not in self.myopts and \
- "--fetch-all-uri" not in self.myopts and \
- myfavkey in favorites:
- myfavs = portage.grabfile(os.path.join(myroot, portage.WORLD_FILE))
- myfavdict=genericdict(myfavs)
- #don't record if already in system profile or already recorded
- if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)):
- #we don't have a favorites entry for this package yet; add one
- myfavdict[myfavkey]=myfavkey
+ myfavkey = portage.cpv_getkey(x[2])
+ if not fetchonly and not pretend and \
+ args_set.findAtomForPackage(pkg_key, metadata):
+ world_set.lock()
+ world_set.load()
+ myfavkey = create_world_atom(pkg_key, metadata,
+ args_set, {"world":world_set, "system":system_set},
+ portdb)
+ if myfavkey:
+ world_set.add(myfavkey)
print ">>> Recording",myfavkey,"in \"world\" favorites file..."
emergelog(xterm_titles, " === ("+\
str(mergecount)+" of "+\
str(len(mymergelist))+\
") Updating world file ("+x[pkgindex]+")")
- portage.write_atomic(
- os.path.join(myroot, portage.WORLD_FILE),
- "\n".join(sorted(myfavdict.values()))+"\n")
+ world_set.save()
+ world_set.unlock()
if "--pretend" not in self.myopts and \
"--fetchonly" not in self.myopts and \
if "--pretend" not in myopts and "--ask" not in myopts:
countdown(int(settings["EMERGE_WARNING_DELAY"]),
colorize("UNMERGE_WARN", "Press Ctrl-C to Stop"))
- print "\n "+white(x)
+ if "--quiet" not in myopts:
+ print "\n "+white(x)
+ else:
+ print white(x)+": ",
for mytype in ["selected","protected","omitted"]:
- portage.writemsg_stdout((mytype + ": ").rjust(14), noiselevel=-1)
+ if "--quiet" not in myopts:
+ portage.writemsg_stdout((mytype + ": ").rjust(14), noiselevel=-1)
if pkgmap[x][mytype]:
for mypkg in pkgmap[x][mytype]:
mysplit=portage.catpkgsplit(mypkg)
portage.writemsg_stdout(
colorize("GOOD", myversion + " "), noiselevel=-1)
else:
- portage.writemsg_stdout("none", noiselevel=-1)
+ portage.writemsg_stdout("none ", noiselevel=-1)
+ if "--quiet" not in myopts:
+ portage.writemsg_stdout("\n", noiselevel=-1)
+ if "--quiet" in myopts:
portage.writemsg_stdout("\n", noiselevel=-1)
portage.writemsg_stdout("\n>>> " + colorize("UNMERGE_WARN", "'Selected'") + \
print
print red(" * ")+bold("An update to portage is available.")+" It is _highly_ recommended"
print red(" * ")+"that you update portage now, before any other packages are updated."
- print red(" * ")+"Please run 'emerge portage' and then update "+bold("ALL")+" of your"
- print red(" * ")+"configuration files."
- print red(" * ")+"To update portage, run 'emerge portage'."
+ print
+ print red(" * ")+"To update portage, run 'emerge portage' now."
print
display_news_notification(trees)
vardb = dep_check_trees[myroot]["vartree"].dbapi
# Constrain dependency selection to the installed packages.
dep_check_trees[myroot]["porttree"] = dep_check_trees[myroot]["vartree"]
- syslist = getlist(settings, "system")
- worldlist = getlist(settings, "world")
- system_world_dict = genericdict(worldlist)
- system_world_dict.update(genericdict(syslist))
+ system_set = SystemSet(settings)
+ syslist = list(system_set)
+ world_set = WorldSet(settings)
+ world_set.load()
+ worldlist = list(world_set)
fakedb = portage.fakedbapi(settings=settings)
myvarlist = vardb.cpv_all()
remaining_atoms += [(atom, 'system', hard) for atom in syslist if vardb.match(atom)]
unresolveable = {}
aux_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
+ metadata_keys = ["PROVIDE", "SLOT", "USE"]
while remaining_atoms:
atom, parent, priority = remaining_atoms.pop()
if not atom.startswith("!") and priority == hard:
unresolveable.setdefault(atom, []).append(parent)
continue
- if portage.dep_getkey(atom) not in system_world_dict:
+ if len(pkgs) > 1 and parent != "world":
# Prune all but the best matching slot, since that's all that a
- # deep world update would pull in. Don't prune if the cpv is in
- # system or world though, since those sets trigger greedy update
- # of all slots.
+ # deep world update would pull in. Don't prune if this atom comes
+ # directly from world though, since world atoms are greedy when
+ # they don't specify a slot.
pkgs = [portage.best(pkgs)]
for pkg in pkgs:
if fakedb.cpv_exists(pkg):
else:
if ("--resume" in myopts):
print darkgreen("emerge: It seems we have nothing to resume...")
- sys.exit(0)
+ return os.EX_OK
myparams = create_depgraph_params(myopts, myaction)
if myaction in ["system","world"]:
mydepgraph = depgraph(settings, trees, myopts, myparams, spinner)
if not mydepgraph.xcreate(myaction):
print "!!! Depgraph creation failed."
- sys.exit(1)
+ return 1
if "--quiet" not in myopts and "--nodeps" not in myopts:
print "\b\b... done!"
else:
retval, favorites = mydepgraph.select_files(myfiles)
except portage.exception.PackageNotFound, e:
portage.writemsg("\n!!! %s\n" % str(e), noiselevel=-1)
- sys.exit(1)
+ return 1
if not retval:
- sys.exit(1)
+ return 1
if "--quiet" not in myopts and "--nodeps" not in myopts:
print "\b\b... done!"
for x in mydepgraph.missingbins:
sys.stderr.write(" "+str(x)+"\n")
sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n")
- sys.exit(1)
+ return 1
if "--pretend" not in myopts and \
("--ask" in myopts or "--tree" in myopts or \
mymergelist = mymergelist[1:]
if len(mymergelist) == 0:
print colorize("INFORM", "emerge: It seems we have nothing to resume...")
- sys.exit(0)
- mydepgraph.display(mymergelist)
+ return os.EX_OK
+ favorites = mtimedb["resume"]["favorites"]
+ retval = mydepgraph.display(mymergelist, favorites=favorites)
+ if retval != os.EX_OK:
+ return retval
prompt="Would you like to resume merging these packages?"
else:
- mydepgraph.display(
- mydepgraph.altlist(reversed=("--tree" in myopts)))
+ retval = mydepgraph.display(
+ mydepgraph.altlist(reversed=("--tree" in myopts)),
+ favorites=favorites)
+ if retval != os.EX_OK:
+ return retval
mergecount=0
for x in mydepgraph.altlist():
if x[0] != "blocks" and x[3] != "nomerge":
print "!!! at the same time on the same system."
if "--quiet" not in myopts:
show_blocker_docs_link()
- sys.exit(1)
+ return 1
if mergecount==0:
if "--noreplace" in myopts and favorites:
print
print
print "Nothing to merge; quitting."
print
- sys.exit(0)
+ return os.EX_OK
elif "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
prompt="Would you like to fetch the source files for these packages?"
else:
print
print "Quitting."
print
- sys.exit(0)
+ return os.EX_OK
# Don't ask again (e.g. when auto-cleaning packages after merge)
myopts.pop("--ask", None)
mymergelist = mymergelist[1:]
if len(mymergelist) == 0:
print colorize("INFORM", "emerge: It seems we have nothing to resume...")
- sys.exit(0)
- mydepgraph.display(mymergelist)
+ return os.EX_OK
+ favorites = mtimedb["resume"]["favorites"]
+ retval = mydepgraph.display(mymergelist, favorites=favorites)
+ if retval != os.EX_OK:
+ return retval
else:
- mydepgraph.display(
- mydepgraph.altlist(reversed=("--tree" in myopts)))
+ retval = mydepgraph.display(
+ mydepgraph.altlist(reversed=("--tree" in myopts)),
+ favorites=favorites)
+ if retval != os.EX_OK:
+ return retval
if "--buildpkgonly" in myopts and \
not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM):
print "\n!!! --buildpkgonly requires all dependencies to be merged."
print "!!! You have to merge the dependencies before you can build this package.\n"
- sys.exit(1)
+ return 1
else:
if ("--buildpkgonly" in myopts):
if not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM):
print "\n!!! --buildpkgonly requires all dependencies to be merged."
print "!!! Cannot merge requested packages. Merge deps and try again.\n"
- sys.exit(1)
+ return 1
if ("--resume" in myopts):
favorites=mtimedb["resume"]["favorites"]
retval = mergetask.merge(
mtimedb["resume"]["mergelist"], favorites, mtimedb)
if retval != os.EX_OK:
- sys.exit(retval)
+ return retval
else:
if "resume" in mtimedb and \
"mergelist" in mtimedb["resume"] and \
pkglist.append(pkg)
else:
pkglist = mydepgraph.altlist()
+ if favorites:
+ mydepgraph.saveNomergeFavorites()
del mydepgraph
mergetask = MergeTask(settings, trees, myopts)
retval = mergetask.merge(pkglist, favorites, mtimedb)
if retval != os.EX_OK:
- sys.exit(retval)
+ return retval
if mtimedb.has_key("resume"):
del mtimedb["resume"]
for x in myfiles:
ext = os.path.splitext(x)[1]
if (ext == ".ebuild" or ext == ".tbz2") and os.path.exists(os.path.abspath(x)):
- print "emerging by path implies --oneshot... adding --oneshot to options."
print colorize("BAD", "\n*** emerging by path is broken and may not always work!!!\n")
break
validate_ebuild_environment(trees)
if "--pretend" not in myopts:
display_news_notification(trees)
- action_build(settings, trees, mtimedb,
+ retval = action_build(settings, trees, mtimedb,
myopts, myaction, myfiles, spinner)
if "--pretend" not in myopts:
- post_emerge(trees, mtimedb, os.EX_OK)
+ post_emerge(trees, mtimedb, retval)
else:
display_news_notification(trees)
+ return retval
if __name__ == "__main__":
retval = emerge_main()