#!/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)