1 |
import rpm |
2 |
import rhpl.arch |
3 |
import string |
4 |
import types |
5 |
from constants import * |
6 |
|
7 |
# set DB_PRIVATE to make rpm happy |
8 |
rpm.addMacro("__dbi_cdb", "create private mpool mp_mmapsize=16Mb mp_size=1Mb") |
9 |
|
10 |
|
11 |
def dEBUG(str): |
12 |
print str |
13 |
|
14 |
def addNewPackageToUpgSet(pkgDict, pkg): |
15 |
"""Check to see if there's already a pkg by the name of pkg already |
16 |
in our dictionary. If not, add this one. If there is, see if |
17 |
this one is 'newer' or has a 'better' arch.""" |
18 |
name = pkg[rpm.RPMTAG_NAME] |
19 |
arch = pkg[rpm.RPMTAG_ARCH] |
20 |
if not pkgDict.has_key((name, arch)): |
21 |
# nope |
22 |
pkgDict[(name,arch)] = pkg |
23 |
else: |
24 |
# first check version |
25 |
val = rpm.versionCompare(pkgDict[(name,arch)], pkg) |
26 |
if val < 0: |
27 |
# we're newer, add this one |
28 |
pkgDict[(name,arch)] = pkg |
29 |
|
30 |
def comparePackageForUpgrade(updDict, h, pkg): |
31 |
val = rpm.versionCompare(h, pkg) |
32 |
if (val > 0): |
33 |
# dEBUG("found older version of %(name)s %(arch)s" % h) |
34 |
pass |
35 |
elif (val < 0): |
36 |
# dEBUG("found newer version of %(name)s %(arch)s" % h) |
37 |
# check if we already have this package in our dictionary |
38 |
addNewPackageToUpgSet(updDict, pkg) |
39 |
else: |
40 |
# dEBUG("found same verison of %(name)s %(arch)s" % h) |
41 |
pass |
42 |
|
43 |
def findBestArch(archlist): |
44 |
bestarch = None |
45 |
for availarch in archlist: |
46 |
newscore = rhpl.arch.score(availarch) |
47 |
# unsupported |
48 |
if newscore <= 0: |
49 |
continue |
50 |
# If old arch is better or same |
51 |
if bestarch and rhpl.arch.score(bestarch) <= newscore: |
52 |
continue |
53 |
|
54 |
# If we get here we're better |
55 |
bestarch = availarch |
56 |
return bestarch |
57 |
|
58 |
def getAvailPackages(hdrlist): |
59 |
# go through and figure out which packages in the header list are |
60 |
# actually applicable for our architecture |
61 |
pkgDict = {} |
62 |
nameDict = {} |
63 |
for h in hdrlist: |
64 |
score1 = rhpl.arch.score(h[rpm.RPMTAG_ARCH]) |
65 |
if (score1): |
66 |
name = h[rpm.RPMTAG_NAME] |
67 |
arch = h[rpm.RPMTAG_ARCH] |
68 |
pkgDict[(name,arch)] = h |
69 |
if nameDict.has_key(name): |
70 |
nameDict[name].append(arch) |
71 |
else: |
72 |
nameDict[name] = [ arch ] |
73 |
return (pkgDict, nameDict) |
74 |
|
75 |
def getInstalledPackages(dbPath='/'): |
76 |
pkgDict = {} |
77 |
nameDict = {} |
78 |
ts = rpm.TransactionSet(dbPath) |
79 |
ts.setVSFlags(~(rpm.RPMVSF_NORSA|rpm.RPMVSF_NODSA|rpm.RPMVSF_NOMD5)) |
80 |
mi = ts.dbMatch() |
81 |
for h in mi: |
82 |
name = h[rpm.RPMTAG_NAME] |
83 |
arch = h[rpm.RPMTAG_ARCH] |
84 |
pkgDict[(name,arch)] = h |
85 |
if nameDict.has_key(name): |
86 |
nameDict[name].append(arch) |
87 |
else: |
88 |
nameDict[name] = [ arch ] |
89 |
return (pkgDict, nameDict) |
90 |
|
91 |
def findpackageset(hdrlist, dbPath='/'): |
92 |
instDict = {} |
93 |
availDict = {} |
94 |
updDict = {} |
95 |
|
96 |
# dicts for name : [archlist] |
97 |
availNames = {} |
98 |
instNames = {} |
99 |
|
100 |
ts = rpm.TransactionSet(dbPath) |
101 |
ts.setVSFlags(~(rpm.RPMVSF_NORSA|rpm.RPMVSF_NODSA|rpm.RPMVSF_NOMD5)) |
102 |
|
103 |
(availDict, availNames) = getAvailPackages(hdrlist) |
104 |
(instDict, instNames) = getInstalledPackages(dbPath=dbPath) |
105 |
|
106 |
hdlist = availDict.values() |
107 |
|
108 |
# loop through packages and find ones which are a newer |
109 |
# version than what we have |
110 |
for ( name, arch ) in instDict.keys(): |
111 |
# See if we have a better arch than that installed |
112 |
if name in availNames.keys(): |
113 |
bestarch = findBestArch(availNames[name]) |
114 |
if not bestarch: |
115 |
continue |
116 |
if availDict.has_key((name,bestarch)): |
117 |
h = instDict[(name,arch)] |
118 |
pkg = availDict[(name,bestarch)] |
119 |
comparePackageForUpgrade(updDict, h, pkg) |
120 |
|
121 |
# handle obsoletes |
122 |
for pkg in hdlist: |
123 |
if (pkg[rpm.RPMTAG_NAME],pkg[rpm.RPMTAG_ARCH]) in updDict.keys(): |
124 |
# dEBUG("%(name)s %(arch)s is already selected" % pkg) |
125 |
continue |
126 |
|
127 |
if pkg[rpm.RPMTAG_OBSOLETENAME] is not None: |
128 |
name = pkg[rpm.RPMTAG_NAME] |
129 |
arch = pkg[rpm.RPMTAG_ARCH] |
130 |
for obs,obsver in zip(pkg[rpm.RPMTAG_OBSOLETENAME],pkg[rpm.RPMTAG_OBSOLETEVERSION]): |
131 |
mi = ts.dbMatch('name', obs) |
132 |
oevr = strToVersion(obsver) |
133 |
for h in mi: |
134 |
if not obsver: |
135 |
# unversioned obsoletes win |
136 |
addNewPackageToUpgSet(updDict, pkg) |
137 |
# dEBUG("adding %(name)s to the upgrade set for obsoletes" % pkg) |
138 |
break |
139 |
else: |
140 |
if h[rpm.RPMTAG_EPOCH] is None: |
141 |
epoch = '0' |
142 |
else: |
143 |
epoch = str(h[rpm.RPMTAG_EPOCH]) |
144 |
val = compareEVR(oevr,(epoch,h[rpm.RPMTAG_VERSION],h[rpm.RPMTAG_RELEASE])) |
145 |
if val > 0: |
146 |
# dEBUG("adding %(name)s %(version)s to the upgrade set for obsoletes" % pkg) |
147 |
updDict[(name,arch)] = pkg |
148 |
break |
149 |
|
150 |
return updDict.values() |
151 |
|
152 |
def rpmOutToStr(arg): |
153 |
if type(arg) != types.StringType: |
154 |
# and arg is not None: |
155 |
arg = str(arg) |
156 |
|
157 |
return arg |
158 |
|
159 |
def compareEVR((e1, v1, r1), (e2, v2, r2)): |
160 |
# return 1: a is newer than b |
161 |
# 0: a and b are the same version |
162 |
# -1: b is newer than a |
163 |
e1 = rpmOutToStr(e1) |
164 |
v1 = rpmOutToStr(v1) |
165 |
r1 = rpmOutToStr(r1) |
166 |
e2 = rpmOutToStr(e2) |
167 |
v2 = rpmOutToStr(v2) |
168 |
r2 = rpmOutToStr(r2) |
169 |
rc = rpm.labelCompare((e1, v1, r1), (e2, v2, r2)) |
170 |
return rc |
171 |
|
172 |
def strToVersion(str): |
173 |
"""Parse a string such as in obsoleteversion into evr. |
174 |
Gratuitously borrowed from yum str_to_version |
175 |
FIXME: should be implemented in and use rpmUtils""" |
176 |
i = string.find(str, ':') |
177 |
if i != -1: |
178 |
epoch = string.atol(str[:i]) |
179 |
else: |
180 |
epoch = '0' |
181 |
j = string.find(str, '-') |
182 |
if j != -1: |
183 |
if str[i + 1:j] == '': |
184 |
version = None |
185 |
else: version = str[i + 1:j] |
186 |
release = str[j + 1:] |
187 |
else: |
188 |
if str[i + 1:] == '': |
189 |
version = None |
190 |
else: |
191 |
version = str[i + 1:] |
192 |
release = None |
193 |
return (epoch, version, release) |
194 |
|
195 |
|
196 |
if __name__ == "__main__": |
197 |
import sys, os |
198 |
|
199 |
if len(sys.argv) < 2: |
200 |
print "Usage: %s /path/to/tree [rootpath]" %(sys.argv[0],) |
201 |
sys.exit(0) |
202 |
|
203 |
tree = sys.argv[1] |
204 |
if len(sys.argv) >= 3: |
205 |
instPath = sys.argv[2] |
206 |
else: |
207 |
instPath = "/" |
208 |
|
209 |
fd = os.open("%s/%s/base/hdlist" %(tree, productPath), os.O_RDONLY) |
210 |
hdlist = rpm.readHeaderListFromFD(fd) |
211 |
os.close(fd) |
212 |
|
213 |
|
214 |
packages = findpackageset(hdlist, instPath) |
215 |
for pkg in packages: |
216 |
print pkg[rpm.RPMTAG_NAME] |
217 |
|