4 from optparse import OptionParser
7 #from BeautifulSoup import *
15 import subprocess as sub
17 update_repo="file:///home/nashif/system-updates/repo"
18 update_cache="/tmp/updates"
22 class FakeSecHead(object):
23 def __init__(self, fp):
25 self.sechead = '[os-release]\n'
28 try: return self.sechead
29 finally: self.sechead = None
30 else: return self.fp.readline()
32 def get_current_version():
33 config = ConfigParser.SafeConfigParser()
34 config.readfp(FakeSecHead(open('/etc/os-release')))
35 return dict(config.items('os-release'))
38 def checksum(fileName, checksum_type="sha256", excludeLine="", includeLine=""):
39 """Compute sha256 hash of the specified file"""
41 if checksum_type == "md5":
45 fd = open(fileName,"rb")
47 print "Unable to open the file in readmode:", filename
49 content = fd.readlines()
51 for eachLine in content:
52 if excludeLine and eachLine.startswith(excludeLine):
60 print "Checking for new updates..."
61 response = urllib2.urlopen("%s/data/updatemd.xml" % update_repo )
62 updatemd = response.read()
63 if not os.path.exists("%s/data" %update_cache):
64 os.mkdir("%s/data" %update_cache)
66 fp = open("%s/data/updatemd.xml" % update_cache , "w")
70 updatemd_local = open("%s/data/updatemd.xml" % update_cache )
71 root = etree.XML(updatemd_local.read())
72 data = root.xpath("//data[@type='update']")[0]
73 loc = data.xpath("location")[0]
74 href = loc.attrib['href']
75 chksum = data.xpath("checksum")[0]
76 chksum_type = chksum.attrib['type']
78 if os.path.exists("%s/data/updates.xml" % update_cache):
79 cur_sum = checksum("%s/data/updates.xml" % update_cache, checksum_type=chksum_type)
80 if cur_sum == chksum.text:
81 print "Using file from cache, no new updates on server."
83 print "Fetching new updates..."
84 get_new_update_list(href)
86 get_new_update_list(href)
93 fp = open("%s/data/updates.xml" % update_cache , "r")
94 updates_root = etree.XML(fp.read())
95 updates_el = updates_root.xpath("//update")
96 for update in updates_el:
100 up['checksum'] = update.xpath("checksum")[0].text
101 up['title'] = update.xpath("title")[0].text
102 loc = update.xpath("location")[0]
103 up['location'] = "%s" % ( loc.attrib['href'])
105 updates[up['id']] = up
109 def download_update(update_data):
111 location = u['location']
112 if not os.path.exists("%s/downloads/%s" % (update_cache,location)):
113 update_file = urllib2.urlopen("%s/%s" % (update_repo, location) )
114 location = os.path.basename(location)
115 announced_csum = u['checksum']
116 update_raw = update_file.read()
117 fp = open("%s/downloads/%s" % (update_cache,location) , "w")
120 downloaded_csum = checksum("%s/downloads/%s" % (update_cache,location), "sha256")
122 if downloaded_csum != announced_csum:
123 print "Error: Checksum mismatch"
124 os.remove("%s/downloads/%s" % (update_cache,location))
126 print "%s already downloaded" % location
128 def download_all_updates(update_label=None):
129 updates = parse_updates()
131 if update_label is not None:
132 u = updates[update_label]
135 for k in updates.keys():
140 def get_new_update_list(location):
141 up = urllib2.urlopen("%s/%s" % (update_repo, location) )
142 update_raw = up.read()
143 fp = open("%s/data/updates.xml" % update_cache , "w")
148 def prepare_update(update_data):
150 location = u['location']
152 if os.path.exists("%s/downloads/%s" % (update_cache,location)) and not os.path.exists("%s/downloads/%s" % (update_cache,u['id'])):
153 zfile = zipfile.ZipFile("%s/downloads/%s" % (update_cache,location))
154 for name in zfile.namelist():
155 (dirname, filename) = os.path.split(name)
156 print "Decompressing " + filename + " on " + dirname
157 if not os.path.exists("%s/downloads/%s" % (update_cache, dirname)):
158 os.mkdir("%s/downloads/%s" % (update_cache, dirname))
160 fd = open("%s/downloads/%s" % (update_cache, name),"w")
161 fd.write(zfile.read(name))
164 print "Delta Packages:"
165 for delta in os.listdir("%s/downloads/%s/delta" % (update_cache,u['id'])):
168 ts = rpm.TransactionSet()
169 delta_location = "%s/downloads/%s/delta/%s" % (update_cache, u['id'], delta)
170 fdno = os.open(delta_location, os.O_RDONLY)
172 hdr = ts.hdrFromFdno(fdno)
174 target_rpm = "%s-%s-%s.%s.rpm" % (hdr['name'], hdr['version'], hdr['release'], hdr['arch'])
175 target_location = "%s/downloads/%s/packages/%s" % (update_cache, u['id'], target_rpm)
176 version = "_%s.%s.drpm" % (hdr['release'], hdr['arch'])
178 original_rpm = "%s.%s.rpm" %( delta.replace(version, ""), hdr['arch'] )
179 original_rpm = original_rpm.replace("_%s" % hdr['version'], "")
180 print " %s" %original_rpm
182 print " = %s" %target_rpm
186 mi = ts.dbMatch("name", hdr['name'])
189 installed = "%s-%s-%s.%s.rpm" % (r.name, r.version, r.release, r.arch)
190 #original = "%s-%s-%s.%s" % (hdr['name'], hdr['version'], hdr['release'], hdr['arch'])
193 if installed == original_rpm:
196 print "Original availale, delta can be applied. Applying now..."
198 if os.path.exists("/usr/bin/applydeltarpm"):
199 if not os.path.exists(target_location):
200 cmd = '/usr/bin/applydeltarpm %s %s' % (delta_location, target_location)
202 p = sub.Popen(["/usr/bin/applydeltarpm", delta_location, target_location] ,stdout=sub.PIPE,stderr=sub.PIPE)
203 output, errors = p.communicate()
206 print "Target already exists"
208 print "Error: original not available, can't apply delta. We have %s instead of %s" % (installed, original_rpm)
212 def apply_update(update_data):
216 updates = parse_updates()
217 for k in updates.keys():
220 print " %s" %u['title']
223 parser = OptionParser()
224 parser.add_option("-V", "--os-version", action="store_true", dest="osver", default=False,
225 help="Current OS Version")
226 parser.add_option("-l", "--list-updates", action="store_true", dest="listupdates", default=False,
228 parser.add_option("-d", "--download-only", action="store_true", dest="downloadonly", default=False,
229 help="Download only")
230 parser.add_option("-i", "--install", dest="install", metavar="LABEL",
231 help="Install update")
232 parser.add_option("-a", "--install-all", dest="installall", action="store_true", default=False,
233 help="Install all updates")
234 parser.add_option("-r", "--recommended", dest="recommended", action="store_true", default=False,
235 help="Install recommended updates only")
236 parser.add_option("-q", "--quiet",
237 action="store_false", dest="verbose", default=True,
238 help="don't print status messages to stdout")
240 (options, args) = parser.parse_args()
242 if not os.path.exists(update_cache):
243 os.mkdir("%s" % update_cache)
244 os.mkdir("%s/downloads" % update_cache)
247 os_release = get_current_version()
248 print os_release['version_id'].strip('"')
250 if options.listupdates:
254 if options.downloadonly:
256 download_all_updates()
258 if options.install is not None:
260 updates = parse_updates()
261 if not updates.has_key(options.install):
262 print "%s is not available for installation. Abort." %options.install
264 u = updates[options.install]