#!/usr/bin/python

import sys

from _emerge.actions import load_emerge_config
import portage.dep

settings, trees, mtimedb = load_emerge_config()
vardb = trees[settings["ROOT"]]["vartree"].dbapi

linkmap = vardb._linkmap
reg = vardb._plib_registry

reg.lock()
try:
    plibdata = reg.getPreservedLibs()

    if plibdata:
        sys.stdout.write("# list of bumped libraries:\n")

    for cpv, paths in plibdata.items():
        sys.stdout.write("%s\n" % (cpv,))
        for path in sorted(paths):
            sys.stderr.write("  %s\n" % (path,))

    if plibdata:
        sys.stdout.write("# list of inverse deps:\n")

    # taken from display_preserved_libs.py, Portage
    linkmap.rebuild()  # can raise CommandNotFound
    consumer_map = {}
    search_for_owners = set()
    for cpv in plibdata:
        internal_plib_keys = set(linkmap._obj_key(f) for f in plibdata[cpv])
        for f in plibdata[cpv]:
            if f in consumer_map:
                continue

            consumers = []
            for c in linkmap.findConsumers(f):
                # Filter out any consumers that are also preserved libs
                # belonging to the same package as the provider.
                if linkmap._obj_key(c) not in internal_plib_keys:
                    consumers.append(c)
                consumers.sort()
                consumer_map[f] = consumers
                search_for_owners.update(consumers)

    owners = {}
    for f in search_for_owners:
        owner_set = set()
        for owner in linkmap.getOwners(f):
            owner_dblink = vardb._dblink(owner)
            if owner_dblink.exists():
                owner_set.add(owner_dblink)
            if owner_set:
                owners[f] = owner_set

    all_preserved = set()
    all_preserved.update(*plibdata.values())
    owners_map = {}

    for cpv in plibdata:
        sys.stdout.write("%s\n" % (cpv,))
        samefile_map = {}
        for f in plibdata[cpv]:
            obj_key = linkmap._obj_key(f)
            alt_paths = samefile_map.get(obj_key)
            if alt_paths is None:
                alt_paths = set()
                samefile_map[obj_key] = alt_paths
            alt_paths.add(f)

        for alt_paths in samefile_map.values():
            alt_paths = sorted(alt_paths)
            for p in alt_paths:
                sys.stderr.write("  - %s" % (p,))
            f = alt_paths[0]
            consumers = consumer_map.get(f, [])

            consumers_non_preserved = [c for c in consumers
                                       if c not in all_preserved]
            if consumers_non_preserved:
                # Filter the consumers that are preserved libraries, since
                # they don't need to be rebuilt (see bug #461908).
                consumers = consumers_non_preserved

            for c in consumers:
                owner_pkgs = []
                if c in all_preserved:
                    # The owner is displayed elsewhere due to having
                    # its libs preserved, so distinguish this special
                    # case (see bug #461908).
                    owners_desc = "preserved"
                else:
                    owner_cpvs = [x.mycpv for x in owners.get(c, [])]
                    owner_pkgs.extend(owner_cpvs)
                    owners_desc = ", ".join(owner_cpvs)

                sys.stderr.write("  used by %s (%s)\n" % (c, owners_desc))

                for owner_pkg in owner_pkgs:
                    cp_slot = "%s:%s" % (
                        portage.dep.dep_getkey("=" + owner_pkg),
                        vardb.aux_get(owner_pkg, ["SLOT"])[0]
                        )
                    obj = owners_map.setdefault(cp_slot, set())
                    obj.add(c)

        sys.stdout.flush()
        sys.stderr.flush()

    if owners_map:
        sys.stdout.write("# grouped list of rebuilds:\n")

    for owner_pkg in sorted(owners_map.keys()):
        owner_files = sorted(owners_map[owner_pkg])
        sys.stdout.write("%s\n" % (owner_pkg,))
        for owner_file in owner_files:
            sys.stderr.write("  %s\n" % (owner_file,))

    sys.stdout.flush()
    sys.stderr.flush()

finally:
    reg.unlock()
