#!/usr/bin/python
# -*- coding: utf-8 -*-
# -*- vim: set ts=4 sw=4 sts=4: -*-
#
# Copyright © 2004 Ed Catmur
# Distributed under the terms of the GNU General Public License v2.
#

__author__ = "Ed Catmur"
__email__ = "ed@catmur.co.uk"
__version__ = "0.0.1"
__productname__ = "depgraph"
__description__ = "Gentoo world depgraph abstraction"

import os, sys, re, string, types
sys.path.insert(0, "/usr/lib/portage/pym")
from output import *
import portage

spinner="\|/-\|/-"
spinpos=0
def update_spinner():
	global spinner, spinpos
	if sys.stdout.isatty():
		portage.writemsg("\b"+spinner[spinpos])
		spinpos=(spinpos+1)%8

def genericdict(mylist):
	mynewdict={}
	for x in mylist:
		mynewdict[portage.dep_getkey(x)]=x
	return mynewdict

#Freeze the portdbapi for enhanced performance:
portage.portdb.freeze()

olddbapi=None
class depgraph:
	def __init__(self):
		global olddbapi
		self.pkgsettings = portage.config(clone=portage.settings)
		if not self.pkgsettings["ARCH"]:
			portage.writemsg(red("\a!!! ARCH is not set... Are you missing the /etc/make.profile symlink?\n"))
			portage.writemsg(red("\a!!! Is the symlink correct? Is your portage tree complete?\n\n"))
			sys.exit(9)
		
		self.digraph=portage.digraph()
		self.fakedbapi=portage.fakedbapi()
		self.mydbapi={}
		self.mydbapi["/"]=self.fakedbapi
		if portage.root!="/":
			self.mydbapi[portage.root]=self.fakedbapi

	def create(self,mybigkey,myparent=None):
		"""creates the actual digraph of packages to merge.  return 1 on success, 0 on failure
		mybigkey = specification of package to merge; myparent = parent package (one depending on me)"""
		
		jbigkey=string.join(mybigkey)
		if self.digraph.hasnode(jbigkey):
			#this conditional is needed to prevent infinite recursion on already-processed deps
			return 1

		update_spinner()

		myroot,mykey=mybigkey
		self.pkgsettings.setcpv(mykey)

		# select the correct /var database that we'll be checking against
		vardbapi=portage.db[myroot]["vartree"].dbapi

		# whatever the case, we need to add the node to our digraph so
		# that children can depend upon it.
		self.digraph.addnode(string.join(mybigkey),myparent)

		edepend={}
		try:
			for x in ["DEPEND","RDEPEND","PDEPEND","CDEPEND"]:
				edepend[x]=string.join(portage.portdb.aux_get(mykey,[x]), " ")
		except (KeyError,IOError):
			print "emerge: create(): aux_get() error on",mykey+"; aborting..."
			sys.exit(1)
		mydep={}	
		mp=string.join(mybigkey)

		if myroot=="/":
			mydep["/"]=edepend["DEPEND"]+" "+edepend["RDEPEND"]
			if not self.select_dep("/",mydep["/"],myparent=mp):
				return 0
		else:
			mydep["/"]=edepend["DEPEND"]
			mydep[myroot]=edepend["RDEPEND"]
			if not self.select_dep("/",mydep["/"],myparent=mp):
				return 0
			elif not self.select_dep(myroot,mydep[myroot],myparent=mp):
				return 0

		if edepend.has_key("PDEPEND") and edepend["PDEPEND"]:
			# Post Depend -- Add to the list without a parent, as it depends
			# on a package being present AND must be built after that package.
			if not self.select_dep(myroot,edepend["PDEPEND"]):
				return 0
			
		return 1
			
	def select_dep(self,myroot,depstring,myparent=None):
		"given a dependency string, create the appropriate depgraph and return 1 on success and 0 on failure"
		#processing dependencies
		mycheck=portage.dep_check(depstring,self.mydbapi[myroot],self.pkgsettings)
		if not mycheck[0]:
			return 0
		mymerge=mycheck[1]
		for x in mymerge:
			myk=None
			if x[0]=="!":
				continue
			else:
				#We are not processing a blocker but a normal dependency
				myeb=portage.portdb.xmatch("bestmatch-visible",x)
				myk=[myroot,myeb]

			if not self.create(myk,myparent):
				return 0
		return 1

	def xcreate(self):
		portage.writemsg("Calculating world dependencies  ")
		syslist = portage.settings.packages
		worldlist = portage.grabfile(portage.root + "var/cache/edb/world")
		virtuals = portage.settings.virtuals
		myvarlist = portage.vardbapi(portage.root).cp_all()
		sysdict=genericdict(syslist)
		worlddict=genericdict(worldlist)
		mylist=[v for k, v in sysdict.iteritems() ] + \
				[v for k, v in worlddict.iteritems() if portage.db["/"]["vartree"].dbapi.match(k)]
		for mydep in mylist:
			myeb=portage.portdb.xmatch("bestmatch-visible",mydep)
			if not myeb:
				portage.writemsg(red("!!! Unavailable world entry: ") + "%s %s\n" % (myeb, mydep))
				continue
			
			myk=[portage.root,myeb]
			if not self.create(myk):
				portage.writemsg(red("!!! Problem with ") + "%s\n" % myeb)
				portage.writemsg(red("!!! Possibly a DEPEND/*DEPEND problem.\n"))
		portage.writemsg("\b\b ... done!\n")

if __name__ == "__main__":
	print "This module is for import only"
