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 |