import tempfile
import time
import platform
+import urllib
from io import StringIO
from itertools import chain
"x11-misc/imake",
])
+metadata_dtd_uri = 'http://www.gentoo.org/dtd/metadata.dtd'
+# force refetch if the local copy creation time is older than this
+metadata_dtd_ctime_interval = 60 * 60 * 24 * 7 # 7 days
+
# file.executable
no_exec = frozenset(["Manifest","ChangeLog","metadata.xml"])
for x in qacats:
stats[x]=0
fails[x]=[]
+
xmllint_capable = False
metadata_dtd = os.path.join(repoman_settings["DISTDIR"], 'metadata.dtd')
-if options.mode == "manifest":
- pass
-elif not find_binary('xmllint'):
- print(red("!!! xmllint not found. Can't check metadata.xml.\n"))
- if options.xml_parse or repolevel==3:
- print(red("!!!")+" sorry, xmllint is needed. failing\n")
- sys.exit(1)
-else:
- #hardcoded paths/urls suck. :-/
- must_fetch=1
- backup_exists=0
- try:
- # if it's been over a week since fetching (or the system clock is fscked), grab an updated copy of metadata.dtd
- # clock is fscked or it's been a week. time to grab a new one.
- ct = os.stat(metadata_dtd)[ST_CTIME]
- if abs(time.time() - ct) > (60*60*24*7):
- # don't trap the exception, we're watching for errno 2 (file not found), anything else is a bug.
- backup_exists=1
- else:
- must_fetch=0
- except (OSError,IOError) as e:
- if e.errno != 2:
- print(red("!!!")+" caught exception '%s' for %s/metadata.dtd, bailing" % (str(e), portage.CACHE_PATH))
- sys.exit(1)
+def fetch_metadata_dtd():
+ """
+ Fetch metadata.dtd if it doesn't exist or the ctime is older than
+ metadata_dtd_ctime_interval.
+ @rtype: bool
+ @returns: True if successful, otherwise False
+ """
+
+ must_fetch = True
+ metadata_dtd_st = None
+ current_time = int(time.time())
+ try:
+ metadata_dtd_st = os.stat(metadata_dtd)
+ except EnvironmentError as e:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
+ raise
+ del e
+ else:
+ # Trigger fetch if metadata.dtd mtime is old or clock is wrong.
+ if abs(current_time - metadata_dtd_st.st_ctime) \
+ < metadata_dtd_ctime_interval:
+ must_fetch = False
if must_fetch:
- print()
- print(green("***")+" the local copy of metadata.dtd needs to be refetched, doing that now")
print()
- val = 0
+ print(green("***") + " the local copy of metadata.dtd " + \
+ "needs to be refetched, doing that now")
+ print()
try:
+ url_f = urllib.urlopen(metadata_dtd_uri)
+ last_modified = url_f.info().getdate('last-modified')
+ if last_modified is not None:
+ last_modified = time.mktime(last_modified)
+
+ metadata_dtd_tmp = "%s.%s" % (metadata_dtd, os.getpid())
try:
- os.unlink(metadata_dtd)
- except OSError as e:
- if e.errno != errno.ENOENT:
- raise
- del e
- val=portage.fetch(['http://www.gentoo.org/dtd/metadata.dtd'],repoman_settings,fetchonly=0, \
- try_mirrors=0)
+ local_f = open(metadata_dtd_tmp, mode='wb')
+ local_f.write(url_f.read())
+ local_f.close()
+ if last_modified is not None:
+ os.utime(metadata_dtd_tmp,
+ (int(last_modified), int(last_modified)))
+ os.rename(metadata_dtd_tmp, metadata_dtd)
+ finally:
+ try:
+ os.unlink(metadata_dtd_tmp)
+ except OSError:
+ pass
- except SystemExit as e:
- raise # Need to propogate this
- except Exception as e:
+ url_f.close()
+
+ except EnvironmentError as e:
print()
- print(red("!!!")+" attempting to fetch 'http://www.gentoo.org/dtd/metadata.dtd', caught")
- print(red("!!!")+" exception '%s' though." % str(e))
- val=0
- if not val:
+ print(red("!!!")+" attempting to fetch '%s', caught" % metadata_dtd_uri)
+ print(red("!!!")+" exception '%s' though." % (e,))
print(red("!!!")+" fetching new metadata.dtd failed, aborting")
- sys.exit(1)
+ return False
+
+ return True
+
+if options.mode == "manifest":
+ pass
+elif not find_binary('xmllint'):
+ print(red("!!! xmllint not found. Can't check metadata.xml.\n"))
+ if options.xml_parse or repolevel==3:
+ print(red("!!!")+" sorry, xmllint is needed. failing\n")
+ sys.exit(1)
+else:
+ if not fetch_metadata_dtd():
+ sys.exit(1)
#this can be problematic if xmllint changes their output
xmllint_capable=True
pretend = "--pretend" in myopts
fetchonly = "--fetchonly" in myopts or "--fetch-all-uri" in myopts
ask = "--ask" in myopts
+ enter_invalid = '--ask-enter-invalid' in myopts
nodeps = "--nodeps" in myopts
oneshot = "--oneshot" in myopts or "--onlydeps" in myopts
tree = "--tree" in myopts
writemsg("%s%s\n" % (prefix, line))
writemsg(prefix + "\n")
- if "--quiet" not in myopts and \
- ("--pretend" in myopts or "--ask" in myopts or \
- "--tree" in myopts or "--verbose" in myopts):
- action = ""
- if "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
- action = "fetched"
- elif "--buildpkgonly" in myopts:
- action = "built"
- else:
- action = "merged"
- if "--tree" in myopts and action != "fetched": # Tree doesn't work with fetching
- print()
- print(darkgreen("These are the packages that would be %s, in reverse order:") % action)
- print()
- else:
- print()
- print(darkgreen("These are the packages that would be %s, in order:") % action)
- print()
-
- show_spinner = "--quiet" not in myopts and "--nodeps" not in myopts
- if not show_spinner:
- spinner.update = spinner.update_quiet
-
if resume:
favorites = mtimedb["resume"].get("favorites")
if not isinstance(favorites, list):
favorites = []
-
- if show_spinner:
- print("Calculating dependencies ", end=' ')
myparams = create_depgraph_params(myopts, myaction)
resume_data = mtimedb["resume"]
depgraph.UnsatisfiedResumeDep) as e:
if isinstance(e, depgraph.UnsatisfiedResumeDep):
mydepgraph = e.depgraph
- if show_spinner:
- print()
+
from textwrap import wrap
from portage.output import EOutput
out = EOutput()
"the operation manually."
for line in wrap(msg, 72):
out.eerror(line)
- else:
- if show_spinner:
- print("\b\b... done!")
if success:
if dropped_tasks:
print(darkgreen("emerge: It seems we have nothing to resume..."))
return os.EX_OK
- if "--quiet" not in myopts and "--nodeps" not in myopts:
- print("Calculating dependencies ", end=' ')
- sys.stdout.flush()
-
myparams = create_depgraph_params(myopts, myaction)
try:
success, mydepgraph, favorites = backtrack_depgraph(
settings, trees, myopts, myparams, myaction, myfiles, spinner)
except portage.exception.PackageSetNotFound as e:
- if show_spinner:
- print("\b\b... done!")
root_config = trees[settings["ROOT"]]["root_config"]
display_missing_pkg_set(root_config, e.value)
return 1
- if show_spinner:
- print("\b\b... done!")
-
if not success:
mydepgraph.display_problems()
return 1
else:
prompt="Would you like to merge these packages?"
print()
- if "--ask" in myopts and userquery(prompt) == "No":
+ if "--ask" in myopts and userquery(prompt, enter_invalid) == "No":
print()
print("Quitting.")
print()
return retval
def action_config(settings, trees, myopts, myfiles):
+ enter_invalid = '--ask-enter-invalid' in myopts
if len(myfiles) != 1:
print(red("!!! config can only take a single package atom at this time\n"))
sys.exit(1)
print(options[-1]+") "+pkg)
print("X) Cancel")
options.append("X")
- idx = userquery("Selection?", options)
+ idx = userquery("Selection?", enter_invalid, responses=options)
if idx == "X":
sys.exit(0)
pkg = pkgs[int(idx)-1]
print()
if "--ask" in myopts:
- if userquery("Ready to configure "+pkg+"?") == "No":
+ if userquery("Ready to configure %s?" % pkg, enter_invalid) == "No":
sys.exit(0)
else:
print("Configuring pkg...")
return 0, [], False, required_pkgs_total
def action_deselect(settings, trees, opts, atoms):
+ enter_invalid = '--ask-enter-invalid' in opts
root_config = trees[settings['ROOT']]['root_config']
world_set = root_config.sets['selected']
if not hasattr(world_set, 'update'):
if '--ask' in opts:
prompt = "Would you like to remove these " + \
"packages from your world favorites?"
- if userquery(prompt) == 'No':
+ if userquery(prompt, enter_invalid) == 'No':
return os.EX_OK
remaining = set(world_set)
searchinstance.output()
def action_sync(settings, trees, mtimedb, myopts, myaction):
+ enter_invalid = '--ask-enter-invalid' in myopts
xterm_titles = "notitles" not in settings.features
emergelog(xterm_titles, " === sync")
portdb = trees[settings["ROOT"]]["porttree"].dbapi
if (retries==0):
if "--ask" in myopts:
- if userquery("Do you want to sync your Portage tree with the mirror at\n" + blue(dosyncuri) + bold("?"))=="No":
+ if userquery("Do you want to sync your Portage tree " + \
+ "with the mirror at\n" + blue(dosyncuri) + bold("?"),
+ enter_invalid) == "No":
print()
print("Quitting.")
print()
def __init__(self, depgraph, myparams, allow_backtracking,
runtime_pkg_mask):
self.myparams = myparams.copy()
+ self._vdb_loaded = False
self._allow_backtracking = allow_backtracking
# Maps slot atom to package for each Package added to the graph.
self._slot_pkg_map = {}
for myroot in depgraph._frozen_config.trees:
self._slot_pkg_map[myroot] = {}
vardb = depgraph._frozen_config.trees[myroot]["vartree"].dbapi
- preload_installed_pkgs = \
- "--nodeps" not in depgraph._frozen_config.myopts and \
- "--buildpkgonly" not in depgraph._frozen_config.myopts
- # This fakedbapi instance will model the state that the vdb will
+ # This dbapi instance will model the state that the vdb will
# have after new packages have been installed.
fakedb = PackageVirtualDbapi(vardb.settings)
- if preload_installed_pkgs:
- for pkg in vardb:
- depgraph._spinner_update()
- # This triggers metadata updates via FakeVartree.
- vardb.aux_get(pkg.cpv, [])
- fakedb.cpv_inject(pkg)
-
- # Now that the vardb state is cached in our FakeVartree,
- # we won't be needing the real vartree cache for awhile.
- # To make some room on the heap, clear the vardbapi
- # caches.
- depgraph._frozen_config._trees_orig[myroot
- ]["vartree"].dbapi._clear_cache()
- gc.collect()
self.mydbapi[myroot] = fakedb
def graph_tree():
self._select_atoms = self._select_atoms_highest_available
self._select_package = self._select_pkg_highest_available
+ def _load_vdb(self):
+ """
+ Load installed package metadata if appropriate. This used to be called
+ from the constructor, but that wasn't very nice since this procedure
+ is slow and it generates spinner output. So, now it's called on-demand
+ by various methods when necessary.
+ """
+
+ if self._dynamic_config._vdb_loaded:
+ return
+
+ for myroot in self._frozen_config.trees:
+
+ preload_installed_pkgs = \
+ "--nodeps" not in self._frozen_config.myopts and \
+ "--buildpkgonly" not in self._frozen_config.myopts
+
+ if preload_installed_pkgs:
+ fakedb = self._dynamic_config._graph_trees[
+ myroot]["vartree"].dbapi
+ vardb = self._frozen_config.trees[myroot]["vartree"].dbapi
+ for pkg in vardb:
+ self._spinner_update()
+ # This triggers metadata updates via FakeVartree.
+ vardb.aux_get(pkg.cpv, [])
+ fakedb.cpv_inject(pkg)
+
+ # Now that the vardb state is cached in our FakeVartree,
+ # we won't be needing the real vartree cache for awhile.
+ # To make some room on the heap, clear the vardbapi
+ # caches.
+ self._frozen_config._trees_orig[myroot
+ ]["vartree"].dbapi._clear_cache()
+ gc.collect()
+
+ self._dynamic_config._vdb_loaded = True
+
def _spinner_update(self):
if self._frozen_config.spinner:
self._frozen_config.spinner.update()
"""Given a list of .tbz2s, .ebuilds sets, and deps, populate
self._dynamic_config._initial_arg_list and call self._resolve to create the
appropriate depgraph and return a favorite list."""
+ self._load_vdb()
debug = "--debug" in self._frozen_config.myopts
root_config = self._frozen_config.roots[self._frozen_config.target_root]
sets = root_config.sets
# Skip this to avoid consuming enough time to disturb users.
return 1
+ self._load_vdb()
+
# Put the depgraph into a mode that causes it to only
# select packages that have already been added to the
# graph or those that are installed and have not been
oneshot = "--oneshot" in self._frozen_config.myopts or \
"--onlydeps" in self._frozen_config.myopts
columns = "--columns" in self._frozen_config.myopts
+ tree_display = "--tree" in self._frozen_config.myopts
changelogs=[]
p=[]
blockers = []
return ret
repo_display = RepoDisplay(self._frozen_config.roots)
-
- tree_nodes = []
- display_list = []
- mygraph = self._dynamic_config.digraph.copy()
-
- # If there are any Uninstall instances, add the corresponding
- # blockers to the digraph (useful for --tree display).
-
- executed_uninstalls = set(node for node in mylist \
- if isinstance(node, Package) and node.operation == "unmerge")
-
- for uninstall in self._dynamic_config._blocker_uninstalls.leaf_nodes():
- uninstall_parents = \
- self._dynamic_config._blocker_uninstalls.parent_nodes(uninstall)
- if not uninstall_parents:
- continue
-
- # Remove the corresponding "nomerge" node and substitute
- # the Uninstall node.
- inst_pkg = self._pkg(uninstall.cpv, "installed",
- uninstall.root_config, installed=True)
-
- try:
- mygraph.remove(inst_pkg)
- except KeyError:
- pass
-
- try:
- inst_pkg_blockers = self._dynamic_config._blocker_parents.child_nodes(inst_pkg)
- except KeyError:
- inst_pkg_blockers = []
-
- # Break the Package -> Uninstall edges.
- mygraph.remove(uninstall)
-
- # Resolution of a package's blockers
- # depend on it's own uninstallation.
- for blocker in inst_pkg_blockers:
- mygraph.add(uninstall, blocker)
-
- # Expand Package -> Uninstall edges into
- # Package -> Blocker -> Uninstall edges.
- for blocker in uninstall_parents:
- mygraph.add(uninstall, blocker)
- for parent in self._dynamic_config._blocker_parents.parent_nodes(blocker):
- if parent != inst_pkg:
- mygraph.add(blocker, parent)
-
- # If the uninstall task did not need to be executed because
- # of an upgrade, display Blocker -> Upgrade edges since the
- # corresponding Blocker -> Uninstall edges will not be shown.
- upgrade_node = \
- self._dynamic_config._slot_pkg_map[uninstall.root].get(uninstall.slot_atom)
- if upgrade_node is not None and \
- uninstall not in executed_uninstalls:
- for blocker in uninstall_parents:
- mygraph.add(upgrade_node, blocker)
-
unsatisfied_blockers = []
- i = 0
- depth = 0
- shown_edges = set()
+ ordered_nodes = []
for x in mylist:
if isinstance(x, Blocker) and not x.satisfied:
unsatisfied_blockers.append(x)
- continue
- graph_key = x
- if "--tree" in self._frozen_config.myopts:
- depth = len(tree_nodes)
- while depth and graph_key not in \
- mygraph.child_nodes(tree_nodes[depth-1]):
- depth -= 1
- if depth:
- tree_nodes = tree_nodes[:depth]
- tree_nodes.append(graph_key)
- display_list.append((x, depth, True))
- shown_edges.add((graph_key, tree_nodes[depth-1]))
- else:
- traversed_nodes = set() # prevent endless circles
- traversed_nodes.add(graph_key)
- def add_parents(current_node, ordered):
- parent_nodes = None
- # 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._dynamic_config._set_nodes:
- parent_nodes = mygraph.parent_nodes(current_node)
- if parent_nodes:
- child_nodes = set(mygraph.child_nodes(current_node))
- selected_parent = None
- # First, try to avoid a direct cycle.
- for node in parent_nodes:
- if not isinstance(node, (Blocker, Package)):
- continue
- if node not in traversed_nodes and \
- node not in child_nodes:
- edge = (current_node, node)
- if edge in shown_edges:
- continue
- selected_parent = node
- break
- if not selected_parent:
- # A direct cycle is unavoidable.
- for node in parent_nodes:
- if not isinstance(node, (Blocker, Package)):
- continue
- if node not in traversed_nodes:
- edge = (current_node, node)
- if edge in shown_edges:
- continue
- selected_parent = node
- break
- if selected_parent:
- shown_edges.add((current_node, selected_parent))
- traversed_nodes.add(selected_parent)
- add_parents(selected_parent, False)
- display_list.append((current_node,
- len(tree_nodes), ordered))
- tree_nodes.append(current_node)
- tree_nodes = []
- add_parents(graph_key, True)
else:
- display_list.append((x, depth, True))
+ ordered_nodes.append(x)
+
+ if tree_display:
+ display_list = self._tree_display(ordered_nodes)
+ else:
+ display_list = [(x, 0, True) for x in ordered_nodes]
+
mylist = display_list
for x in unsatisfied_blockers:
mylist.append((x, 0, True))
- last_merge_depth = 0
- for i in range(len(mylist)-1,-1,-1):
- graph_key, depth, ordered = mylist[i]
- if not ordered and depth == 0 and i > 0 \
- and graph_key == mylist[i-1][0] and \
- mylist[i-1][1] == 0:
- # An ordered node got a consecutive duplicate when the tree was
- # being filled in.
- del mylist[i]
- continue
- if ordered and graph_key[-1] != "nomerge":
- last_merge_depth = depth
- continue
- if depth >= last_merge_depth or \
- i < len(mylist) - 1 and \
- depth >= mylist[i+1][1]:
- del mylist[i]
-
# files to fetch list - avoids counting a same file twice
# in size display (verbose mode)
myfetchlist=[]
sys.stdout.flush()
return os.EX_OK
+ def _tree_display(self, mylist):
+
+ # If there are any Uninstall instances, add the
+ # corresponding blockers to the digraph.
+ mygraph = self._dynamic_config.digraph.copy()
+
+ executed_uninstalls = set(node for node in mylist \
+ if isinstance(node, Package) and node.operation == "unmerge")
+
+ for uninstall in self._dynamic_config._blocker_uninstalls.leaf_nodes():
+ uninstall_parents = \
+ self._dynamic_config._blocker_uninstalls.parent_nodes(uninstall)
+ if not uninstall_parents:
+ continue
+
+ # Remove the corresponding "nomerge" node and substitute
+ # the Uninstall node.
+ inst_pkg = self._pkg(uninstall.cpv, "installed",
+ uninstall.root_config, installed=True)
+
+ try:
+ mygraph.remove(inst_pkg)
+ except KeyError:
+ pass
+
+ try:
+ inst_pkg_blockers = self._dynamic_config._blocker_parents.child_nodes(inst_pkg)
+ except KeyError:
+ inst_pkg_blockers = []
+
+ # Break the Package -> Uninstall edges.
+ mygraph.remove(uninstall)
+
+ # Resolution of a package's blockers
+ # depend on it's own uninstallation.
+ for blocker in inst_pkg_blockers:
+ mygraph.add(uninstall, blocker)
+
+ # Expand Package -> Uninstall edges into
+ # Package -> Blocker -> Uninstall edges.
+ for blocker in uninstall_parents:
+ mygraph.add(uninstall, blocker)
+ for parent in self._dynamic_config._blocker_parents.parent_nodes(blocker):
+ if parent != inst_pkg:
+ mygraph.add(blocker, parent)
+
+ # If the uninstall task did not need to be executed because
+ # of an upgrade, display Blocker -> Upgrade edges since the
+ # corresponding Blocker -> Uninstall edges will not be shown.
+ upgrade_node = \
+ self._dynamic_config._slot_pkg_map[uninstall.root].get(uninstall.slot_atom)
+ if upgrade_node is not None and \
+ uninstall not in executed_uninstalls:
+ for blocker in uninstall_parents:
+ mygraph.add(upgrade_node, blocker)
+
+ if "--unordered-display" in self._frozen_config.myopts:
+ display_list = self._unordered_tree_display(mygraph, mylist)
+ else:
+ display_list = self._ordered_tree_display(mygraph, mylist)
+
+ self._prune_tree_display(display_list)
+
+ return display_list
+
+ def _unordered_tree_display(self, mygraph, mylist):
+ display_list = []
+ seen_nodes = set()
+
+ def print_node(node, depth):
+
+ if node in seen_nodes:
+ pass
+ else:
+ seen_nodes.add(node)
+
+ if isinstance(node, Package):
+ display_list.append((node, depth, True))
+ else:
+ depth = -1
+
+ for child_node in mygraph.child_nodes(node):
+ print_node(child_node, depth + 1)
+
+ for root_node in mygraph.root_nodes():
+ print_node(root_node, 0)
+
+ return display_list
+
+ def _ordered_tree_display(self, mygraph, mylist):
+ depth = 0
+ shown_edges = set()
+ tree_nodes = []
+ display_list = []
+
+ for x in mylist:
+ depth = len(tree_nodes)
+ while depth and x not in \
+ mygraph.child_nodes(tree_nodes[depth-1]):
+ depth -= 1
+ if depth:
+ tree_nodes = tree_nodes[:depth]
+ tree_nodes.append(x)
+ display_list.append((x, depth, True))
+ shown_edges.add((x, tree_nodes[depth-1]))
+ else:
+ traversed_nodes = set() # prevent endless circles
+ traversed_nodes.add(x)
+ def add_parents(current_node, ordered):
+ parent_nodes = None
+ # 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._dynamic_config._set_nodes:
+ parent_nodes = mygraph.parent_nodes(current_node)
+ if parent_nodes:
+ child_nodes = set(mygraph.child_nodes(current_node))
+ selected_parent = None
+ # First, try to avoid a direct cycle.
+ for node in parent_nodes:
+ if not isinstance(node, (Blocker, Package)):
+ continue
+ if node not in traversed_nodes and \
+ node not in child_nodes:
+ edge = (current_node, node)
+ if edge in shown_edges:
+ continue
+ selected_parent = node
+ break
+ if not selected_parent:
+ # A direct cycle is unavoidable.
+ for node in parent_nodes:
+ if not isinstance(node, (Blocker, Package)):
+ continue
+ if node not in traversed_nodes:
+ edge = (current_node, node)
+ if edge in shown_edges:
+ continue
+ selected_parent = node
+ break
+ if selected_parent:
+ shown_edges.add((current_node, selected_parent))
+ traversed_nodes.add(selected_parent)
+ add_parents(selected_parent, False)
+ display_list.append((current_node,
+ len(tree_nodes), ordered))
+ tree_nodes.append(current_node)
+ tree_nodes = []
+ add_parents(x, True)
+
+ return display_list
+
+ def _prune_tree_display(self, display_list):
+ last_merge_depth = 0
+ for i in range(len(display_list) - 1, -1, -1):
+ node, depth, ordered = display_list[i]
+ if not ordered and depth == 0 and i > 0 \
+ and node == display_list[i-1][0] and \
+ display_list[i-1][1] == 0:
+ # An ordered node got a consecutive duplicate
+ # when the tree was being filled in.
+ del display_list[i]
+ continue
+ if ordered and isinstance(node, Package) \
+ and node.operation == 'merge':
+ last_merge_depth = depth
+ continue
+ if depth >= last_merge_depth or \
+ i < len(display_list) - 1 and \
+ depth >= display_list[i+1][1]:
+ del display_list[i]
+
def display_problems(self):
"""
Display problems with the dependency graph such as slot collisions.
will raise a PackageNotFound exception if a package is not available.
"""
+ self._load_vdb()
+
if not isinstance(resume_data, dict):
return False
ret = None
return ret
+def _spinner_start(spinner, myopts):
+ if spinner is None:
+ return
+ if "--quiet" not in myopts and \
+ ("--pretend" in myopts or "--ask" in myopts or \
+ "--tree" in myopts or "--verbose" in myopts):
+ action = ""
+ if "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
+ action = "fetched"
+ elif "--buildpkgonly" in myopts:
+ action = "built"
+ else:
+ action = "merged"
+ if "--tree" in myopts and action != "fetched": # Tree doesn't work with fetching
+ if "--unordered-display" in myopts:
+ portage.writemsg_stdout("\n" + \
+ darkgreen("These are the packages that " + \
+ "would be %s:" % action) + "\n\n")
+ else:
+ portage.writemsg_stdout("\n" + \
+ darkgreen("These are the packages that " + \
+ "would be %s, in reverse order:" % action) + "\n\n")
+ else:
+ portage.writemsg_stdout("\n" + \
+ darkgreen("These are the packages that " + \
+ "would be %s, in order:" % action) + "\n\n")
+
+ show_spinner = "--quiet" not in myopts and "--nodeps" not in myopts
+ if not show_spinner:
+ spinner.update = spinner.update_quiet
+
+ if show_spinner:
+ portage.writemsg_stdout("Calculating dependencies ")
+
+def _spinner_stop(spinner):
+ if spinner is None or \
+ spinner.update is spinner.update_quiet:
+ return
+
+ portage.writemsg_stdout("\b\b... done!\n")
+
def backtrack_depgraph(settings, trees, myopts, myparams,
myaction, myfiles, spinner):
"""
Raises PackageSetNotFound if myfiles contains a missing package set.
"""
+ _spinner_start(spinner, myopts)
+ try:
+ return _backtrack_depgraph(settings, trees, myopts, myparams,
+ myaction, myfiles, spinner)
+ finally:
+ _spinner_stop(spinner)
+
+def _backtrack_depgraph(settings, trees, myopts, myparams,
+ myaction, myfiles, spinner):
+
backtrack_max = 30
runtime_pkg_mask = None
allow_backtracking = True
return (success, mydepgraph, favorites)
def resume_depgraph(settings, trees, mtimedb, myopts, myparams, spinner):
+ """
+ Raises PackageSetNotFound if myfiles contains a missing package set.
+ """
+ _spinner_start(spinner, myopts)
+ try:
+ return _resume_depgraph(settings, trees, mtimedb, myopts,
+ myparams, spinner)
+ finally:
+ _spinner_stop(spinner)
+
+def _resume_depgraph(settings, trees, mtimedb, myopts, myparams, spinner):
"""
Construct a depgraph for the given resume list. This will raise
PackageNotFound or depgraph.UnsatisfiedResumeDep when necessary.