Package rpmUtils :: Module miscutils
[hide private]
[frames] | no frames]

Source Code for Module rpmUtils.miscutils

  1  #!/usr/bin/python -tt 
  2   
  3  # This program is free software; you can redistribute it and/or modify 
  4  # it under the terms of the GNU General Public License as published by 
  5  # the Free Software Foundation; either version 2 of the License, or 
  6  # (at your option) any later version. 
  7  # 
  8  # This program is distributed in the hope that it will be useful, 
  9  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 10  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 11  # GNU Library General Public License for more details. 
 12  # 
 13  # You should have received a copy of the GNU General Public License 
 14  # along with this program; if not, write to the Free Software 
 15  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
 16  # Copyright 2003 Duke University 
 17   
 18  import rpm 
 19  import types 
 20  import gzip 
 21  import os 
 22  import sys 
 23  import locale 
 24  import signal 
 25   
 26  import rpmUtils.transaction 
 27   
28 -def rpmOutToStr(arg):
29 if type(arg) != types.StringType: 30 # and arg is not None: 31 arg = str(arg) 32 33 return arg
34 35
36 -def compareEVR((e1, v1, r1), (e2, v2, r2)):
37 # return 1: a is newer than b 38 # 0: a and b are the same version 39 # -1: b is newer than a 40 e1 = str(e1) 41 v1 = str(v1) 42 r1 = str(r1) 43 e2 = str(e2) 44 v2 = str(v2) 45 r2 = str(r2) 46 #print '%s, %s, %s vs %s, %s, %s' % (e1, v1, r1, e2, v2, r2) 47 rc = rpm.labelCompare((e1, v1, r1), (e2, v2, r2)) 48 #print '%s, %s, %s vs %s, %s, %s = %s' % (e1, v1, r1, e2, v2, r2, rc) 49 return rc
50
51 -def checkSig(ts, package):
52 """Takes a transaction set and a package, check it's sigs, 53 return 0 if they are all fine 54 return 1 if the gpg key can't be found 55 return 2 if the header is in someway damaged 56 return 3 if the key is not trusted 57 return 4 if the pkg is not gpg or pgp signed""" 58 59 value = 0 60 currentflags = ts.setVSFlags(0) 61 fdno = os.open(package, os.O_RDONLY) 62 try: 63 hdr = ts.hdrFromFdno(fdno) 64 except rpm.error, e: 65 if str(e) == "public key not availaiable": 66 value = 1 67 if str(e) == "public key not available": 68 value = 1 69 if str(e) == "public key not trusted": 70 value = 3 71 if str(e) == "error reading package header": 72 value = 2 73 else: 74 error, siginfo = getSigInfo(hdr) 75 if error == 101: 76 os.close(fdno) 77 del hdr 78 value = 4 79 else: 80 del hdr 81 82 try: 83 os.close(fdno) 84 except OSError, e: # if we're not opened, don't scream about it 85 pass 86 87 ts.setVSFlags(currentflags) # put things back like they were before 88 return value
89
90 -def getSigInfo(hdr):
91 """checks signature from an hdr hand back signature information and/or 92 an error code""" 93 94 locale.setlocale(locale.LC_ALL, 'C') 95 string = '%|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|' 96 siginfo = hdr.sprintf(string) 97 if siginfo != '(none)': 98 error = 0 99 sigtype, sigdate, sigid = siginfo.split(',') 100 else: 101 error = 101 102 sigtype = 'MD5' 103 sigdate = 'None' 104 sigid = 'None' 105 106 infotuple = (sigtype, sigdate, sigid) 107 return error, infotuple
108
109 -def pkgTupleFromHeader(hdr):
110 """return a pkgtuple (n, a, e, v, r) from a hdr object, converts 111 None epoch to 0, as well.""" 112 113 name = hdr['name'] 114 115 # RPMTAG_SOURCEPACKAGE: RPMTAG_SOURCERPM is not necessarily there for 116 # e.g. gpg-pubkeys imported with older rpm versions 117 # http://lists.baseurl.org/pipermail/yum/2009-January/022275.html 118 if hdr[rpm.RPMTAG_SOURCERPM] or hdr[rpm.RPMTAG_SOURCEPACKAGE] != 1: 119 arch = hdr['arch'] 120 else: 121 arch = 'src' 122 123 ver = hdr['version'] 124 rel = hdr['release'] 125 epoch = hdr['epoch'] 126 if epoch is None: 127 epoch = '0' 128 pkgtuple = (name, arch, epoch, ver, rel) 129 return pkgtuple
130 131
132 -def rangeCheck(reqtuple, pkgtuple):
133 """returns true if the package epoch-ver-rel satisfy the range 134 requested in the reqtuple: 135 ex: foo >= 2.1-1""" 136 # we only ever get here if we have a versioned prco 137 # nameonly shouldn't ever raise it 138 #(reqn, reqf, (reqe, reqv, reqr)) = reqtuple 139 (n, a, e, v, r) = pkgtuple 140 return rangeCompare(reqtuple, (n, 'EQ', (e, v, r)))
141
142 -def rangeCompare(reqtuple, provtuple):
143 """returns true if provtuple satisfies reqtuple""" 144 (reqn, reqf, (reqe, reqv, reqr)) = reqtuple 145 (n, f, (e, v, r)) = provtuple 146 if reqn != n: 147 return 0 148 149 # unversioned satisfies everything 150 if not f or not reqf: 151 return 1 152 153 # and you thought we were done having fun 154 # if the requested release is left out then we have 155 # to remove release from the package prco to make sure the match 156 # is a success - ie: if the request is EQ foo 1:3.0.0 and we have 157 # foo 1:3.0.0-15 then we have to drop the 15 so we can match 158 if reqr is None: 159 r = None 160 if reqe is None: 161 e = None 162 if reqv is None: # just for the record if ver is None then we're going to segfault 163 v = None 164 165 # if we just require foo-version, then foo-version-* will match 166 if r is None: 167 reqr = None 168 169 rc = compareEVR((e, v, r), (reqe, reqv, reqr)) 170 171 # does not match unless 172 if rc >= 1: 173 if reqf in ['GT', 'GE', 4, 12]: 174 return 1 175 if reqf in ['EQ', 8]: 176 if f in ['LE', 10, 'LT', 2]: 177 return 1 178 if reqf in ['LE', 'LT', 'EQ', 10, 2, 8]: 179 if f in ['LE', 'LT', 10, 2]: 180 return 1 181 182 if rc == 0: 183 if reqf in ['GT', 4]: 184 if f in ['GT', 'GE', 4, 12]: 185 return 1 186 if reqf in ['GE', 12]: 187 if f in ['GT', 'GE', 'EQ', 'LE', 4, 12, 8, 10]: 188 return 1 189 if reqf in ['EQ', 8]: 190 if f in ['EQ', 'GE', 'LE', 8, 12, 10]: 191 return 1 192 if reqf in ['LE', 10]: 193 if f in ['EQ', 'LE', 'LT', 'GE', 8, 10, 2, 12]: 194 return 1 195 if reqf in ['LT', 2]: 196 if f in ['LE', 'LT', 10, 2]: 197 return 1 198 if rc <= -1: 199 if reqf in ['GT', 'GE', 'EQ', 4, 12, 8]: 200 if f in ['GT', 'GE', 4, 12]: 201 return 1 202 if reqf in ['LE', 'LT', 10, 2]: 203 return 1 204 # if rc >= 1: 205 # if reqf in ['GT', 'GE', 4, 12]: 206 # return 1 207 # if rc == 0: 208 # if reqf in ['GE', 'LE', 'EQ', 8, 10, 12]: 209 # return 1 210 # if rc <= -1: 211 # if reqf in ['LT', 'LE', 2, 10]: 212 # return 1 213 214 return 0
215 216 217 ########### 218 # Title: Remove duplicates from a sequence 219 # Submitter: Tim Peters 220 # From: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 221
222 -def unique(s):
223 """Return a list of the elements in s, but without duplicates. 224 225 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3], 226 unique("abcabc") some permutation of ["a", "b", "c"], and 227 unique(([1, 2], [2, 3], [1, 2])) some permutation of 228 [[2, 3], [1, 2]]. 229 230 For best speed, all sequence elements should be hashable. Then 231 unique() will usually work in linear time. 232 233 If not possible, the sequence elements should enjoy a total 234 ordering, and if list(s).sort() doesn't raise TypeError it's 235 assumed that they do enjoy a total ordering. Then unique() will 236 usually work in O(N*log2(N)) time. 237 238 If that's not possible either, the sequence elements must support 239 equality-testing. Then unique() will usually work in quadratic 240 time. 241 """ 242 243 n = len(s) 244 if n == 0: 245 return [] 246 247 # Try using a dict first, as that's the fastest and will usually 248 # work. If it doesn't work, it will usually fail quickly, so it 249 # usually doesn't cost much to *try* it. It requires that all the 250 # sequence elements be hashable, and support equality comparison. 251 u = {} 252 try: 253 for x in s: 254 u[x] = 1 255 except TypeError: 256 del u # move on to the next method 257 else: 258 return u.keys() 259 260 # We can't hash all the elements. Second fastest is to sort, 261 # which brings the equal elements together; then duplicates are 262 # easy to weed out in a single pass. 263 # NOTE: Python's list.sort() was designed to be efficient in the 264 # presence of many duplicate elements. This isn't true of all 265 # sort functions in all languages or libraries, so this approach 266 # is more effective in Python than it may be elsewhere. 267 try: 268 t = list(s) 269 t.sort() 270 except TypeError: 271 del t # move on to the next method 272 else: 273 assert n > 0 274 last = t[0] 275 lasti = i = 1 276 while i < n: 277 if t[i] != last: 278 t[lasti] = last = t[i] 279 lasti += 1 280 i += 1 281 return t[:lasti] 282 283 # Brute force is all that's left. 284 u = [] 285 for x in s: 286 if x not in u: 287 u.append(x) 288 return u
289 290
291 -def splitFilename(filename):
292 """ 293 Pass in a standard style rpm fullname 294 295 Return a name, version, release, epoch, arch, e.g.:: 296 foo-1.0-1.i386.rpm returns foo, 1.0, 1, i386 297 1:bar-9-123a.ia64.rpm returns bar, 9, 123a, 1, ia64 298 """ 299 300 if filename[-4:] == '.rpm': 301 filename = filename[:-4] 302 303 archIndex = filename.rfind('.') 304 arch = filename[archIndex+1:] 305 306 relIndex = filename[:archIndex].rfind('-') 307 rel = filename[relIndex+1:archIndex] 308 309 verIndex = filename[:relIndex].rfind('-') 310 ver = filename[verIndex+1:relIndex] 311 312 epochIndex = filename.find(':') 313 if epochIndex == -1: 314 epoch = '' 315 else: 316 epoch = filename[:epochIndex] 317 318 name = filename[epochIndex + 1:verIndex] 319 return name, ver, rel, epoch, arch
320 321
322 -def rpm2cpio(fdno, out=sys.stdout, bufsize=2048):
323 """Performs roughly the equivalent of rpm2cpio(8). 324 Reads the package from fdno, and dumps the cpio payload to out, 325 using bufsize as the buffer size.""" 326 ts = rpmUtils.transaction.initReadOnlyTransaction() 327 hdr = ts.hdrFromFdno(fdno) 328 del ts 329 330 compr = hdr[rpm.RPMTAG_PAYLOADCOMPRESSOR] or 'gzip' 331 #XXX FIXME 332 #if compr == 'bzip2': 333 # TODO: someone implement me! 334 #el 335 if compr != 'gzip': 336 raise rpmUtils.RpmUtilsError, \ 337 'Unsupported payload compressor: "%s"' % compr 338 f = gzip.GzipFile(None, 'rb', None, os.fdopen(fdno, 'rb', bufsize)) 339 while 1: 340 tmp = f.read(bufsize) 341 if tmp == "": break 342 out.write(tmp) 343 f.close()
344
345 -def formatRequire (name, version, flags):
346 s = name 347 348 if flags: 349 if flags & (rpm.RPMSENSE_LESS | rpm.RPMSENSE_GREATER | 350 rpm.RPMSENSE_EQUAL): 351 s = s + " " 352 if flags & rpm.RPMSENSE_LESS: 353 s = s + "<" 354 if flags & rpm.RPMSENSE_GREATER: 355 s = s + ">" 356 if flags & rpm.RPMSENSE_EQUAL: 357 s = s + "=" 358 if version: 359 s = "%s %s" %(s, version) 360 return s
361
362 -def flagToString(flags):
363 flags = flags & 0xf 364 365 if flags == 0: return None 366 elif flags == 2: return 'LT' 367 elif flags == 4: return 'GT' 368 elif flags == 8: return 'EQ' 369 elif flags == 10: return 'LE' 370 elif flags == 12: return 'GE' 371 372 return flags
373
374 -def stringToVersion(verstring):
375 if verstring in [None, '']: 376 return (None, None, None) 377 i = verstring.find(':') 378 if i != -1: 379 try: 380 epoch = str(long(verstring[:i])) 381 except ValueError: 382 # look, garbage in the epoch field, how fun, kill it 383 epoch = '0' # this is our fallback, deal 384 else: 385 epoch = '0' 386 j = verstring.find('-') 387 if j != -1: 388 if verstring[i + 1:j] == '': 389 version = None 390 else: 391 version = verstring[i + 1:j] 392 release = verstring[j + 1:] 393 else: 394 if verstring[i + 1:] == '': 395 version = None 396 else: 397 version = verstring[i + 1:] 398 release = None 399 return (epoch, version, release)
400
401 -def hdrFromPackage(ts, package):
402 """hand back the rpm header or raise an Error if the pkg is fubar""" 403 try: 404 fdno = os.open(package, os.O_RDONLY) 405 except OSError, e: 406 raise rpmUtils.RpmUtilsError, 'Unable to open file' 407 408 # XXX: We should start a readonly ts here, so we don't get the options 409 # from the other one (sig checking, etc) 410 try: 411 hdr = ts.hdrFromFdno(fdno) 412 except rpm.error, e: 413 os.close(fdno) 414 raise rpmUtils.RpmUtilsError, "RPM Error opening Package" 415 if type(hdr) != rpm.hdr: 416 os.close(fdno) 417 raise rpmUtils.RpmUtilsError, "RPM Error opening Package (type)" 418 419 os.close(fdno) 420 return hdr
421
422 -def checkSignals():
423 if hasattr(rpm, "checkSignals") and hasattr(rpm, 'signalsCaught'): 424 if rpm.signalsCaught([signal.SIGINT, 425 signal.SIGTERM, 426 signal.SIGPIPE, 427 signal.SIGQUIT, 428 signal.SIGHUP]): 429 sys.exit(1)
430