| # Copyright 2010 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| __all__ = ( |
| "display", "filter_iuse_defaults", |
| ) |
| |
| import codecs |
| import re |
| import sys |
| |
| from portage import os |
| from portage import _encodings, _unicode_decode, _unicode_encode |
| from portage.dbapi.dep_expand import dep_expand |
| from portage.const import PORTAGE_PACKAGE_ATOM |
| from portage.dep import cpvequal, match_from_list |
| from portage.exception import InvalidDependString |
| from portage._sets.base import InternalPackageSet |
| from portage.output import blue, bold, colorize, create_color_func, darkblue, darkgreen, green, nc_len, red, \ |
| teal, turquoise, yellow |
| bad = create_color_func("BAD") |
| from portage.util import writemsg, writemsg_stdout |
| from portage.versions import best, catpkgsplit, cpv_getkey |
| |
| from _emerge.Blocker import Blocker |
| from _emerge.create_world_atom import create_world_atom |
| from _emerge.Package import Package |
| |
| if sys.hexversion >= 0x3000000: |
| basestring = str |
| |
| def filter_iuse_defaults(iuse): |
| for flag in iuse: |
| if flag.startswith("+") or flag.startswith("-"): |
| yield flag[1:] |
| else: |
| yield flag |
| |
| class _RepoDisplay(object): |
| def __init__(self, roots): |
| self._shown_repos = {} |
| self._unknown_repo = False |
| repo_paths = set() |
| for root_config in roots.values(): |
| portdir = root_config.settings.get("PORTDIR") |
| if root_config.settings.repositories: |
| repo_paths.update(root_config.settings.repositories.repoUserLocationList()) |
| repo_paths = list(repo_paths) |
| self._repo_paths = repo_paths |
| self._repo_paths_real = [ os.path.realpath(repo_path) \ |
| for repo_path in repo_paths ] |
| |
| # pre-allocate index for PORTDIR so that it always has index 0. |
| for root_config in roots.values(): |
| portdb = root_config.trees["porttree"].dbapi |
| portdir = portdb.porttree_root |
| if portdir: |
| self.repoStr(portdir) |
| |
| def repoStr(self, repo_path_real): |
| real_index = -1 |
| if repo_path_real: |
| real_index = self._repo_paths_real.index(repo_path_real) |
| if real_index == -1: |
| s = "?" |
| self._unknown_repo = True |
| else: |
| shown_repos = self._shown_repos |
| repo_paths = self._repo_paths |
| repo_path = repo_paths[real_index] |
| index = shown_repos.get(repo_path) |
| if index is None: |
| index = len(shown_repos) |
| shown_repos[repo_path] = index |
| s = str(index) |
| return s |
| |
| def __str__(self): |
| output = [] |
| shown_repos = self._shown_repos |
| unknown_repo = self._unknown_repo |
| if shown_repos or self._unknown_repo: |
| output.append("Portage tree and overlays:\n") |
| show_repo_paths = list(shown_repos) |
| for repo_path, repo_index in shown_repos.items(): |
| show_repo_paths[repo_index] = repo_path |
| if show_repo_paths: |
| for index, repo_path in enumerate(show_repo_paths): |
| output.append(" "+teal("["+str(index)+"]")+" %s\n" % repo_path) |
| if unknown_repo: |
| output.append(" "+teal("[?]") + \ |
| " indicates that the source repository could not be determined\n") |
| return "".join(output) |
| |
| if sys.hexversion < 0x3000000: |
| |
| __unicode__ = __str__ |
| |
| def __str__(self): |
| return _unicode_encode(self.__unicode__(), |
| encoding=_encodings['content']) |
| |
| class _PackageCounters(object): |
| |
| def __init__(self): |
| self.upgrades = 0 |
| self.downgrades = 0 |
| self.new = 0 |
| self.newslot = 0 |
| self.reinst = 0 |
| self.uninst = 0 |
| self.blocks = 0 |
| self.blocks_satisfied = 0 |
| self.totalsize = 0 |
| self.restrict_fetch = 0 |
| self.restrict_fetch_satisfied = 0 |
| self.interactive = 0 |
| self.binary = 0 |
| |
| def __str__(self): |
| total_installs = self.upgrades + self.downgrades + self.newslot + self.new + self.reinst |
| myoutput = [] |
| details = [] |
| myoutput.append("Total: %s package" % total_installs) |
| if total_installs != 1: |
| myoutput.append("s") |
| if total_installs != 0: |
| myoutput.append(" (") |
| if self.upgrades > 0: |
| details.append("%s upgrade" % self.upgrades) |
| if self.upgrades > 1: |
| details[-1] += "s" |
| if self.downgrades > 0: |
| details.append("%s downgrade" % self.downgrades) |
| if self.downgrades > 1: |
| details[-1] += "s" |
| if self.new > 0: |
| details.append("%s new" % self.new) |
| if self.newslot > 0: |
| details.append("%s in new slot" % self.newslot) |
| if self.newslot > 1: |
| details[-1] += "s" |
| if self.reinst > 0: |
| details.append("%s reinstall" % self.reinst) |
| if self.reinst > 1: |
| details[-1] += "s" |
| if self.binary > 0: |
| details.append("%s binary" % self.binary) |
| if self.binary > 1: |
| details[-1] = details[-1][:-1] + "ies" |
| if self.uninst > 0: |
| details.append("%s uninstall" % self.uninst) |
| if self.uninst > 1: |
| details[-1] += "s" |
| if self.interactive > 0: |
| details.append("%s %s" % (self.interactive, |
| colorize("WARN", "interactive"))) |
| myoutput.append(", ".join(details)) |
| if total_installs != 0: |
| myoutput.append(")") |
| myoutput.append(", Size of downloads: %s" % _format_size(self.totalsize)) |
| if self.restrict_fetch: |
| myoutput.append("\nFetch Restriction: %s package" % \ |
| self.restrict_fetch) |
| if self.restrict_fetch > 1: |
| myoutput.append("s") |
| if self.restrict_fetch_satisfied < self.restrict_fetch: |
| myoutput.append(bad(" (%s unsatisfied)") % \ |
| (self.restrict_fetch - self.restrict_fetch_satisfied)) |
| if self.blocks > 0: |
| myoutput.append("\nConflict: %s block" % \ |
| self.blocks) |
| if self.blocks > 1: |
| myoutput.append("s") |
| if self.blocks_satisfied < self.blocks: |
| myoutput.append(bad(" (%s unsatisfied)") % \ |
| (self.blocks - self.blocks_satisfied)) |
| return "".join(myoutput) |
| |
| class _DisplayConfig(object): |
| def __init__(self, depgraph, mylist, favorites, verbosity): |
| frozen_config = depgraph._frozen_config |
| dynamic_config = depgraph._dynamic_config |
| |
| self.mylist = mylist |
| self.favorites = InternalPackageSet(favorites, allow_repo=True) |
| self.verbosity = verbosity |
| |
| if self.verbosity is None: |
| self.verbosity = ("--quiet" in frozen_config.myopts and 1 or \ |
| "--verbose" in frozen_config.myopts and 3 or 2) |
| |
| self.oneshot = "--oneshot" in frozen_config.myopts or \ |
| "--onlydeps" in frozen_config.myopts |
| self.columns = "--columns" in frozen_config.myopts |
| self.tree_display = "--tree" in frozen_config.myopts |
| self.alphabetical = "--alphabetical" in frozen_config.myopts |
| self.quiet = "--quiet" in frozen_config.myopts |
| self.all_flags = self.verbosity == 3 or self.quiet |
| self.print_use_string = self.verbosity != 1 or "--verbose" in frozen_config.myopts |
| self.changelog = "--changelog" in frozen_config.myopts |
| self.edebug = frozen_config.edebug |
| self.no_restart = frozen_config._opts_no_restart.intersection(frozen_config.myopts) |
| self.unordered_display = "--unordered-display" in frozen_config.myopts |
| |
| mywidth = 130 |
| if "COLUMNWIDTH" in frozen_config.settings: |
| try: |
| mywidth = int(frozen_config.settings["COLUMNWIDTH"]) |
| except ValueError as e: |
| writemsg("!!! %s\n" % str(e), noiselevel=-1) |
| writemsg("!!! Unable to parse COLUMNWIDTH='%s'\n" % \ |
| frozen_config.settings["COLUMNWIDTH"], noiselevel=-1) |
| del e |
| self.columnwidth = mywidth |
| |
| self.repo_display = _RepoDisplay(frozen_config.roots) |
| self.trees = frozen_config.trees |
| self.pkgsettings = frozen_config.pkgsettings |
| self.target_root = frozen_config.target_root |
| self.running_root = frozen_config._running_root |
| self.roots = frozen_config.roots |
| |
| self.blocker_parents = dynamic_config._blocker_parents |
| self.reinstall_nodes = dynamic_config._reinstall_nodes |
| self.digraph = dynamic_config.digraph |
| self.blocker_uninstalls = dynamic_config._blocker_uninstalls |
| self.slot_pkg_map = dynamic_config._slot_pkg_map |
| self.set_nodes = dynamic_config._set_nodes |
| |
| self.pkg_use_enabled = depgraph._pkg_use_enabled |
| self.pkg = depgraph._pkg |
| |
| # formats a size given in bytes nicely |
| def _format_size(mysize): |
| if isinstance(mysize, basestring): |
| return mysize |
| if 0 != mysize % 1024: |
| # Always round up to the next kB so that it doesn't show 0 kB when |
| # some small file still needs to be fetched. |
| mysize += 1024 - mysize % 1024 |
| mystr=str(mysize//1024) |
| mycount=len(mystr) |
| while (mycount > 3): |
| mycount-=3 |
| mystr=mystr[:mycount]+","+mystr[mycount:] |
| return mystr+" kB" |
| |
| def display(depgraph, mylist, favorites=[], verbosity=None): |
| |
| conf = _DisplayConfig(depgraph, mylist, favorites, verbosity) |
| |
| changelogs=[] |
| p=[] |
| blockers = [] |
| counters = _PackageCounters() |
| repo_display = conf.repo_display |
| unsatisfied_blockers = [] |
| ordered_nodes = [] |
| for x in conf.mylist: |
| if isinstance(x, Blocker): |
| counters.blocks += 1 |
| if x.satisfied: |
| ordered_nodes.append(x) |
| counters.blocks_satisfied += 1 |
| else: |
| unsatisfied_blockers.append(x) |
| else: |
| ordered_nodes.append(x) |
| |
| if conf.tree_display: |
| display_list = _tree_display(conf, 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)) |
| |
| # files to fetch list - avoids counting a same file twice |
| # in size display (verbose mode) |
| myfetchlist=[] |
| |
| # Use this set to detect when all the "repoadd" strings are "[0]" |
| # and disable the entire repo display in this case. |
| repoadd_set = set() |
| |
| for mylist_index in range(len(mylist)): |
| x, depth, ordered = mylist[mylist_index] |
| pkg_type = x[0] |
| myroot = x[1] |
| pkg_key = x[2] |
| portdb = conf.trees[myroot]["porttree"].dbapi |
| vardb = conf.trees[myroot]["vartree"].dbapi |
| pkgsettings = conf.pkgsettings[myroot] |
| |
| fetch=" " |
| indent = " " * depth |
| |
| if isinstance(x, Blocker): |
| if x.satisfied: |
| blocker_style = "PKG_BLOCKER_SATISFIED" |
| addl = "%s %s " % (colorize(blocker_style, "b"), fetch) |
| else: |
| blocker_style = "PKG_BLOCKER" |
| addl = "%s %s " % (colorize(blocker_style, "B"), fetch) |
| resolved = dep_expand( |
| str(x.atom).lstrip("!"), mydb=vardb, settings=pkgsettings) |
| if conf.columns and conf.quiet: |
| addl += " " + colorize(blocker_style, str(resolved)) |
| else: |
| addl = "[%s %s] %s%s" % \ |
| (colorize(blocker_style, "blocks"), |
| addl, indent, colorize(blocker_style, str(resolved))) |
| block_parents = conf.blocker_parents.parent_nodes(x) |
| block_parents = set([pnode[2] for pnode in block_parents]) |
| block_parents = ", ".join(block_parents) |
| if resolved!=x[2]: |
| addl += colorize(blocker_style, |
| " (\"%s\" is blocking %s)") % \ |
| (str(x.atom).lstrip("!"), block_parents) |
| else: |
| addl += colorize(blocker_style, |
| " (is blocking %s)") % block_parents |
| if isinstance(x, Blocker) and x.satisfied: |
| if conf.columns: |
| continue |
| p.append(addl) |
| else: |
| blockers.append(addl) |
| else: |
| pkg_status = x[3] |
| pkg_merge = ordered and pkg_status == "merge" |
| if not pkg_merge and pkg_status == "merge": |
| pkg_status = "nomerge" |
| built = pkg_type != "ebuild" |
| pkg = x |
| metadata = pkg.metadata |
| ebuild_path = None |
| repo_name = pkg.repo |
| if pkg.type_name == "ebuild": |
| ebuild_path = portdb.findname(pkg.cpv, myrepo=repo_name) |
| if ebuild_path is None: |
| raise AssertionError( |
| "ebuild not found for '%s'" % pkg.cpv) |
| repo_path_real = os.path.dirname(os.path.dirname( |
| os.path.dirname(ebuild_path))) |
| else: |
| repo_path_real = portdb.getRepositoryPath(repo_name) |
| pkg_use = list(conf.pkg_use_enabled(pkg)) |
| if not pkg.built and pkg.operation == 'merge' and \ |
| 'fetch' in pkg.metadata.restrict: |
| fetch = red("F") |
| if ordered: |
| counters.restrict_fetch += 1 |
| if portdb.fetch_check(pkg_key, pkg_use, myrepo=pkg.repo): |
| fetch = green("f") |
| if ordered: |
| counters.restrict_fetch_satisfied += 1 |
| |
| #we need to use "--emptrytree" testing here rather than "empty" param testing because "empty" |
| #param is used for -u, where you still *do* want to see when something is being upgraded. |
| myoldbest = [] |
| myinslotlist = None |
| installed_versions = vardb.match(cpv_getkey(pkg_key)) |
| if vardb.cpv_exists(pkg_key): |
| addl=" "+yellow("R")+fetch+" " |
| if ordered: |
| if pkg_merge: |
| counters.reinst += 1 |
| if pkg_type == "binary": |
| counters.binary += 1 |
| elif pkg_status == "uninstall": |
| counters.uninst += 1 |
| # filter out old-style virtual matches |
| elif installed_versions and \ |
| cpv_getkey(installed_versions[0]) == \ |
| cpv_getkey(pkg_key): |
| myinslotlist = vardb.match(pkg.slot_atom) |
| # If this is the first install of a new-style virtual, we |
| # need to filter out old-style virtual matches. |
| if myinslotlist and \ |
| cpv_getkey(myinslotlist[0]) != \ |
| cpv_getkey(pkg_key): |
| myinslotlist = None |
| if myinslotlist: |
| myoldbest = myinslotlist[:] |
| addl = " " + fetch |
| if not cpvequal(pkg_key, |
| best([pkg_key] + myoldbest)): |
| # Downgrade in slot |
| addl += turquoise("U")+blue("D") |
| if ordered: |
| counters.downgrades += 1 |
| if pkg_type == "binary": |
| counters.binary += 1 |
| else: |
| # Update in slot |
| addl += turquoise("U") + " " |
| if ordered: |
| counters.upgrades += 1 |
| if pkg_type == "binary": |
| counters.binary += 1 |
| else: |
| # New slot, mark it new. |
| addl = " " + green("NS") + fetch + " " |
| myoldbest = vardb.match(cpv_getkey(pkg_key)) |
| if ordered: |
| counters.newslot += 1 |
| if pkg_type == "binary": |
| counters.binary += 1 |
| |
| if conf.changelog: |
| inst_matches = vardb.match(pkg.slot_atom) |
| if inst_matches: |
| ebuild_path_cl = ebuild_path |
| if ebuild_path_cl is None: |
| # binary package |
| ebuild_path_cl = portdb.findname(pkg.cpv) |
| |
| if ebuild_path_cl is not None: |
| changelogs.extend(_calc_changelog( |
| ebuild_path_cl, inst_matches[0], pkg.cpv)) |
| else: |
| addl = " " + green("N") + " " + fetch + " " |
| if ordered: |
| counters.new += 1 |
| if pkg_type == "binary": |
| counters.binary += 1 |
| |
| verboseadd = "" |
| repoadd = None |
| |
| if True: |
| # USE flag display |
| forced_flags = set() |
| pkgsettings.setcpv(pkg) # for package.use.{mask,force} |
| forced_flags.update(pkgsettings.useforce) |
| forced_flags.update(pkgsettings.usemask) |
| |
| cur_use = [flag for flag in conf.pkg_use_enabled(pkg) \ |
| if flag in pkg.iuse.all] |
| cur_iuse = sorted(pkg.iuse.all) |
| |
| if myoldbest and myinslotlist: |
| previous_cpv = myoldbest[0] |
| else: |
| previous_cpv = pkg.cpv |
| if vardb.cpv_exists(previous_cpv): |
| old_iuse, old_use = vardb.aux_get( |
| previous_cpv, ["IUSE", "USE"]) |
| old_iuse = list(set( |
| filter_iuse_defaults(old_iuse.split()))) |
| old_iuse.sort() |
| old_use = old_use.split() |
| is_new = False |
| else: |
| old_iuse = [] |
| old_use = [] |
| is_new = True |
| |
| old_use = [flag for flag in old_use if flag in old_iuse] |
| |
| use_expand = pkgsettings["USE_EXPAND"].lower().split() |
| use_expand.sort() |
| use_expand.reverse() |
| use_expand_hidden = \ |
| pkgsettings["USE_EXPAND_HIDDEN"].lower().split() |
| |
| def map_to_use_expand(myvals, forcedFlags=False, |
| removeHidden=True): |
| ret = {} |
| forced = {} |
| for exp in use_expand: |
| ret[exp] = [] |
| forced[exp] = set() |
| for val in myvals[:]: |
| if val.startswith(exp.lower()+"_"): |
| if val in forced_flags: |
| forced[exp].add(val[len(exp)+1:]) |
| ret[exp].append(val[len(exp)+1:]) |
| myvals.remove(val) |
| ret["USE"] = myvals |
| forced["USE"] = [val for val in myvals \ |
| if val in forced_flags] |
| if removeHidden: |
| for exp in use_expand_hidden: |
| ret.pop(exp, None) |
| if forcedFlags: |
| return ret, forced |
| return ret |
| |
| # Prevent USE_EXPAND_HIDDEN flags from being hidden if they |
| # are the only thing that triggered reinstallation. |
| reinst_flags_map = {} |
| reinstall_for_flags = conf.reinstall_nodes.get(pkg) |
| reinst_expand_map = None |
| if reinstall_for_flags: |
| reinst_flags_map = map_to_use_expand( |
| list(reinstall_for_flags), removeHidden=False) |
| for k in list(reinst_flags_map): |
| if not reinst_flags_map[k]: |
| del reinst_flags_map[k] |
| if not reinst_flags_map.get("USE"): |
| reinst_expand_map = reinst_flags_map.copy() |
| reinst_expand_map.pop("USE", None) |
| if reinst_expand_map and \ |
| not set(reinst_expand_map).difference( |
| use_expand_hidden): |
| use_expand_hidden = \ |
| set(use_expand_hidden).difference( |
| reinst_expand_map) |
| |
| cur_iuse_map, iuse_forced = \ |
| map_to_use_expand(cur_iuse, forcedFlags=True) |
| cur_use_map = map_to_use_expand(cur_use) |
| old_iuse_map = map_to_use_expand(old_iuse) |
| old_use_map = map_to_use_expand(old_use) |
| |
| use_expand.sort() |
| use_expand.insert(0, "USE") |
| |
| for key in use_expand: |
| if key in use_expand_hidden: |
| continue |
| verboseadd += _create_use_string(conf, key.upper(), |
| cur_iuse_map[key], iuse_forced[key], |
| cur_use_map[key], old_iuse_map[key], |
| old_use_map[key], is_new, |
| reinst_flags_map.get(key)) |
| |
| if conf.verbosity == 3: |
| # size verbose |
| mysize=0 |
| if pkg_type == "ebuild" and pkg_merge: |
| try: |
| myfilesdict = portdb.getfetchsizes(pkg_key, |
| useflags=pkg_use, debug=conf.edebug) |
| except InvalidDependString: |
| # should have been masked before it was selected |
| raise |
| if myfilesdict is None: |
| myfilesdict="[empty/missing/bad digest]" |
| else: |
| for myfetchfile in myfilesdict: |
| if myfetchfile not in myfetchlist: |
| mysize+=myfilesdict[myfetchfile] |
| myfetchlist.append(myfetchfile) |
| if ordered: |
| counters.totalsize += mysize |
| verboseadd += _format_size(mysize) |
| |
| # overlay verbose |
| # assign index for a previous version in the same slot |
| has_previous = False |
| repo_name_prev = None |
| slot_matches = vardb.match(pkg.slot_atom) |
| if slot_matches: |
| has_previous = True |
| repo_name_prev = vardb.aux_get(slot_matches[0], |
| ["repository"])[0] |
| |
| # now use the data to generate output |
| if pkg.installed or not has_previous: |
| repoadd = repo_display.repoStr(repo_path_real) |
| else: |
| repo_path_prev = None |
| if repo_name_prev: |
| repo_path_prev = portdb.getRepositoryPath( |
| repo_name_prev) |
| if repo_path_prev == repo_path_real: |
| repoadd = repo_display.repoStr(repo_path_real) |
| else: |
| repoadd = "%s=>%s" % ( |
| repo_display.repoStr(repo_path_prev), |
| repo_display.repoStr(repo_path_real)) |
| if repoadd: |
| repoadd_set.add(repoadd) |
| |
| xs = [cpv_getkey(pkg_key)] + \ |
| list(catpkgsplit(pkg_key)[2:]) |
| if xs[2] == "r0": |
| xs[2] = "" |
| else: |
| xs[2] = "-" + xs[2] |
| |
| oldlp = conf.columnwidth - 30 |
| newlp = oldlp - 30 |
| |
| # Convert myoldbest from a list to a string. |
| if not myoldbest: |
| myoldbest = "" |
| else: |
| for pos, key in enumerate(myoldbest): |
| key = catpkgsplit(key)[2] + \ |
| "-" + catpkgsplit(key)[3] |
| if key[-3:] == "-r0": |
| key = key[:-3] |
| myoldbest[pos] = key |
| myoldbest = blue("["+", ".join(myoldbest)+"]") |
| |
| pkg_cp = xs[0] |
| root_config = conf.roots[myroot] |
| system_set = root_config.sets["system"] |
| world_set = root_config.sets["selected"] |
| |
| pkg_system = False |
| pkg_world = False |
| try: |
| pkg_system = system_set.findAtomForPackage(pkg, modified_use=conf.pkg_use_enabled(pkg)) |
| pkg_world = world_set.findAtomForPackage(pkg, modified_use=conf.pkg_use_enabled(pkg)) |
| if not (conf.oneshot or pkg_world) and \ |
| myroot == conf.target_root and \ |
| conf.favorites.findAtomForPackage(pkg, modified_use=conf.pkg_use_enabled(pkg)): |
| # Maybe it will be added to world now. |
| if create_world_atom(pkg, conf.favorites, root_config): |
| pkg_world = True |
| except InvalidDependString: |
| # This is reported elsewhere if relevant. |
| pass |
| |
| def pkgprint(pkg_str): |
| if pkg_merge: |
| if built: |
| if pkg_system: |
| return colorize("PKG_BINARY_MERGE_SYSTEM", pkg_str) |
| elif pkg_world: |
| return colorize("PKG_BINARY_MERGE_WORLD", pkg_str) |
| else: |
| return colorize("PKG_BINARY_MERGE", pkg_str) |
| else: |
| if pkg_system: |
| return colorize("PKG_MERGE_SYSTEM", pkg_str) |
| elif pkg_world: |
| return colorize("PKG_MERGE_WORLD", pkg_str) |
| else: |
| return colorize("PKG_MERGE", pkg_str) |
| elif pkg_status == "uninstall": |
| return colorize("PKG_UNINSTALL", pkg_str) |
| else: |
| if pkg_system: |
| return colorize("PKG_NOMERGE_SYSTEM", pkg_str) |
| elif pkg_world: |
| return colorize("PKG_NOMERGE_WORLD", pkg_str) |
| else: |
| return colorize("PKG_NOMERGE", pkg_str) |
| |
| if 'interactive' in pkg.metadata.properties and \ |
| pkg.operation == 'merge': |
| addl = colorize("WARN", "I") + addl[1:] |
| if ordered: |
| counters.interactive += 1 |
| |
| if x[1]!="/": |
| if myoldbest: |
| myoldbest +=" " |
| if conf.columns: |
| if conf.quiet: |
| myprint=addl+" "+indent+pkgprint(pkg_cp) |
| myprint=myprint+darkblue(" "+xs[1]+xs[2])+" " |
| myprint=myprint+myoldbest |
| myprint=myprint+darkgreen("to "+x[1]) |
| verboseadd = None |
| else: |
| if not pkg_merge: |
| myprint = "[%s] %s%s" % \ |
| (pkgprint(pkg_status.ljust(13)), |
| indent, pkgprint(pkg.cp)) |
| else: |
| myprint = "[%s %s] %s%s" % \ |
| (pkgprint(pkg.type_name), addl, |
| indent, pkgprint(pkg.cp)) |
| if (newlp-nc_len(myprint)) > 0: |
| myprint=myprint+(" "*(newlp-nc_len(myprint))) |
| myprint=myprint+"["+darkblue(xs[1]+xs[2])+"] " |
| if (oldlp-nc_len(myprint)) > 0: |
| myprint=myprint+" "*(oldlp-nc_len(myprint)) |
| myprint=myprint+myoldbest |
| myprint += darkgreen("to " + pkg.root) |
| else: |
| if not pkg_merge: |
| myprint = "[%s] " % pkgprint(pkg_status.ljust(13)) |
| else: |
| myprint = "[%s %s] " % (pkgprint(pkg_type), addl) |
| myprint += indent + pkgprint(pkg_key) + " " + \ |
| myoldbest + darkgreen("to " + myroot) |
| else: |
| if conf.columns: |
| if conf.quiet: |
| myprint=addl+" "+indent+pkgprint(pkg_cp) |
| myprint=myprint+" "+green(xs[1]+xs[2])+" " |
| myprint=myprint+myoldbest |
| verboseadd = None |
| else: |
| if not pkg_merge: |
| myprint = "[%s] %s%s" % \ |
| (pkgprint(pkg_status.ljust(13)), |
| indent, pkgprint(pkg.cp)) |
| else: |
| myprint = "[%s %s] %s%s" % \ |
| (pkgprint(pkg.type_name), addl, |
| indent, pkgprint(pkg.cp)) |
| if (newlp-nc_len(myprint)) > 0: |
| myprint=myprint+(" "*(newlp-nc_len(myprint))) |
| myprint=myprint+green(" ["+xs[1]+xs[2]+"] ") |
| if (oldlp-nc_len(myprint)) > 0: |
| myprint=myprint+(" "*(oldlp-nc_len(myprint))) |
| myprint += myoldbest |
| else: |
| if not pkg_merge: |
| myprint = "[%s] %s%s %s" % \ |
| (pkgprint(pkg_status.ljust(13)), |
| indent, pkgprint(pkg.cpv), |
| myoldbest) |
| else: |
| myprint = "[%s %s] %s%s %s" % \ |
| (pkgprint(pkg_type), addl, indent, |
| pkgprint(pkg.cpv), myoldbest) |
| |
| if conf.columns and pkg.operation == "uninstall": |
| continue |
| p.append((myprint, verboseadd, repoadd)) |
| |
| if not conf.tree_display and \ |
| conf.quiet and \ |
| not conf.no_restart and \ |
| pkg.root == conf.running_root.root and \ |
| match_from_list( |
| PORTAGE_PACKAGE_ATOM, [pkg]) and \ |
| not conf.quiet: |
| if not vardb.cpv_exists(pkg.cpv) or \ |
| '9999' in pkg.cpv or \ |
| 'git' in pkg.inherited: |
| if mylist_index < len(mylist) - 1: |
| p.append(colorize("WARN", "*** Portage will stop merging at this point and reload itself,")) |
| p.append(colorize("WARN", " then resume the merge.")) |
| |
| show_repos = repoadd_set and repoadd_set != set(["0"]) |
| |
| for x in p: |
| if isinstance(x, basestring): |
| writemsg_stdout("%s\n" % (x,), noiselevel=-1) |
| continue |
| |
| myprint, verboseadd, repoadd = x |
| |
| if verboseadd: |
| myprint += " " + verboseadd |
| |
| if show_repos and repoadd: |
| myprint += " " + teal("[%s]" % repoadd) |
| |
| writemsg_stdout("%s\n" % (myprint,), noiselevel=-1) |
| |
| for x in blockers: |
| writemsg_stdout("%s\n" % (x,), noiselevel=-1) |
| |
| if conf.verbosity == 3: |
| writemsg_stdout('\n%s\n' % (counters,), noiselevel=-1) |
| if show_repos: |
| # Use _unicode_decode() to force unicode format string so |
| # that RepoDisplay.__unicode__() is called in python2. |
| writemsg_stdout(_unicode_decode("%s") % (repo_display,), |
| noiselevel=-1) |
| |
| if conf.changelog: |
| writemsg_stdout('\n', noiselevel=-1) |
| for revision,text in changelogs: |
| writemsg_stdout(bold('*'+revision) + '\n' + text, |
| noiselevel=-1) |
| |
| return os.EX_OK |
| |
| |
| def _create_use_string(conf, name, cur_iuse, iuse_forced, cur_use, |
| old_iuse, old_use, |
| is_new, reinst_flags): |
| |
| if not conf.print_use_string: |
| return "" |
| |
| enabled = [] |
| if conf.alphabetical: |
| disabled = enabled |
| removed = enabled |
| else: |
| disabled = [] |
| removed = [] |
| cur_iuse = set(cur_iuse) |
| enabled_flags = cur_iuse.intersection(cur_use) |
| removed_iuse = set(old_iuse).difference(cur_iuse) |
| any_iuse = cur_iuse.union(old_iuse) |
| any_iuse = list(any_iuse) |
| any_iuse.sort() |
| for flag in any_iuse: |
| flag_str = None |
| isEnabled = False |
| reinst_flag = reinst_flags and flag in reinst_flags |
| if flag in enabled_flags: |
| isEnabled = True |
| if is_new or flag in old_use and \ |
| (conf.all_flags or reinst_flag): |
| flag_str = red(flag) |
| elif flag not in old_iuse: |
| flag_str = yellow(flag) + "%*" |
| elif flag not in old_use: |
| flag_str = green(flag) + "*" |
| elif flag in removed_iuse: |
| if conf.all_flags or reinst_flag: |
| flag_str = yellow("-" + flag) + "%" |
| if flag in old_use: |
| flag_str += "*" |
| flag_str = "(" + flag_str + ")" |
| removed.append(flag_str) |
| continue |
| else: |
| if is_new or flag in old_iuse and \ |
| flag not in old_use and \ |
| (conf.all_flags or reinst_flag): |
| flag_str = blue("-" + flag) |
| elif flag not in old_iuse: |
| flag_str = yellow("-" + flag) |
| if flag not in iuse_forced: |
| flag_str += "%" |
| elif flag in old_use: |
| flag_str = green("-" + flag) + "*" |
| if flag_str: |
| if flag in iuse_forced: |
| flag_str = "(" + flag_str + ")" |
| if isEnabled: |
| enabled.append(flag_str) |
| else: |
| disabled.append(flag_str) |
| |
| if conf.alphabetical: |
| ret = " ".join(enabled) |
| else: |
| ret = " ".join(enabled + disabled + removed) |
| if ret: |
| ret = '%s="%s" ' % (name, ret) |
| return ret |
| |
| |
| def _tree_display(conf, mylist): |
| |
| # If there are any Uninstall instances, add the |
| # corresponding blockers to the digraph. |
| mygraph = conf.digraph.copy() |
| |
| executed_uninstalls = set(node for node in mylist \ |
| if isinstance(node, Package) and node.operation == "unmerge") |
| |
| for uninstall in conf.blocker_uninstalls.leaf_nodes(): |
| uninstall_parents = \ |
| conf.blocker_uninstalls.parent_nodes(uninstall) |
| if not uninstall_parents: |
| continue |
| |
| # Remove the corresponding "nomerge" node and substitute |
| # the Uninstall node. |
| inst_pkg = conf.pkg(uninstall.cpv, "installed", |
| uninstall.root_config, installed=True) |
| |
| try: |
| mygraph.remove(inst_pkg) |
| except KeyError: |
| pass |
| |
| try: |
| inst_pkg_blockers = conf.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 conf.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 = \ |
| conf.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 conf.unordered_display: |
| display_list = _unordered_tree_display(mygraph, mylist) |
| else: |
| display_list = _ordered_tree_display(conf, mygraph, mylist) |
| |
| _prune_tree_display(display_list) |
| |
| return display_list |
| |
| def _unordered_tree_display(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, (Blocker, 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(conf, 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 conf.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(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 in ('merge', 'uninstall'): |
| 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 _calc_changelog(ebuildpath,current,next): |
| if ebuildpath == None or not os.path.exists(ebuildpath): |
| return [] |
| current = '-'.join(catpkgsplit(current)[1:]) |
| if current.endswith('-r0'): |
| current = current[:-3] |
| next = '-'.join(catpkgsplit(next)[1:]) |
| if next.endswith('-r0'): |
| next = next[:-3] |
| changelogpath = os.path.join(os.path.split(ebuildpath)[0],'ChangeLog') |
| try: |
| changelog = codecs.open(_unicode_encode(changelogpath, |
| encoding=_encodings['fs'], errors='strict'), |
| mode='r', encoding=_encodings['repo.content'], errors='replace' |
| ).read() |
| except SystemExit: |
| raise # Needed else can't exit |
| except: |
| return [] |
| divisions = _find_changelog_tags(changelog) |
| #print 'XX from',current,'to',next |
| #for div,text in divisions: print 'XX',div |
| # skip entries for all revisions above the one we are about to emerge |
| for i in range(len(divisions)): |
| if divisions[i][0]==next: |
| divisions = divisions[i:] |
| break |
| # find out how many entries we are going to display |
| for i in range(len(divisions)): |
| if divisions[i][0]==current: |
| divisions = divisions[:i] |
| break |
| else: |
| # couldnt find the current revision in the list. display nothing |
| return [] |
| return divisions |
| |
| def _find_changelog_tags(changelog): |
| divs = [] |
| release = None |
| while 1: |
| match = re.search(r'^\*\ ?([-a-zA-Z0-9_.+]*)(?:\ .*)?\n',changelog,re.M) |
| if match is None: |
| if release is not None: |
| divs.append((release,changelog)) |
| return divs |
| if release is not None: |
| divs.append((release,changelog[:match.start()])) |
| changelog = changelog[match.end():] |
| release = match.group(1) |
| if release.endswith('.ebuild'): |
| release = release[:-7] |
| if release.endswith('-r0'): |
| release = release[:-3] |