summaryrefslogtreecommitdiffstats
path: root/deltarpm.py
blob: aac0c02d9a393ce04a55ad251346859650a2470b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
# author: Lars Herrmann <herrmann@redhat.com>
#	Ahmed Kamal <email.ahmedkamal@googlemail.com>
# license: GPL (see COPYING file in distribution)
#
# this module provides a python wrapper around deltarpm tools written by suse
# 
# TODO: catch exceptions wherever possible and raise useful ones ;)
#	see TODO lines in methods

MAKE='/usr/bin/makedeltarpm'
APPLY='/usr/bin/applydeltarpm'
SEQ_SUFFIX='seq'
SUFFIX='drpm'

# constants for up2date configuration
# major flag to enable or disable use of delta rpms , used in patched up2date
USE_DELTA='useDeltaRpms'
# directory where to store generated rpms - depending on use up2date storage or temp storage for fetching
STORAGE='storageDir'
# directory where to store delta rpm files, normally temporarily
DELTA_STORAGE='deltaStorageDir'
# url to fetch delta rpm files from
DELTA_URL='deltaRpmURL'
# directory where local copies of oldrpms reside
DELTA_OLDRPM_REPOSITORY='deltaOldRpmRepository'
# flag indicates if downloading and verfying sequence files before downloading delta rpms - saves bandwidth
DELTA_USE_SEQ='deltaUseSequences'
# flag indicates if local copies of old rpms should be used
DELTA_USE_OLDRPMS='deltaUseOldRpms'
SIZELIMIT='deltaRpmSizeLimit'

# default setting for STORAGE - same as with up2date
DEFAULT_STORAGE='/var/spool/up2date'
# default setting for DELTA_STORAGE
DEFAULT_DELTA_STORAGE='/var/spool/up2date/deltarpms'

# enable or disable to see verbose messages on stdout
DEBUG=0

import popen2
import string
import os
import glob

class Process:
	"""wrapper class to execute programs and return exitcode and output (stdout and stderr combined)"""
	def __init__(self):
		self.__stdout=None
		self.__returncode=None
		self.__command=None
		self.__args=None

	def run(self, command, *args):
		self.__command=command
		self.__args=args
		cmdline=command+" "+string.join(args, " ")
		if DEBUG:
			print 'DEBUG: %s.%s: executing %s' % (self.__class__, 'run', cmdline)
		pipe = popen2.Popen4(cmdline)
		self.__stdout=pipe.fromchild.read()
		retcode = pipe.wait()
		if os.WIFEXITED(retcode):
			self.__returncode = os.WEXITSTATUS(retcode)
		else:
			self.__returncode = retcode
		# fallback to old implementation - works better ?
		#stdoutp = os.popen(cmdline,'r',1)
		#self.__stdout = stdoutp.read()
		#retcode = stdoutp.close()
		#if retcode is None:
		#	self.__returncode = 0
		#else:
		#	self.__returncode = retcode

	def getOutput(self):
		return self.__stdout

	def returnCode(self):
		return self.__returncode

class RpmDescription:
	"""Wrapper class to encapsulate RPM attributes"""

	def __init__(self, name,version,release,arch, epoch=''):
		"""constructor: provide major attributes in correct order - epoch optional"""
		self.name=name
		self.version=version
		self.release=release
		self.epoch=epoch
		self.arch=arch
		if DEBUG:
			print 'DEBUG: %s.%s: created: %s' % (self.__class__, '__init__', self)

	def rhnFileName(self):
		"""return file name in e:nvr.a notation"""
		if self.epoch:
			return "%s:%s-%s-%s.%s" % (self.epoch, self.name, self.version, self.release, self.arch)
		else:
			return "%s-%s-%s.%s" % (self.name, self.version, self.release, self.arch)

	def evr(self):
		"""return file name in e:vr notation as used in Satellite repository"""
		if self.epoch:
			return "%s:%s-%s" % (self.epoch, self.version, self.release)
		else:
			return "%s-%s" % (self.version, self.release)

	def satellitePath(self):
		"""return file path as used in Satellite repository - relative to /var/satellite"""
		return "%s/%s/%s/%s.rpm" % (self.name, self.evr(), self.arch, self.fileName())

	def fileName(self):
		"""return file name in nvr.a notation as used in up2date storageDir"""
		return "%s-%s-%s.%s" % (self.name, self.version, self.release, self.arch)

	def __str__(self):
		return self.rhnFileName()

class DeltaRpmWrapper:
	"""wrapper around deltarpm binaries - implement methods for create, apply and verify delta rpms
	- raises exceptions if exitcode of binaries was != 0"""
	
	def __init__(self, storageDir, oldRpmDir=None):
		"""constructor - params: storageDir=path of delta rpm storage, oldRpmDir = path of full rpm repository (optional)"""
		self.storageDir = storageDir
		self.oldRpmDir = oldRpmDir
		if DEBUG:
			print 'DEBUG: %s.%s: created: %s' % (self.__class__, '__init__', self)

	def __str__(self):
		return "%s: storageDir=%s, oldRpmDir=%s" % (self.__class__, self.storageDir, self.oldRpmDir)

	def create(self, oldrpm, newrpm):
		"""wraps execution of makedeltarpm -s seqfile oldrpm newrpm deltarpm
		constructs file names and paths based on given RpmDescription and instance settings for directories"""
		if DEBUG:
			print 'DEBUG: %s.create(%s,%s)' % (self.__class__,oldrpm, newrpm)

		# contruct filenames in satellite repository
		oldrpmfile = "%s/%s" % (self.oldRpmDir, oldrpm.satellitePath())
		newrpmfile = "%s/%s" % (self.oldRpmDir, newrpm.satellitePath())

		# check if file exists
		# this is an ugly workaround, where the epoch is 0, but satellite
		# stores it as 0:package, so we try it with epoch = string "0"
		# we do glob.glob here, because satellite path could also contain
		# shell wildcards
		if not glob.glob(oldrpmfile):
			if not oldrpm.epoch:
				oldrpm.epoch = '0'
				oldrpmfile = "%s/%s" % (self.oldRpmDir, oldrpm.satellitePath())
		if not glob.glob(newrpmfile):
			if not newrpm.epoch:
				newrpm.epoch = '0'
				newrpmfile = "%s/%s" % (self.oldRpmDir, newrpm.satellitePath())

		# construct filenames in deltarpm repository:
		#   /root/oldrpm/newrpm.{seq|rpm}
		# with oldrpm|newrpm in e:nvr.a notation
		deltarpm = newrpm.rhnFileName()
		# files should go to /root/oldrpm
		deltadir = "%s/%s" % (self.storageDir, oldrpm.rhnFileName())
		# TODO check if is a directory
		if not os.access(deltadir, os.F_OK):
			if DEBUG:
				print 'DEBUG: %s.create: mkdir(%s)' % (__name__, deltadir)
			os.makedirs(deltadir)
		# filenames 
		deltarpmfile = "%s/%s" % (deltadir, deltarpm)
		p=Process()
		p.run(MAKE, '-s', "%s.%s" % (deltarpmfile,SEQ_SUFFIX), oldrpmfile, newrpmfile, "%s.rpm" % deltarpmfile)
		# save output into logfile
		logfile = "%s.log" % deltarpmfile
		fd = open(logfile,'w')
		fd.write(p.getOutput())
		print >> fd,  "of: %s \nnf: %s" % (oldrpmfile, newrpmfile)

		fd.close()
		if p.returnCode():
			raise Exception("%s.create: exitcode was %s - see %s" % (self.__class__,p.returnCode(), logfile))
		return deltarpmfile

	def apply(self, oldrpm, newrpm, deltarpmfile, useOldRpms = 0):
		"""wraps execution of applydeltarpm [-r oldrpm] deltarpm newrpm -
		constructs file names and paths based on given RpmDescription and instance settings for directories"""
		# args: RpmDescription
		# TODO: test args for type == instance and __class__ == RpmDescription
		# TODO: test without useOldRpms
		if DEBUG:
			print 'DEBUG: %s.apply(%s,%s,%s,%s)' % (self.__class__,oldrpm, newrpm, deltarpmfile, useOldRpms)
		p=Process()
		# targetrpm filename
		newrpmfile = "%s/%s-%s-%s.%s.rpm" % (self.storageDir, newrpm.name, newrpm.version, newrpm.release, newrpm.arch)
		if useOldRpms:
			# TODO: check if self.oldRpmDir is set and exists !
			oldrpmfile = "%s/%s-%s-%s.%s.rpm" % (self.oldRpmDir, oldrpm.name, oldrpm.version, oldrpm.release, oldrpm.arch)
			p.run(APPLY, '-r', oldrpmfile, deltarpmfile, newrpmfile)
		else:
			p.run(APPLY, deltarpmfile, newrpmfile)
		if p.returnCode():
			# in case of error save output into logfile - will not be removed for further inspection
			logfile = "%s.log" % deltarpmfile
			fd = open(logfile,'w')
			fd.write(p.getOutput())
			fd.close()
			raise Exception("%s.apply(%s) exitcode was %d - see %s" % (self.__class__, newrpm, p.returnCode(), logfile))
		return newrpmfile

	def verifySequence(self, sequencefile, oldrpm = None, useOldRpms = 0):
		"""wraps execution of applydeltarpm [-r oldrpm] -s seqfilecontent -
		constructs file names and paths based on given RpmDescription and instance settings for directories"""
		if DEBUG:
			print 'DEBUG: %s.verify(%s,%s,%s)' % (self.__class__,sequencefile, oldrpm, useOldRpms)
		# read sequencefile
		fd = open(sequencefile)
		# TODO: is strip safe here ? could remove other chars than the linebreak
		content = string.strip(string.join(fd.readlines()))
		fd.close()
		p = Process()
		if useOldRpms:
			oldrpmfile = "%s/%s-%s-%s.%s.rpm" % (self.oldRpmDir, oldrpm.name, oldrpm.version, oldrpm.release, oldrpm.arch)
			p.run(APPLY, '-s', content, '-r', oldrpmfile)
		else:
			p.run(APPLY, '-s', content)
		if p.returnCode():
			# in case of error save output into logfile - will not be removed for further inspection
			logfile = "%s.log" % deltarpmfile
			fd = open(logfile,'w')
			fd.write(p.getOutput())
			fd.close()
			raise Exception("could not verify sequence of delta rpm: %d - see %s" % (p.returnCode(), logfile))
class Fetcher:
	""" abstract class to be derived from classes implementing fetching seq and rpm files """

	def fetchSequence(self, oldrpm, targetrpm):
		pass

	def fetchDeltaRpm(self, oldrpm, targetrpm):
		pass

class HttpFetcher(Fetcher):
	""" fetching seq and rpm files via http urls"""

	def __init__(self, deltaUrl, destinationDir):
		"""constructor - params: deltaUrl = webapp-url, destinationDir=path to store files"""
		self.deltaUrl = deltaUrl
		self.destinationDir = destinationDir
		if DEBUG:
			print 'DEBUG: %s.%s: created: %s' % (self.__class__, '__init__', self)

	def fetchSequence(self, oldrpm, targetrpm):
		if DEBUG:
			print 'DEBUG: %s.fetchSequence: : (%s,%s)' % (self.__class__, oldrpm, targetrpm)
		return self.__fetchFile(oldrpm, targetrpm, SEQ_SUFFIX, 1)

	# The following method has been disabled by Fedora Infrastructure team, as
	# we will not be using a server side web service, rather, delta rpms will be generated
	# periodically, and client side, will simply download them if applicable
	def __DISABLED__fetchFile(self, oldrpm, targetrpm, suffix, sequence=0):
		"""private method - uses private module to do the http request to rely on http return code"""
		import httppost
		data={}
		data['oldname'] =  oldrpm.name
		data['oldversion'] = oldrpm.version
		data['oldrelease'] = oldrpm.release
		# avoid that httplib would send 'None' and not empty string
		if oldrpm.epoch:
			data['oldepoch'] = oldrpm.epoch
		else:
			data['oldepoch']=''
		data['oldarch'] = oldrpm.arch
		data['newname'] = targetrpm.name
		data['newversion'] = targetrpm.version
		data['newrelease'] = targetrpm.release
		if targetrpm.epoch:
			data['newepoch'] = targetrpm.epoch
		else:
			data['newepoch'] = ''
		data['newarch'] = targetrpm.arch
		if sequence:
			data['sequence']='1'

		fd = httppost.send(self.deltaUrl, data, DEBUG)
		content = fd.read()
		fd.close()
		dest = "%s/%s-%s-%s.%s.%s" % (self.destinationDir, targetrpm.name, targetrpm.version, targetrpm.release, targetrpm.arch, suffix)
		fd=open(dest,'w')
		fd.write(content)
		fd.close
		return dest
	def __fetchFile(self, oldrpm, targetrpm, suffix, sequence=0):
		"""private method - uses private module to download delta rpms"""
		import urllib2
		
		if sequence:
			data['sequence']='1'
		
		drpmName = getDrpmName(oldrpm, targetrpm)
		fullUrl = '%s%s.%s' % (self.deltaUrl,drpmName,suffix)
		if DEBUG:
			print 'DEBUG: oldrpm: %s, newrpm: %s, suffix: %s' % (oldrpm, targetrpm, suffix)
			print 'DEBUG: %s.__fetchFile: : (%s)' % (self.__class__, fullUrl)
		try:
			fd = urllib2.urlopen(fullUrl)
		except IOError, e:
			if hasattr(e, 'reason'):
				raise Exception ("Failed to download delta rpm from URL %s, error: %s" % (fullUrl,e.reason))
			elif hasattr(e, 'code'):
				raise Exception ("Failed to download delta rpm from URL %s, error: %s" % (fullUrl,e.code))
		else:
			content = fd.read()
			fd.close()
			dest = "%s/%s-%s-%s.%s.%s" % (self.destinationDir, targetrpm.name, targetrpm.version, targetrpm.release, targetrpm.arch, suffix)
			fd=open(dest,'w')
			fd.write(content)
			fd.close
			return dest

	def fetchDeltaRpm(self, oldrpm, targetrpm):
		if DEBUG:
			print 'DEBUG: %s.fetchDeltaRpm: : (%s,%s)' % (self.__class__, oldrpm, targetrpm)
		return self.__fetchFile(oldrpm, targetrpm, SUFFIX, 0)

	def __str__(self):
		return "%s: deltaUrl=%s, destinationDir=%s" % (self.__class__, self.deltaUrl, self.destinationDir)

class TestFSFetcher(Fetcher):
	""" fetching seq and rpm files from local filesystem - uses NOT same directory structure as DeltaRpmWrapper.create"""

	def __init__(self, sourceDir, destinationDir):
		self.sourceDir = sourceDir
		self.destinationDir = destinationDir
		if DEBUG:
			print 'DEBUG: %s.%s: created: %s' % (self.__class__, '__init__', self)

	def __str__(self):
		return "%s: sourceDir=%s, destinationDir=%s" % (self.__class__, self.sourceDir, self.destinationDir)

	def __copyFile(self, targetrpm, suffix):
		source = "%s/%s-%s-%s.%s.%s" % (self.sourceDir, targetrpm.name, targetrpm.version, targetrpm.release, targetrpm.arch, suffix)
		# construct new sequence filename
		dest = "%s/%s-%s-%s.%s.%s" % (self.destinationDir, targetrpm.name, targetrpm.version, targetrpm.release, targetrpm.arch, suffix)
		# copy content usind read/write
		fr=open(source,'r')
		content=fr.readlines()
		fr.close()
		fw=open(dest,'w')
		fw.writelines(content)
		fw.close()
		return dest


	def fetchSequence(self, oldrpm, targetrpm):
		if DEBUG:
			print 'DEBUG: %s.fetchSequence(%s,%s)' % (self.__class__, oldrpm, targetrpm)
		return self.__copyFile(targetrpm, SEQ_SUFFIX)

	def fetchDeltaRpm(self, oldrpm, targetrpm):
		if DEBUG:
			print 'DEBUG: %s.fetchDeltaRpm(%s,%s)' % (self.__class__, oldrpm, targetrpm)
		return self.__copyFile(targetrpm, 'rpm')

def getInstalled(targetrpm, sizelimit=0):
	"""retrieve description of installed version from rpm database"""
	if DEBUG:
		print 'DEBUG: %s.getInstalled(%s)' % (__name__, targetrpm)
	import rpm
	ts = rpm.TransactionSet()
	# ts.setVSFlags(-1)
	mi = ts.dbMatch('name', targetrpm.name)
	oldrpm = None
	count = 0
	for h in mi:
		oldrpmtmp = RpmDescription( h['name'], h['version'], h['release'], h['arch'], h['epoch'])
		size = h['size']
		#print "sizelimit: %d, size: %d" % (sizelimit, size)
		if sizelimit > 0 and size > sizelimit:
			raise Exception ("package %s bigger than limit (%d, %d)" % (targetrpm.name, size, sizelimit))
		# TODO: add __cmp__ to RpmDescription to determine most current installed
		# does not matter too much - for reconstruction any installed version is good
		oldrpm = oldrpmtmp
		count+=1
		continue
		if oldrpm:
			if oldrpm > oldrpmtmp:
				oldrpm = oldrpmtmp
			else:
				oldrpm = oldrpmtmp
	# cleanup handles to free all rpmdb transactions - avoid db locking
	del mi
	del ts
	if DEBUG:
		print 'DEBUG: %s.getInstalled(%s): %s matches, using %s' % (__name__, targetrpm, count,oldrpm)
	return oldrpm
		
def getPackageFromDelta(cfg, rpmarray):
	# method to be invoked within up2date
	# return filename of regenerated newrpm
	#
	if DEBUG:
		print 'DEBUG: %s.getPackageFromDelta(%s)' % (__name__, rpmarray)
	sizelimit=0
	if cfg.has_key(SIZELIMIT):
		sizelimit = cfg[SIZELIMIT]
	# 1. retrieve relevant config from rhncfg
	if cfg.has_key(STORAGE):
		storageDir = cfg[STORAGE]
	else:
		storageDir = DEFAULT_STORAGE
	# TODO: check if is directory
	if not os.access(storageDir, os.F_OK):
		if DEBUG:
			print 'DEBUG: %s.getPackageFromDelta: mkdir(%s)' % (__name__, storageDir)
		os.makedirs(storageDir)
	if cfg.has_key(DELTA_STORAGE):
		deltaStorage = cfg[DELTA_STORAGE]
	else:
		deltaStorage = DEFAULT_DELTA_STORAGE
	# TODO: check if is directory
	if not os.access(deltaStorage, os.F_OK):
		if DEBUG:
			print 'DEBUG: %s.getPackageFromDelta: mkdir(%s)' % (__name__, deltaStorage)
		os.makedirs(deltaStorage)
	if cfg.has_key(DELTA_URL):
		deltaUrl = cfg[DELTA_URL]
	else:
		# without URL we can't do anything useful - raise exception and let up2date fall back to its own retrieval
		raise "%s not configured" % DELTA_URL
	oldRpms = None
	if cfg.has_key(DELTA_OLDRPM_REPOSITORY):
		oldRpms = cfg[DELTA_OLDRPM_REPOSITORY]
	# use both config setting where old rpms could be and if they should be used
	if cfg.has_key(DELTA_USE_OLDRPMS):
		useOldRpms = cfg[DELTA_USE_OLDRPMS]
	else:
		# default is to NOT use old rpms
		useOldRpms = 0
	# if old rpms should be used, check if oldRpms is set , warn otherwise
	if useOldRpms:
		if not oldRpms:
			print "warning: configuration inconsistent: cannot use ols rpms without path specified, check %s" % DELTA_OLDRPM_REPOSITORY
			useOldRpms = 0
	if cfg.has_key(DELTA_USE_SEQ):
		useSeq = cfg[DELTA_USE_SEQ] 
	else:
		# default is to NOT use sequence files
		useSeq = 0
	# 2. determine old rpm description
	targetrpm = RpmDescription(rpmarray[0], rpmarray[1], rpmarray[2], rpmarray[4], rpmarray[3])
	oldrpm = getInstalled(targetrpm, sizelimit)
	
	# raise exception if package is not installed
	if not oldrpm:
		raise Exception("%s is not installed" % targetrpm.name)

	# TODO: determine based on URL setting whih fetcher to use
	fetcher = HttpFetcher(deltaUrl, deltaStorage)
	#fetcher = TestFSFetcher('/tmp/deltasource', deltaStorage)
	# wrapper takes only paths as constructor arguments, 
	# flags like useSeq or useOldRpms can be set on every method invocation
	wrapper = DeltaRpmWrapper(storageDir, oldRpms)
	# 3. ifSeq:
	if useSeq:
		# 3.1. download seq
		seqfile = fetcher.fetchSequence(oldrpm, targetrpm)
		if DEBUG:
			print 'DEBUG: %s.getPackageFromDelta: received seq in %s' % (__name__, seqfile)
		# 3.2  verify seq
		wrapper.verifySequence(seqfile, oldrpm, useOldRpms)
	# 4. download deltarpm
	deltafile = fetcher.fetchDeltaRpm(oldrpm, targetrpm)
	if DEBUG:
		print 'DEBUG: %s.getPackageFromDelta: received rpm in %s' % (__name__, deltafile)
	# 5. regenerate newrpm
	newfile = wrapper.apply(oldrpm, targetrpm, deltafile, useOldRpms)
        # output some statistics ;)
        print "successfully reconstructed %s - %d bytes tranferred instead of %d" % (targetrpm, os.stat(deltafile).st_size, os.stat(newfile).st_size)
	# done, cleanup
	# 6. delete seq and deltarpm file if keepAfterInstall is not set
	if cfg.has_key('keepAfterInstall') and cfg['keepAfterInstall']:
		pass
	else:
		# let mkdir operation without try/except as failure would mean that something is really broken
		# up2date would fallback to its retrieval and therefore not rely at all on this code ;)
		if DEBUG:
			print 'DEBUG: %s.getPackageFromDelta: rm(%s)' % (__name__, deltafile)
		os.unlink(deltafile)
		if useSeq:
			if DEBUG:
				print 'DEBUG: %s.getPackageFromDelta: rm(%s)' % (__name__, seqfile)
			os.unlink(seqfile)
	return newfile

def getDrpmName(oldrpm, targetrpm):
	"""Get delta rpm name from old, new rpms, and suffix"""
	dver = "_".join([targetrpm.version, oldrpm.version] )
	drel = "_".join([targetrpm.release ,oldrpm.release] )
	drpmName =  '%s-%s-%s.%s' % (oldrpm.name, dver, drel, oldrpm.arch)
	return drpmName

if __name__ == '__main__':
	import sys
	arg = sys.argv[1]
	newrpm = RpmDescription(arg,'1.0.6','1.4.1','i386')
	old = getInstalled(newrpm, 0)
	old = getInstalled(newrpm, 10000000)

	print old.rhnFileName()
	#p = Process()
	#p.run('find','/var/Satellite','-xdev')
	#print p.getOutput()
	#print p.returnCode()
	print