#!/usr/bin/env python3 # Copyright 2017 Luke Shumaker <lukeshu@parabola.nu> # # This is a little program that is useful for helping prune lists of # dependencies. I should clean it up, document it, and add it to # libretools. import pyalpm import pycman.config def get_by_depspec(depspec): global dbs global pkgs dep = pyalpm.find_satisfier(pkgs.values(), depspec) if dep is not None: return dep for db in dbs: dep = pyalpm.find_satisfier(db.search('.*'), depspec) if dep is not None: return dep return None def handlepkg(pkg): global pkgs global deps global ignore if pkg.name in pkgs: return pkgs[pkg.name] = pkg deps[pkg.name] = set([get_by_depspec(depspec) for depspec in pkg.depends]) for dep in deps[pkg.name]: ignore.add(dep.name) handlepkg(dep) class DepTree(object): def __init__(self, pkgname, reasons=[]): self.pkgname = pkgname thresh = 0 if len(reasons) > 0: thresh = min([reason.height for reason in reasons]) self.reasons = [reason for reason in reasons if reason.height <= thresh] self.height = 1+thresh def __str__(self): if len(self.reasons) == 0: return self.pkgname if len(self.reasons) == 1: return self.pkgname+"<-"+str(self.reasons[0]) else: return self.pkgname+"<-{"+(",".join([str(reason) for reason in self.reasons]))+"}" # keeping track of 'visited' is important because of cycles def getreasons(reasons, dupname, visited=[]): global deps global pkgs if dupname in reasons: return DepTree(dupname) required_by = [pkgname for pkgname, deplist in deps.items() if (dupname in [dep.name for dep in deplist])] in_groups = pkgs[dupname].groups myreasons_pkgs = [getreasons(reasons, myreason, visited+[dupname]) for myreason in set(required_by)-set(visited)] myreasons_grps = [DepTree(g) for g in reasons.intersection(set(pkgs[dupname].groups))] return DepTree(dupname, myreasons_pkgs + myreasons_grps) def main(args): pycman_options = pycman.config.make_parser().parse_args([]) handle = pycman.config.init_with_config_and_options(pycman_options) showdups = False pkgnames = set() grpnames = set() global dbs, pkgs, deps, ignore dbs = handle.get_syncdbs() pkgs = {} deps = {} ignore = set() for arg in args: if arg == "-d": showdups = True continue pkg = get_by_depspec(arg) if pkg is not None: pkgnames.add(pkg.name) handlepkg(pkg) else: grpnames.add(arg) for pkg in pyalpm.find_grp_pkgs(dbs, arg): ignore.add(pkg.name) handlepkg(pkg) if not showdups: print("\n".join(pkgnames-ignore)) else: reasons = pkgnames.union(grpnames) for dupname in sorted(pkgnames.intersection(ignore)): print(getreasons(reasons-{dupname}, dupname)) return 0 if __name__ == "__main__": import sys ret = main(sys.argv[1:]) sys.exit(ret)