Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 2938 | Differences between
and this patch

Collapse All | Expand All

(-)emerge.orig (-3 / +245 lines)
Lines 11-17 Link Here
11
from stat import *
11
from stat import *
12
from output import *
12
from output import *
13
13
14
import portage
14
import portage, portage_dep
15
import portage_util
15
import portage_util
16
import portage_locks
16
import portage_locks
17
import portage_exception
17
import portage_exception
Lines 35-41 Link Here
35
	colours: a List of Functions taking and returning a String, used to 
35
	colours: a List of Functions taking and returning a String, used to 
36
	process the responses for display. Typically these will be functions 
36
	process the responses for display. Typically these will be functions 
37
	like red() but could be e.g. lambda x: "DisplayString".
37
	like red() but could be e.g. lambda x: "DisplayString".
38
	If responses is omitted, defaults to ["Yes, "No"], [green, red].
38
	If responses is omitted, defaults to ["Yes", "No"], [green, red].
39
	If only colours is omitted, defaults to [bold, ...].
39
	If only colours is omitted, defaults to [bold, ...].
40
40
41
	Returns a member of the List responses. (If called without optional
41
	Returns a member of the List responses. (If called without optional
Lines 1820-1825 Link Here
1820
			else:
1820
			else:
1821
				sys.exit(0)
1821
				sys.exit(0)
1822
1822
1823
# Helper function; I can't seem to find another function to do this...
1824
def cpv_satisfies_dep(cpv, atom):
1825
	# hack. Move along now.
1826
	#print "cpv_satisfies_dep:", cpv, atom
1827
	return ( len(portage.match_from_list(atom, [cpv])) > 0 )
1828
1829
1830
class revdepgraph:
1831
	"A reverse dependency graph. What depends upon this package?"
1832
1833
	def __init__(self):
1834
		self.pkgsettings = portage.config(clone=portage.settings)
1835
		if not self.pkgsettings["ARCH"]:
1836
			portage.writemsg(red("\a!!! ARCH is not set... Are you missing the /etc/make.profile symlink?\n"))
1837
			portage.writemsg(red("\a!!! Is the symlink correct? Is your portage tree complete?\n\n"))
1838
			sys.exit(9)
1839
		self.applied_useflags = {}
1840
1841
		self.digraph=portage.digraph()
1842
1843
	def potential_revdeps(self, cpv):
1844
		" Returns a list of tuples (cpv, depstring) that /might/ depend upon cpv. "
1845
		" Only considers run-time dependencies (RDEPEND). "
1846
		vardbapi=portage.db[self.myroot]["vartree"].dbapi
1847
		mycp=portage.pkgsplit(cpv)[0]
1848
		myprovide=vardbapi.aux_get(cpv, ["PROVIDE"])[0].split()
1849
		
1850
		myret=[]
1851
		for x in vardbapi.cpv_all():
1852
			#myrawdep=string.join(vardbapi.aux_get(x,["DEPEND","RDEPEND","PDEPEND"]), " ")
1853
			myrawdep=string.join(vardbapi.aux_get(x,self.depvars), " ")
1854
			if string.find(myrawdep, mycp) != -1:
1855
				myret.append( (x,myrawdep) )
1856
			for p in myprovide:
1857
				if string.find(myrawdep, p) != -1:
1858
					myret.append( (x,myrawdep) )
1859
			#print "potential revdeps for "+cpv+":",map(lambda x:x[0],myret)
1860
		return myret
1861
1862
	def parse_dep(self, atom, cpv, others):
1863
		""" Returns 1 if cpv and no package in others will satisfy atom, 0 otherwise.
1864
		atom is either a DEPEND atom, or a list beginning with '||'. """
1865
		if type(atom) is list:
1866
			# We have a '||' construct.
1867
			mylist = atom[:]
1868
			head = mylist.pop(0)
1869
			if head == "||":
1870
				# Does cpv satisfy any of the alternatives? If not, return 0.
1871
				if True not in map(lambda x:cpv_satisfies_dep(cpv,x), mylist):
1872
					return 0
1873
				# cpv satisfies the || dep. Now check the others.
1874
				for p in others:
1875
					if True in map(lambda x:cpv_satisfies_dep(cpv,x), mylist):
1876
						# Another packages satisfies it.
1877
						return 0
1878
				return 1
1879
			else:
1880
				portage.writemsg("revdepgraph: parse_dep: don't understand " + str(atom) + ".\n")
1881
				raise ValueError, str(atom)
1882
		else:
1883
			#print "atom: " + atom
1884
			if portage.pkgsplit(portage.dep_getcpv(atom)):
1885
				mycp = portage.pkgsplit( portage.dep_getcpv(atom) )[0]
1886
			else:
1887
				mycp = atom
1888
			if mycp in portage.settings.virtuals.keys():
1889
				#print "testing virtual",mycp
1890
				myop = portage.get_operator(atom)
1891
				if not myop:
1892
					# A virtual. Yay.
1893
					vardbapi = portage.db[self.myroot]["vartree"].dbapi
1894
					myprovide = vardbapi.aux_get(cpv, ["PROVIDE"])[0].split()
1895
					#print "myprovide:",myprovide
1896
					if mycp not in myprovide:
1897
						#print "mycp not in myprovide"
1898
						return 0
1899
					for p in others:
1900
						myprovide = vardbapi.aux_get(p, ["PROVIDE"])[0].split()
1901
						if mycp in myprovide:
1902
							#print p,"satisfies virtual",mycp
1903
							return 0
1904
					return 1
1905
				else:
1906
					# A virtual with an operator. Even better.
1907
					vardbapi = portage.db[self.myroot]["vartree"].dbapi
1908
					myprovide = vardbapi.aux_get(cpv, ["PROVIDE"])[0].split()
1909
					if mycp not in myprovide:
1910
						return 0
1911
					# It provides the right virtual; does it have the right version number?
1912
					mycpver,mycprev = portage.pkgsplit(cpv)[1:3]
1913
					# This is probably cleaner than switching through all the operators here...
1914
					if not cpv_satisfies_dep(mycp+"-"+mycpver+"-"+mycprev, atom):
1915
						return 0
1916
					for p in others:
1917
						myprovide = vardbapi.aux_get(cpv, ["PROVIDE"])[0].split()
1918
						if mycp not in myprovide:
1919
							continue
1920
						myver,myrev = portage.pkgsplit(p)[1:3]
1921
						if cpv_satisfies_dep(mycp+"-"+myver+"-"+myrev, atom):
1922
							return 0
1923
					return 1
1924
					
1925
			else:
1926
				# A simple depend atom.
1927
				#print "Simple atom", atom
1928
				if not cpv_satisfies_dep(cpv, atom):
1929
					return 0
1930
				for p in others:
1931
					if cpv_satisfies_dep(p, atom):
1932
						return 0
1933
				return 1
1934
		# Stick this here just in case...
1935
		return 0
1936
1937
	def dep_flatten(self, dep):
1938
		" Flattens out every sublist not beginning with '||'. "
1939
		#print "attempting to flatten:", dep
1940
		returnme = []
1941
		for x in dep:
1942
			#print "x:", x
1943
			if type(x) is list and len(x)>0 and x[0] != '||':
1944
				returnme = returnme + self.dep_flatten(x)
1945
			elif type(x) is not list:
1946
				returnme.append(x)
1947
		return returnme
1948
1949
	def workaround_broken_use_dep(self, myrawdep):
1950
		#return string.join(map((lambda x: (x[0]=='!' and x[-1]!='?') and x+'?' or x), string.split(myrawdep)))
1951
		#print "workaround: myrawdep=",myrawdep
1952
		mysplit=myrawdep.split()
1953
		for x in range(0, len(mysplit)-1):
1954
			if mysplit[x][0]=='!' and mysplit[x][-1]!='?' and mysplit[x+1]=='(':
1955
				mysplit[x] = mysplit[x]+'?'
1956
		#print mysplit
1957
		return string.join(mysplit)
1958
	
1959
	def direct_revdeps(self, cpv):
1960
		" Returns a list of first-level reverse dependencies on a given package. "
1961
		#print "calculating revdeps for " + cpv
1962
		vardbapi=portage.db[self.myroot]["vartree"].dbapi
1963
		myinstcpvs = vardbapi.cpv_all()
1964
		while cpv in myinstcpvs:
1965
			myinstcpvs.remove(cpv)
1966
1967
		myrevdeps = []
1968
		
1969
		for myp,myrawdep in self.potential_revdeps(cpv):
1970
			# Check the rdepend string. Does it really require this package?
1971
			#print "checking " + myp
1972
			myuse = vardbapi.aux_get(myp, ["USE"])[0].split()
1973
			#print "mydep=", myrawdep
1974
			# use_reduce doesn't handle '!flag ( package )'; workaround
1975
			mydep = self.workaround_broken_use_dep(myrawdep)
1976
			#print "mydep=", mydep
1977
			mydep = portage_dep.paren_reduce(mydep)
1978
			mydep = portage_dep.dep_opconvert(mydep)
1979
			mydep = portage_dep.use_reduce(mydep,myuse)
1980
			#print "mydep=", mydep
1981
			# At this point we need to flatten out any sublist not beginning with '||'.
1982
			mydep = self.dep_flatten(mydep)
1983
			#print "mydep=", mydep
1984
			for myatom in mydep:
1985
				#print "Checking atom", myatom
1986
				if self.parse_dep(myatom, cpv, myinstcpvs):
1987
					# This package requires cpv. Add it to the list.
1988
					#print "Found revdep " + myp + " for " + cpv
1989
					myrevdeps.append(myp)
1990
					break
1991
				
1992
		return myrevdeps
1993
1994
	def create(self, cpv, myparent=None, addme=1, buildtimedeps=0):
1995
		""" Creates the digraph. This function is a good deal simpler than the normal depgraph creation,
1996
		since there are so many fewer possible scenarios to worry about. """
1997
		#jbigkey = string.join(mybigkey)
1998
		#if self.digraph.hasnode(jbigkey+" unmerge"):
1999
		#	return 1
2000
		if self.digraph.hasnode(cpv):
2001
			return 1
2002
2003
		if buildtimedeps:
2004
			self.depvars=["DEPEND","RDEPEND","PDEPEND"]
2005
		else:
2006
			self.depvars=["RDEPEND"]
2007
		update_spinner()
2008
2009
		#print "mybigkey: ", mybigkey
2010
		#mytype,myroot,mykey = mybigkey
2011
		#self.myroot = myroot
2012
		self.myroot = portage.root
2013
		#if mytype not in ["unmerge"]:
2014
			#portage.writemsg("Using revdeps for something other than unmerge?\n")
2015
2016
		# Check that mykey is valid...
2017
		if not portage.pkgsplit(cpv):
2018
			portage.writemsg("Invalid package key: " + cpv + "\n")
2019
			sys.exit(1)
2020
			
2021
		vardbapi = portage.db[self.myroot]["vartree"].dbapi
2022
2023
		if addme:
2024
			#print "adding '"+cpv+"'; parent=",myparent
2025
			#print self.digraph.allnodes()
2026
			self.digraph.addnode(cpv, myparent)
2027
		
2028
		for mydep in self.direct_revdeps(cpv):
2029
			self.create( mydep, cpv, 1 )
2030
2031
2032
	def getpackages(self):
2033
		#return map(lambda x: string.split(x)[2], self.digraph.allnodes())
2034
		return self.digraph.allnodes()
2035
		
2036
1823
def unmerge(unmerge_action, unmerge_files):
2037
def unmerge(unmerge_action, unmerge_files):
1824
	candidate_catpkgs=[]
2038
	candidate_catpkgs=[]
1825
	global_unmerge=0
2039
	global_unmerge=0
Lines 1906-1911 Link Here
1906
	
2120
	
1907
	pkgmap={}
2121
	pkgmap={}
1908
	numselected=0
2122
	numselected=0
2123
	if unmerge_action=="unmerge" and "--nodeps" not in myopts:
2124
		# Print the calculating deps message here, instead of once per package.
2125
		print
2126
		portage.writemsg("Calculating reverse dependencies  ")
2127
		# Also create the revdepgraph here once, so that we can reuse it. Should be significantly
2128
		# more efficient when unmerging multiple packages.
2129
		myrdepgraph=revdepgraph()
2130
	
1909
	for x in candidate_catpkgs:
2131
	for x in candidate_catpkgs:
1910
		#cycle through all our candidate deps and determine what will and will not get unmerged
2132
		#cycle through all our candidate deps and determine what will and will not get unmerged
1911
		try:
2133
		try:
Lines 1930-1935 Link Here
1930
		if not pkgmap.has_key(mykey):
2152
		if not pkgmap.has_key(mykey):
1931
			pkgmap[mykey]={"protected":[], "selected":[], "omitted":[] }
2153
			pkgmap[mykey]={"protected":[], "selected":[], "omitted":[] }
1932
		if unmerge_action=="unmerge":
2154
		if unmerge_action=="unmerge":
2155
			if "--nodeps" in myopts:
2156
				# We're not interested in revdeps, so just add this package to the pkgmap.
1933
				for y in mymatch:
2157
				for y in mymatch:
1934
					if y not in pkgmap[mykey]["selected"]:
2158
					if y not in pkgmap[mykey]["selected"]:
1935
						pkgmap[mykey]["selected"].append(y)
2159
						pkgmap[mykey]["selected"].append(y)
Lines 1940-1946 Link Here
1940
					print yellow("\a!!! This could be damaging to your system.\n")
2164
					print yellow("\a!!! This could be damaging to your system.\n")
1941
					if "--pretend" not in myopts:
2165
					if "--pretend" not in myopts:
1942
						countdown(10,red("Press Ctrl-C to Stop"))
2166
						countdown(10,red("Press Ctrl-C to Stop"))
1943
2167
			else:
2168
				# Add this package to the revdepgraph.
2169
				for y in mymatch:
2170
					myrdepgraph.create(y)
2171
				
1944
		else:
2172
		else:
1945
			#unmerge_action in ["prune", clean"]
2173
			#unmerge_action in ["prune", clean"]
1946
			slotmap={}
2174
			slotmap={}
Lines 1966-1971 Link Here
1966
					pkgmap[mykey]["selected"].append(slotmap[myslot][ckey])
2194
					pkgmap[mykey]["selected"].append(slotmap[myslot][ckey])
1967
					numselected=numselected+1
2195
					numselected=numselected+1
1968
				#ok, now the last-merged package is protected, and the rest are selected
2196
				#ok, now the last-merged package is protected, and the rest are selected
2197
2198
	if unmerge_action=="unmerge" and "--nodeps" not in myopts:
2199
		# Above, we didn't actually add packages to pkgmap, so we need to do that here.
2200
		print myrdepgraph.getpackages()
2201
		for x in myrdepgraph.getpackages():
2202
			print x
2203
			mycp = portage.pkgsplit(x)[0]
2204
			if not pkgmap.has_key(mycp):
2205
				pkgmap[mycp]={"selected":[],"protected":[],"omitted":[]}
2206
			pkgmap[mycp]["selected"].append(x)
2207
			numselected = numselected+1
2208
				
2209
		sys.stdout.write("\b\b  ...done!\n\n")
2210
		
1969
	if global_unmerge and not numselected:
2211
	if global_unmerge and not numselected:
1970
		print "\n>>> No outdated packages were found on your system.\n"
2212
		print "\n>>> No outdated packages were found on your system.\n"
1971
		return 0
2213
		return 0

Return to bug 2938