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