1 import rpm, os, sys, re
6 class RPMInstallCallback:
8 command line callback class for callbacks from the RPM library.
11 def __init__(self, ts, output=1):
13 self.callbackfilehandles = {}
14 self.total_actions = 0
15 self.total_installed = 0
16 self.installed_pkg_names = []
17 self.total_removed = 0
21 self.tsInfo = None # this needs to be set for anything else to work
25 def _dopkgtup(self, hdr):
26 tmpepoch = hdr['epoch']
27 if tmpepoch is None: epoch = '0'
28 else: epoch = str(tmpepoch)
30 return (hdr['name'], hdr['arch'], epoch, hdr['version'], hdr['release'])
32 def _makeHandle(self, hdr):
33 handle = '%s:%s.%s-%s-%s' % (hdr['epoch'], hdr['name'], hdr['version'],
34 hdr['release'], hdr['arch'])
38 def _localprint(self, msg):
42 def _makefmt(self, percent, progress = True):
43 l = len(str(self.total_actions))
44 size = "%s.%s" % (l, l)
45 fmt_done = "[%" + size + "s/%" + size + "s]"
46 done = fmt_done % (self.total_installed + self.total_removed,
48 marks = self.marks - (2 * l)
49 width = "%s.%s" % (marks, marks)
50 fmt_bar = "%-" + width + "s"
52 bar = fmt_bar % (self.mark * int(marks * (percent / 100.0)), )
53 fmt = "\r %-10.10s: " + bar + " " + done
55 bar = fmt_bar % (self.mark * marks, )
56 fmt = " %-10.10s: " + bar + " " + done
59 def _logPkgString(self, hdr):
60 """return nice representation of the package for the log"""
61 (n,a,e,v,r) = self._dopkgtup(hdr)
63 pkg = '%s.%s %s-%s' % (n, a, v, r)
65 pkg = '%s.%s %s:%s-%s' % (n, a, e, v, r)
69 def callback(self, what, bytes, total, h, user):
70 if what == rpm.RPMCALLBACK_TRANS_START:
72 self.total_actions = total
74 elif what == rpm.RPMCALLBACK_TRANS_PROGRESS:
77 elif what == rpm.RPMCALLBACK_TRANS_STOP:
80 elif what == rpm.RPMCALLBACK_INST_OPEN_FILE:
85 hdr = readRpmHeader(self.ts, h)
86 handle = self._makeHandle(hdr)
87 fd = os.open(rpmloc, os.O_RDONLY)
88 self.callbackfilehandles[handle]=fd
89 self.total_installed += 1
90 self.installed_pkg_names.append(hdr['name'])
93 self._localprint("No header - huh?")
95 elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE:
99 hdr = readRpmHeader(self.ts, h)
100 handle = self._makeHandle(hdr)
101 os.close(self.callbackfilehandles[handle])
105 #pkgtup = self._dopkgtup(hdr)
106 self.logString.append(self._logPkgString(hdr))
109 elif what == rpm.RPMCALLBACK_INST_PROGRESS:
111 percent = (self.total_installed*100L)/self.total_actions
112 if self.output and (sys.stdout.isatty() or self.total_installed == self.total_actions):
113 fmt = self._makefmt(percent)
114 msg = fmt % ("Installing")
115 if msg != self.lastmsg:
116 sys.stdout.write(msg)
119 if self.total_installed == self.total_actions:
120 sys.stdout.write("\n")
121 logging.info('\n'.join(self.logString))
123 elif what == rpm.RPMCALLBACK_UNINST_START:
126 elif what == rpm.RPMCALLBACK_UNINST_PROGRESS:
129 elif what == rpm.RPMCALLBACK_UNINST_STOP:
130 self.total_removed += 1
132 elif what == rpm.RPMCALLBACK_REPACKAGE_START:
134 elif what == rpm.RPMCALLBACK_REPACKAGE_STOP:
136 elif what == rpm.RPMCALLBACK_REPACKAGE_PROGRESS:
139 def readRpmHeader(ts, filename):
140 """ Read an rpm header. """
141 fd = os.open(filename, os.O_RDONLY)
142 h = ts.hdrFromFdno(fd)
146 def splitFilename(filename):
148 Pass in a standard style rpm fullname
150 Return a name, version, release, epoch, arch, e.g.::
151 foo-1.0-1.i386.rpm returns foo, 1.0, 1, i386
152 1:bar-9-123a.ia64.rpm returns bar, 9, 123a, 1, ia64
155 if filename[-4:] == '.rpm':
156 filename = filename[:-4]
158 archIndex = filename.rfind('.')
159 arch = filename[archIndex+1:]
161 relIndex = filename[:archIndex].rfind('-')
162 rel = filename[relIndex+1:archIndex]
164 verIndex = filename[:relIndex].rfind('-')
165 ver = filename[verIndex+1:relIndex]
167 epochIndex = filename.find(':')
171 epoch = filename[:epochIndex]
173 name = filename[epochIndex + 1:verIndex]
174 return name, ver, rel, epoch, arch
176 def getCanonX86Arch(arch):
179 f = open("/proc/cpuinfo", "r")
180 lines = f.readlines()
183 if line.startswith("model name") and line.find("Geode(TM)") != -1:
186 # only athlon vs i686 isn't handled with uname currently
190 # if we're i686 and AuthenticAMD, then we should be an athlon
191 f = open("/proc/cpuinfo", "r")
192 lines = f.readlines()
195 if line.startswith("vendor") and line.find("AuthenticAMD") != -1:
197 # i686 doesn't guarantee cmov, but we depend on it
198 elif line.startswith("flags") and line.find("cmov") == -1:
203 def getCanonX86_64Arch(arch):
208 f = open("/proc/cpuinfo", "r")
209 lines = f.readlines()
212 if line.startswith("vendor_id"):
213 vendor = line.split(':')[1]
218 if vendor.find("Authentic AMD") != -1 or vendor.find("AuthenticAMD") != -1:
220 if vendor.find("GenuineIntel") != -1:
227 if (len(arch) == 4 and arch[0] == "i" and arch[2:4] == "86"):
228 return getCanonX86Arch(arch)
231 return getCanonX86_64Arch(arch)
235 # dict mapping arch -> ( multicompat, best personality, biarch personality )
236 multilibArches = { "x86_64": ( "athlon", "x86_64", "athlon" ),
237 "sparc64v": ( "sparc", "sparcv9v", "sparc64v" ),
238 "sparc64": ( "sparc", "sparcv9", "sparc64" ),
239 "ppc64": ( "ppc", "ppc", "ppc64" ),
240 "s390x": ( "s390", "s390x", "s390" ),
258 "ppc64pseries": "ppc64",
259 "ppc64iseries": "ppc64",
268 "sparc64v": "sparc64",
269 "sparc64v": "sparcv9v",
270 "sparc64": "sparcv9",
271 "sparcv9v": "sparcv9",
272 "sparcv9": "sparcv8",
277 "alphaev7": "alphaev68",
278 "alphaev68": "alphaev67",
279 "alphaev67": "alphaev6",
280 "alphaev6": "alphapca56",
281 "alphapca56": "alphaev56",
282 "alphaev56": "alphaev5",
283 "alphaev5": "alphaev45",
284 "alphaev45": "alphaev4",
289 "armv7nhl": "armv7hl",
292 "armv6l": "armv5tejl",
293 "armv5tejl": "armv5tel",
294 "armv5tel": "noarch",
305 def isMultiLibArch(arch=None):
306 """returns true if arch is a multilib arch, false if not"""
310 if not arches.has_key(arch): # or we could check if it is noarch
313 if multilibArches.has_key(arch):
316 if multilibArches.has_key(arches[arch]):
322 myarch = getCanonArch()
323 if not arches.has_key(myarch):
326 if isMultiLibArch(arch=myarch):
327 if multilibArches.has_key(myarch):
330 return arches[myarch]
332 if arches.has_key(myarch):
334 value = arches[basearch]
335 while value != 'noarch':
337 value = arches[basearch]
341 def checkRpmIntegrity(bin_rpm, package):
342 argv = [bin_rpm, "--checksig", "--nogpg", package]
343 dev_null = os.open("/dev/null", os.O_WRONLY)
345 ret = subprocess.call(argv, stdout = dev_null, stderr = dev_null)
350 def checkSig(ts, package):
351 """Takes a transaction set and a package, check it's sigs,
352 return 0 if they are all fine
353 return 1 if the gpg key can't be found
354 return 2 if the header is in someway damaged
355 return 3 if the key is not trusted
356 return 4 if the pkg is not gpg or pgp signed"""
359 currentflags = ts.setVSFlags(0)
360 fdno = os.open(package, os.O_RDONLY)
362 hdr = ts.hdrFromFdno(fdno)
364 if str(e) == "public key not availaiable":
366 if str(e) == "public key not available":
368 if str(e) == "public key not trusted":
370 if str(e) == "error reading package header":
373 error, siginfo = getSigInfo(hdr)
383 except OSError, e: # if we're not opened, don't scream about it
386 ts.setVSFlags(currentflags) # put things back like they were before
390 """checks signature from an hdr hand back signature information and/or
393 locale.setlocale(locale.LC_ALL, 'C')
394 string = '%|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|'
395 siginfo = hdr.sprintf(string)
396 if siginfo != '(none)':
398 sigtype, sigdate, sigid = siginfo.split(',')
405 infotuple = (sigtype, sigdate, sigid)
406 return error, infotuple