replace most of subprocess calls by new runner apis
[tools/mic.git] / mic / utils / misc.py
1 #
2 # misc.py : miscellaneous utilities
3 #
4 # Copyright 2010, 2011 Intel Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; version 2 of the License.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU Library General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 import os
20 import sys
21 import tempfile
22 import re
23 import shutil
24 import glob
25 import hashlib
26
27 try:
28     import sqlite3 as sqlite
29 except ImportError:
30     import sqlite
31
32 try:
33     from xml.etree import cElementTree
34 except ImportError:
35     import cElementTree
36 xmlparse = cElementTree.parse
37
38 from errors import *
39 from fs_related import *
40 from proxy import get_proxy_for
41 import runner
42
43 from mic import msger
44
45 def get_image_type(path):
46
47     def _get_extension_name(path):
48         match = re.search("(?<=\.)\w+$", path)
49         if match:
50             return match.group(0)
51         else:
52             return None
53
54     def _ismeego(rootdir):
55         if (os.path.exists(rootdir + "/etc/moblin-release") \
56             or os.path.exists(rootdir + "/etc/meego-release")) \
57             and os.path.exists(rootdir + "/etc/inittab") \
58             and os.path.exists(rootdir + "/etc/rc.sysinit") \
59             and glob.glob(rootdir + "/boot/vmlinuz-*"):
60             return True
61         else:
62             return False
63
64     if os.path.isdir(path):
65         if _ismeego(path):
66             return "fs"
67         return None
68
69     maptab = {
70               "raw":"raw",
71               "vmdk":"vmdk",
72               "vdi":"vdi",
73               "iso":"livecd",
74               "usbimg":"liveusb",
75              }
76
77     extension = _get_extension_name(path)
78     if extension in maptab:
79         return maptab[extension]
80
81     fd = open(path, "rb")
82     file_header = fd.read(1024)
83     fd.close()
84     vdi_flag = "<<< Sun VirtualBox Disk Image >>>"
85     if file_header[0:len(vdi_flag)] == vdi_flag:
86         return maptab["vdi"]
87
88     output = runner.outs(['file', path])
89     isoptn = re.compile(r".*ISO 9660 CD-ROM filesystem.*(bootable).*")
90     usbimgptn = re.compile(r".*x86 boot sector.*active.*")
91     rawptn = re.compile(r".*x86 boot sector.*")
92     vmdkptn = re.compile(r".*VMware. disk image.*")
93     ext3fsimgptn = re.compile(r".*Linux.*ext3 filesystem data.*")
94     if isoptn.match(output):
95         return maptab["iso"]
96     elif usbimgptn.match(output):
97         return maptab["usbimg"]
98     elif rawptn.match(output):
99         return maptab["raw"]
100     elif vmdkptn.match(output):
101         return maptab["vmdk"]
102     elif ext3fsimgptn.match(output):
103         return "ext3fsimg"
104     else:
105         return None
106
107 def get_file_size(file):
108     """Return size in MB unit"""
109     rc, duOutput  = runner.runtool(['du', "-s", "-b", "-B", "1M", file])
110     if rc != 0:
111         raise CreatorError("Failed to run %s" % du)
112
113     size1 = int(duOutput.split()[0])
114     rc, duOutput = runner.runtool(['du', "-s", "-B", "1M", file])
115     if rc != 0:
116         raise CreatorError("Failed to run %s" % du)
117
118     size2 = int(duOutput.split()[0])
119     if size1 > size2:
120         return size1
121     else:
122         return size2
123
124 def get_filesystem_avail(fs):
125     vfstat = os.statvfs(fs)
126     return vfstat.f_bavail * vfstat.f_bsize
127
128 def convert_image(srcimg, srcfmt, dstimg, dstfmt):
129     #convert disk format
130     if dstfmt != "raw":
131         raise CreatorError("Invalid destination image format: %s" % dstfmt)
132     msger.debug("converting %s image to %s" % (srcimg, dstimg))
133     if srcfmt == "vmdk":
134         path = find_binary_path("qemu-img")
135         argv = [path, "convert", "-f", "vmdk", srcimg, "-O", dstfmt,  dstimg]
136     elif srcfmt == "vdi":
137         path = find_binary_path("VBoxManage")
138         argv = [path, "internalcommands", "converttoraw", srcimg, dstimg]
139     else:
140         raise CreatorError("Invalid soure image format: %s" % srcfmt)
141
142     rc = runner.show(argv)
143     if rc == 0:
144         msger.debug("convert successful")
145     if rc != 0:
146         raise CreatorError("Unable to convert disk to %s" % dstfmt)
147
148 def uncompress_squashfs(squashfsimg, outdir):
149     """Uncompress file system from squshfs image"""
150     unsquashfs = find_binary_path("unsquashfs")
151     args = [ unsquashfs, "-d", outdir, squashfsimg ]
152     rc = runner.show(args)
153     if (rc != 0):
154         raise SquashfsError("Failed to uncompress %s." % squashfsimg)
155
156 def mkdtemp(dir = "/var/tmp", prefix = "mic-tmp-"):
157     makedirs(dir)
158     return tempfile.mkdtemp(dir = dir, prefix = prefix)
159
160 def get_temp_reponame(baseurl):
161     md5obj = hashlib.md5(baseurl)
162     tmpreponame = "%s" % md5obj.hexdigest()
163     return tmpreponame
164
165 def get_repostrs_from_ks(ks):
166     kickstart_repos = []
167     for repodata in ks.handler.repo.repoList:
168         repostr = ""
169         if hasattr(repodata, "name") and repodata.name:
170             repostr += ",name:" + repodata.name
171         if hasattr(repodata, "baseurl") and repodata.baseurl:
172             repostr += ",baseurl:" + repodata.baseurl
173         if hasattr(repodata, "mirrorlist") and repodata.mirrorlist:
174             repostr += ",mirrorlist:" + repodata.mirrorlist
175         if hasattr(repodata, "includepkgs") and repodata.includepkgs:
176             repostr += ",includepkgs:" + ";".join(repodata.includepkgs)
177         if hasattr(repodata, "excludepkgs") and repodata.excludepkgs:
178             repostr += ",excludepkgs:" + ";".join(repodata.excludepkgs)
179         if hasattr(repodata, "cost") and repodata.cost:
180             repostr += ",cost:%d" % repodata.cost
181         if hasattr(repodata, "save") and repodata.save:
182             repostr += ",save:"
183         if hasattr(repodata, "proxy") and repodata.proxy:
184             repostr += ",proxy:" + repodata.proxy
185         if hasattr(repodata, "proxyuser") and repodata.proxy_username:
186             repostr += ",proxyuser:" + repodata.proxy_username
187         if  hasattr(repodata, "proxypasswd") and repodata.proxy_password:
188             repostr += ",proxypasswd:" + repodata.proxy_password
189         if repostr.find("name:") == -1:
190             repostr = ",name:%s" % get_temp_reponame(repodata.baseurl)
191         if hasattr(repodata, "debuginfo") and repodata.debuginfo:
192             repostr += ",debuginfo:"
193         if hasattr(repodata, "source") and repodata.source:
194             repostr += ",source:"
195         if  hasattr(repodata, "gpgkey") and repodata.gpgkey:
196             repostr += ",gpgkey:" + repodata.gpgkey
197         kickstart_repos.append(repostr[1:])
198     return kickstart_repos
199
200 def get_uncompressed_data_from_url(url, filename, proxies):
201     filename = myurlgrab(url, filename, proxies)
202     suffix = None
203     if filename.endswith(".gz"):
204         suffix = ".gz"
205         gunzip = find_binary_path('gunzip')
206         runner.show([gunzip, "-f", filename])
207     elif filename.endswith(".bz2"):
208         suffix = ".bz2"
209         bunzip2 = find_binary_path('bunzip2')
210         runner.show([bunzip2, "-f", filename])
211     if suffix:
212         filename = filename.replace(suffix, "")
213     return filename
214
215 def get_metadata_from_repo(baseurl, proxies, cachedir, reponame, filename):
216     url = str(baseurl + "/" + filename)
217     filename_tmp = str("%s/%s/%s" % (cachedir, reponame, os.path.basename(filename)))
218     return get_uncompressed_data_from_url(url,filename_tmp,proxies)
219
220 def get_metadata_from_repos(repostrs, cachedir):
221     my_repo_metadata = []
222     for repostr in repostrs:
223         reponame = None
224         baseurl = None
225         proxy = None
226         items = repostr.split(",")
227         for item in items:
228             subitems = item.split(":")
229             if subitems[0] == "name":
230                 reponame = subitems[1]
231             if subitems[0] == "baseurl":
232                 baseurl = item[8:]
233             if subitems[0] == "proxy":
234                 proxy = item[6:]
235             if subitems[0] in ("http", "https", "ftp", "ftps", "file"):
236                 baseurl = item
237         if not proxy:
238             proxy = get_proxy_for(baseurl)
239         proxies = None
240         if proxy:
241            proxies = {str(proxy.split(":")[0]):str(proxy)}
242         makedirs(cachedir + "/" + reponame)
243         url = str(baseurl + "/repodata/repomd.xml")
244         filename = str("%s/%s/repomd.xml" % (cachedir, reponame))
245         repomd = myurlgrab(url, filename, proxies)
246         try:
247             root = xmlparse(repomd)
248         except SyntaxError:
249             raise CreatorError("repomd.xml syntax error.")
250
251         ns = root.getroot().tag
252         ns = ns[0:ns.rindex("}")+1]
253
254         patterns = None
255         for elm in root.getiterator("%sdata" % ns):
256             if elm.attrib["type"] == "patterns":
257                 patterns = elm.find("%slocation" % ns).attrib['href']
258                 break
259
260         comps = None
261         for elm in root.getiterator("%sdata" % ns):
262             if elm.attrib["type"] == "group_gz":
263                 comps = elm.find("%slocation" % ns).attrib['href']
264                 break
265         if not comps:
266             for elm in root.getiterator("%sdata" % ns):
267                 if elm.attrib["type"] == "group":
268                     comps = elm.find("%slocation" % ns).attrib['href']
269                     break
270
271         primary_type = None
272         for elm in root.getiterator("%sdata" % ns):
273             if elm.attrib["type"] == "primary_db":
274                 primary_type=".sqlite"
275                 break
276
277         if not primary_type:
278             for elm in root.getiterator("%sdata" % ns):
279                 if elm.attrib["type"] == "primary":
280                     primary_type=".xml"
281                     break
282
283         if not primary_type:
284             continue
285
286         primary = elm.find("%slocation" % ns).attrib['href']
287         primary = get_metadata_from_repo(baseurl, proxies, cachedir, reponame, primary)
288
289         if patterns:
290             patterns = get_metadata_from_repo(baseurl, proxies, cachedir, reponame, patterns)
291
292         if comps:
293             comps = get_metadata_from_repo(baseurl, proxies, cachedir, reponame, comps)
294
295         """ Get repo key """
296         try:
297             repokey = get_metadata_from_repo(baseurl, proxies, cachedir, reponame, "repodata/repomd.xml.key")
298         except CreatorError:
299             repokey = None
300             msger.warning("can't get %s/%s" % (baseurl, "repodata/repomd.xml.key"))
301
302         my_repo_metadata.append({"name":reponame, "baseurl":baseurl, "repomd":repomd, "primary":primary, "cachedir":cachedir, "proxies":proxies, "patterns":patterns, "comps":comps, "repokey":repokey})
303
304     return my_repo_metadata
305
306 def get_package(pkg, repometadata, arch = None):
307     ver = ""
308     target_repo = None
309     for repo in repometadata:
310         if repo["primary"].endswith(".xml"):
311             root = xmlparse(repo["primary"])
312             ns = root.getroot().tag
313             ns = ns[0:ns.rindex("}")+1]
314             for elm in root.getiterator("%spackage" % ns):
315                 if elm.find("%sname" % ns).text == pkg:
316                     if elm.find("%sarch" % ns).text != "src":
317                         version = elm.find("%sversion" % ns)
318                         tmpver = "%s-%s" % (version.attrib['ver'], version.attrib['rel'])
319                         if tmpver > ver:
320                             ver = tmpver
321                             location = elm.find("%slocation" % ns)
322                             pkgpath = "%s" % location.attrib['href']
323                             target_repo = repo
324                         break
325         if repo["primary"].endswith(".sqlite"):
326             con = sqlite.connect(repo["primary"])
327             if not arch:
328                 for row in con.execute("select version, release,location_href from packages where name = \"%s\" and arch != \"src\"" % pkg):
329                     tmpver = "%s-%s" % (row[0], row[1])
330                     if tmpver > ver:
331                         pkgpath = "%s" % row[2]
332                         target_repo = repo
333                     break
334             else:
335                 for row in con.execute("select version, release,location_href from packages where name = \"%s\"" % pkg):
336                     tmpver = "%s-%s" % (row[0], row[1])
337                     if tmpver > ver:
338                         pkgpath = "%s" % row[2]
339                         target_repo = repo
340                     break
341             con.close()
342     if target_repo:
343         makedirs("%s/%s/packages" % (target_repo["cachedir"], target_repo["name"]))
344         url = str(target_repo["baseurl"] + "/" + pkgpath)
345         filename = str("%s/%s/packages/%s" % (target_repo["cachedir"], target_repo["name"], os.path.basename(pkgpath)))
346         pkg = myurlgrab(url, filename, target_repo["proxies"])
347         return pkg
348     else:
349         return None
350
351 def get_source_name(pkg, repometadata):
352
353     def get_bin_name(pkg):
354         m = re.match("(.*)-(.*)-(.*)\.(.*)\.rpm", pkg)
355         if m:
356             return m.group(1)
357         return None
358
359     def get_src_name(srpm):
360         m = re.match("(.*)-(\d+.*)-(\d+\.\d+).src.rpm", srpm)
361         if m:
362             return m.group(1)
363         return None
364
365     ver = ""
366     target_repo = None
367
368     pkg_name = get_bin_name(pkg)
369     if not pkg_name:
370         return None
371
372     for repo in repometadata:
373         if repo["primary"].endswith(".xml"):
374             root = xmlparse(repo["primary"])
375             ns = root.getroot().tag
376             ns = ns[0:ns.rindex("}")+1]
377             for elm in root.getiterator("%spackage" % ns):
378                 if elm.find("%sname" % ns).text == pkg_name:
379                     if elm.find("%sarch" % ns).text != "src":
380                         version = elm.find("%sversion" % ns)
381                         tmpver = "%s-%s" % (version.attrib['ver'], version.attrib['rel'])
382                         if tmpver > ver:
383                             ver = tmpver
384                             fmt = elm.find("%sformat" % ns)
385                             if fmt:
386                                 fns = fmt.getchildren()[0].tag
387                                 fns = fns[0:fns.rindex("}")+1]
388                                 pkgpath = fmt.find("%ssourcerpm" % fns).text
389                                 target_repo = repo
390                         break
391
392         if repo["primary"].endswith(".sqlite"):
393             con = sqlite.connect(repo["primary"])
394             for row in con.execute("select version, release, rpm_sourcerpm from packages where name = \"%s\" and arch != \"src\"" % pkg_name):
395                 tmpver = "%s-%s" % (row[0], row[1])
396                 if tmpver > ver:
397                     pkgpath = "%s" % row[2]
398                     target_repo = repo
399                 break
400             con.close()
401     if target_repo:
402         return get_src_name(pkgpath)
403     else:
404         return None
405
406 def get_release_no(repometadata, distro="meego"):
407     import subprocess
408
409     cpio = find_binary_path("cpio")
410     rpm2cpio = find_binary_path("rpm2cpio")
411     release_pkg = get_package("%s-release" % distro, repometadata)
412     if release_pkg:
413         tmpdir = mkdtemp()
414         oldcwd = os.getcwd()
415         os.chdir(tmpdir)
416         p1 = subprocess.Popen([rpm2cpio, release_pkg], stdout = subprocess.PIPE)
417         p2 = subprocess.Popen([cpio, "-idv"], stdin = p1.stdout, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
418         p2.communicate()
419         f = open("%s/etc/%s-release" % (tmpdir, distro), "r")
420         content = f.read()
421         f.close()
422         os.chdir(oldcwd)
423         shutil.rmtree(tmpdir, ignore_errors = True)
424         return content.split(" ")[2]
425     else:
426         return "UNKNOWN"
427
428 def get_kickstarts_from_repos(repometadata):
429     kickstarts = []
430     for repo in repometadata:
431         try:
432             root = xmlparse(repo["repomd"])
433         except SyntaxError:
434             raise CreatorError("repomd.xml syntax error.")
435
436         ns = root.getroot().tag
437         ns = ns[0:ns.rindex("}")+1]
438
439         for elm in root.getiterator("%sdata" % ns):
440             if elm.attrib["type"] == "image-config":
441                 break
442
443         if elm.attrib["type"] != "image-config":
444             continue
445
446         location = elm.find("%slocation" % ns)
447         image_config = str(repo["baseurl"] + "/" + location.attrib["href"])
448         filename = str("%s/%s/image-config.xml%s" % (repo["cachedir"], repo["name"], suffix))
449
450         image_config = get_uncompressed_data_from_url(image_config,filename,repo["proxies"])
451
452         try:
453             root = xmlparse(image_config)
454         except SyntaxError:
455             raise CreatorError("image-config.xml syntax error.")
456
457         for elm in root.getiterator("config"):
458             path = elm.find("path").text
459             path = path.replace("images-config", "image-config")
460             description = elm.find("description").text
461             makedirs(os.path.dirname("%s/%s/%s" % (repo["cachedir"], repo["name"], path)))
462             url = path
463             if "http" not in path:
464                 url = str(repo["baseurl"] + "/" + path)
465             filename = str("%s/%s/%s" % (repo["cachedir"], repo["name"], path))
466             path = myurlgrab(url, filename, repo["proxies"])
467             kickstarts.append({"filename":path,"description":description})
468         return kickstarts
469
470 def select_ks(ksfiles):
471     msger.info("Available kickstart files:")
472     i = 0
473     for ks in ksfiles:
474         i += 1
475         msger.raw("\t%d. %s (%s)" % (i, ks["description"], os.path.basename(ks["filename"])))
476
477     while True:
478         choice = raw_input("Please input your choice and press ENTER. [1..%d] ? " % i)
479         if choice.lower() == "q":
480             sys.exit(1)
481         if choice.isdigit():
482             choice = int(choice)
483             if choice >= 1 and choice <= i:
484                 break
485
486     return ksfiles[choice-1]["filename"]
487
488 def get_pkglist_in_patterns(group, patterns):
489     found = False
490     pkglist = []
491     try:
492         root = xmlparse(patterns)
493     except SyntaxError:
494         raise SyntaxError("%s syntax error." % patterns)
495
496     for elm in list(root.getroot()):
497         ns = elm.tag
498         ns = ns[0:ns.rindex("}")+1]
499         name = elm.find("%sname" % ns)
500         summary = elm.find("%ssummary" % ns)
501         if name.text == group or summary.text == group:
502             found = True
503             break
504
505     if not found:
506         return pkglist
507
508     found = False
509     for requires in list(elm):
510         if requires.tag.endswith("requires"):
511             found = True
512             break
513
514     if not found:
515         return pkglist
516
517     for pkg in list(requires):
518         pkgname = pkg.attrib["name"]
519         if pkgname not in pkglist:
520             pkglist.append(pkgname)
521
522     return pkglist
523
524 def get_pkglist_in_comps(group, comps):
525     found = False
526     pkglist = []
527     try:
528         root = xmlparse(comps)
529     except SyntaxError:
530         raise SyntaxError("%s syntax error." % comps)
531
532     for elm in root.getiterator("group"):
533         id = elm.find("id")
534         name = elm.find("name")
535         if id.text == group or name.text == group:
536             packagelist = elm.find("packagelist")
537             found = True
538             break
539
540     if not found:
541         return pkglist
542
543     for require in elm.getiterator("packagereq"):
544         if require.tag.endswith("packagereq"):
545             pkgname = require.text
546         if pkgname not in pkglist:
547             pkglist.append(pkgname)
548
549     return pkglist
550
551 def is_statically_linked(binary):
552     return ", statically linked, " in runner.outs(['file', binary])
553
554 def setup_qemu_emulator(rootdir, arch):
555     # mount binfmt_misc if it doesn't exist
556     if not os.path.exists("/proc/sys/fs/binfmt_misc"):
557         modprobecmd = find_binary_path("modprobe")
558         runner.show([modprobecmd, "binfmt_misc"])
559     if not os.path.exists("/proc/sys/fs/binfmt_misc/register"):
560         mountcmd = find_binary_path("mount")
561         runner.show([mountcmd, "-t", "binfmt_misc", "none", "/proc/sys/fs/binfmt_misc"])
562
563     # qemu_emulator is a special case, we can't use find_binary_path
564     # qemu emulator should be a statically-linked executable file
565     qemu_emulator = "/usr/bin/qemu-arm"
566     if not os.path.exists(qemu_emulator) or not is_statically_linked(qemu_emulator):
567         qemu_emulator = "/usr/bin/qemu-arm-static"
568     if not os.path.exists(qemu_emulator):
569         raise CreatorError("Please install a statically-linked qemu-arm")
570     if not os.path.exists(rootdir + "/usr/bin"):
571         makedirs(rootdir + "/usr/bin")
572     shutil.copy(qemu_emulator, rootdir + qemu_emulator)
573
574     # disable selinux, selinux will block qemu emulator to run
575     if os.path.exists("/usr/sbin/setenforce"):
576         msger.info('Try to disable selinux')
577         runner.show(["/usr/sbin/setenforce", "0"])
578
579     node = "/proc/sys/fs/binfmt_misc/arm"
580     if is_statically_linked(qemu_emulator) and os.path.exists(node):
581         return qemu_emulator
582
583     # unregister it if it has been registered and is a dynamically-linked executable
584     if not is_statically_linked(qemu_emulator) and os.path.exists(node):
585         qemu_unregister_string = "-1\n"
586         fd = open("/proc/sys/fs/binfmt_misc/arm", "w")
587         fd.write(qemu_unregister_string)
588         fd.close()
589
590     # register qemu emulator for interpreting other arch executable file
591     if not os.path.exists(node):
592         qemu_arm_string = ":arm:M::\\x7fELF\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x28\\x00:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfa\\xff\\xff\\xff:%s:\n" % qemu_emulator
593         fd = open("/proc/sys/fs/binfmt_misc/register", "w")
594         fd.write(qemu_arm_string)
595         fd.close()
596
597     return qemu_emulator
598
599 def create_release(config, destdir, name, outimages, release):
600     """ TODO: This functionality should really be in creator.py inside the
601     ImageCreator class. """
602
603     # For virtual machine images, we have a subdir for it, this is unnecessary
604     # for release
605     thatsubdir = None
606     for i in range(len(outimages)):
607         file = outimages[i]
608         if not os.path.isdir(file) and os.path.dirname(file) != destdir:
609             thatsubdir = os.path.dirname(file)
610             newfile = os.path.join(destdir, os.path.basename(file))
611             shutil.move(file, newfile)
612             outimages[i] = newfile
613     if thatsubdir:
614         shutil.rmtree(thatsubdir, ignore_errors = True)
615
616     """ Create release directory and files """
617     runner.show("cp %s %s/%s.ks" % (config, destdir, name))
618     # When building a release we want to make sure the .ks
619     # file generates the same build even when --release= is not used.
620     fd = open(config, "r")
621     kscont = fd.read()
622     fd.close()
623     kscont = kscont.replace("@BUILD_ID@",release)
624     fd = open("%s/%s.ks" % (destdir,name), "w")
625     fd.write(kscont)
626     fd.close()
627     outimages.append("%s/%s.ks" % (destdir,name))
628
629     # Using system + mv, because of * in filename.
630     runner.show("mv %s/*-pkgs.txt %s/%s.packages" % (destdir, destdir, name))
631     outimages.append("%s/%s.packages" % (destdir,name))
632
633     for f in os.listdir(destdir):
634         if f.endswith(".iso"):
635             ff = f.replace(".iso", ".img")
636             os.rename("%s/%s" %(destdir, f ), "%s/%s" %(destdir, ff))
637             outimages.append("%s/%s" %(destdir, ff))
638         elif f.endswith(".usbimg"):
639             ff = f.replace(".usbimg", ".img")
640             os.rename("%s/%s" %(destdir, f ), "%s/%s" %(destdir, ff))
641             outimages.append("%s/%s" %(destdir, ff))
642
643     if os.path.exists("/usr/bin/md5sum"):
644         fd = open(destdir + "/MANIFEST", "w")
645         for f in os.listdir(destdir):
646             if f == "MANIFEST":
647                 continue
648
649             rc, md5sum = runner.runtool(["/usr/bin/md5sum", "-b", "%s/%s" %(destdir, f )])
650             if rc != 0:
651                 msger.warning("Can't generate md5sum for image %s/%s" %(destdir, f ))
652             else:
653                 md5sum = md5sum.lstrip().split()[0]
654                 fd.write(md5sum+" "+f+"\n")
655
656     outimages.append("%s/MANIFEST" % destdir)
657     fd.close()
658
659     """ Update the file list. """
660     updated_list = []
661     for file in outimages:
662         if os.path.exists("%s" % file):
663             updated_list.append(file)
664
665     return updated_list
666
667 def SrcpkgsDownload(pkgs, repometadata, instroot, cachedir):
668
669     def get_source_repometadata(repometadata):
670         src_repometadata=[]
671         for repo in repometadata:
672             if repo["name"].endswith("-source"):
673                 src_repometadata.append(repo)
674         if src_repometadata:
675             return src_repometadata
676         return None
677
678     def get_src_name(srpm):
679         m = re.match("(.*)-(\d+.*)-(\d+\.\d+).src.rpm", srpm)
680         if m:
681             return m.group(1)
682         return None
683
684     src_repometadata = get_source_repometadata(repometadata)
685
686     if not src_repometadata:
687         msger.warning("No source repo found")
688         return None
689
690     src_pkgs = []
691     lpkgs_dict = {}
692     lpkgs_path = []
693     for repo in src_repometadata:
694         cachepath = "%s/%s/packages/*.src.rpm" %(cachedir, repo["name"])
695         lpkgs_path += glob.glob(cachepath)
696
697     for lpkg in lpkgs_path:
698         lpkg_name = get_src_name(os.path.basename(lpkg))
699         lpkgs_dict[lpkg_name] = lpkg
700     localpkgs = lpkgs_dict.keys()
701
702     cached_count = 0
703     destdir = instroot+'/usr/src/SRPMS'
704     if not os.path.exists(destdir):
705         os.makedirs(destdir)
706
707     srcpkgset = set()
708     for _pkg in pkgs:
709         srcpkg_name = get_source_name(_pkg, repometadata)
710         if not srcpkg_name:
711             return None
712         srcpkgset.add(srcpkg_name)
713
714     for pkg in list(srcpkgset):
715         if pkg in localpkgs:
716             cached_count += 1
717             shutil.copy(lpkgs_dict[pkg], destdir)
718             src_pkgs.append(os.path.basename(lpkgs_dict[pkg]))
719         else:
720             src_pkg = get_package(pkg, src_repometadata, 'src')
721             if src_pkg:
722                 shutil.copy(src_pkg, destdir)
723                 src_pkgs.append(src_pkg)
724     msger.info("%d source packages gotten from cache" %cached_count)
725
726     return src_pkgs