#! /usr/local/bin/python

# portgraph - a program to draw dependency graphs for ports
#
# Copyright (C) 2003 by Adriaan de Groot
# This file is released under the BSD license, see /COPYRIGHT
#
# Portgraph prints a dependency graph of the given port(s)
# (or all ports if -a is passed) to stdout, in dot (graphviz)
# format. it uses the information from /usr/ports/INDEX,
# so it only shows mandatory dependencies.

import sys
import re
import getopt
import string

def usage():
    sys.stderr.write("Usage: portgraph [-f INDEX-file] [-h] [-a | port ...]\n")
    sys.stderr.write("       -f reads INDEX-file instead of /usr/ports/INDEX\n")
    sys.stderr.write("       -h prints this help message\n")
    sys.stderr.write("       -a graph _all_ ports\n\n")
    sys.stderr.write("portgraph writes a dot (graphviz) representation of the\n"
			"dependency graph of the ports listed on the command\n"
			"line (or all ports if -a is given) to stdout.\n")
    sys.exit()

try:
    opt,arg = getopt.getopt(sys.argv[1:],"f:ha")
except getopt.GetoptError, e:
    print str(e)
    print ""
    usage()


filename = None
for i in opt:
    if i[0] == "-f":
        filename = i[1]
    elif i[0] == "-h":
        usage()
    elif i[0] == "-a":
        if arg:
            sys.stderr.write("*** Using -a with port names is silly.\n")
        arg=["--all"]
    else:
        usage()

if not filename:
    filename = "/usr/ports/INDEX"

if not arg:
    print "No -a or ports arguments given.\n"
    usage()

f = file(filename)

global depends,expanddepends

depends = {}
expanddepends = {}


def expand_depends(key):
    if not key:
	return
    if expanddepends.has_key(key):
	return
    for i in depends[key]:
	expand_depends(i)
    l = []
    l.extend(depends[key])
    for i in depends[key]:
	if not expanddepends.get(i):
	    continue
        for j in expanddepends[i]:
	    if not j:
		continue
            if not j in l:
                l.append(j)
    # print key," has ",len(l)," total dependencies."
    # for i in l:
    #    print "    ",i
    expanddepends[key]=l

sys.stderr.write("* Reading INDEX\n")
while 1:
    indexline = f.readline()
    if not indexline:
        break
    l = indexline.split('|')
    if depends.get(l[0]):
	print "Duplicated port ",l[0]
    else:
	dep = l[7].split(" ")
	if not dep[0]:
	    dep=[]
	depends[l[0]] = dep

f.close()

for i in arg:
    if i != "--all" and not depends[i]:
        print "*** No package named ",i
        sys.exit(1)

if len(arg)>1:
    depends["ROOT"]=arg

sys.stderr.write("* Expanding dependencies\n")
for i in depends.keys():
    expand_depends(i)

sys.stderr.write("* Pruning dependencies\n")
for i in depends.keys():
    if not expanddepends[i]:
        continue
    l = []
    for j in depends[i]:
        l.extend(expanddepends[j])
    newdepends = []
    for j in depends[i]:
        if not j in l:
            newdepends.append(j)
    depends[i]=newdepends

if arg[0] == "--all":
    sys.stderr.write("* Writing total dependency graph\n")
    sys.stdout.write("digraph \"Dependencies for all packages\" { \n")
    for i in depends.keys():
        for j in depends[i]:
            sys.stdout.write("\"" + i + "\" -> \"" + j + "\"\n")
else:
    sys.stdout.write("digraph \"Dependencies for " + string.join(arg,",") + "\" { \n")
    if len(arg)>1:
        packagename = "ROOT"
    else:
        packagename = arg[0]
    if depends.get(packagename): 
        l = [packagename]
        d = []
        while len(l):
            current = l[0]
            sys.stderr.write("* Writing dependency graph for "+current+"\n")
            l.remove(current)
            if current in d:
                continue
            d.append(current)
            l.extend(depends[current])
            for i in depends[current]:
                sys.stdout.write("\"" + current + "\" -> \"" + i + "\"\n")
    else:
        sys.stderr.write("*** No package named "+packagename+"\n")

sys.stdout.write("}\n")


